Hallo erstmal zusammen. Ich recheriere hier schon länger im Board und bin sehr zufrieden mit der Kompetenz einiger User (sehr gutes Wissen), was mir schon viel in der Vergangenheit geholfen hatte, dafür Danke! Jedoch stehe ich jetzt vor einem Problem: Ich habe hier einen ATMega32 + 16MHz Quarz. -> AVR Studio 5 ("C"). Ich benutze den Timer1 für eine "PPM" (Ich benötige eine variable Frequenz am PD5 mit fester positiven Pulsweite [26µs]). Das tut auch ganz gut, gesteuert wird dies via RS232. An den restlichen Pins des ATMega32 (ausser PD4) müssen jetzt I/O's angeschlossen werden. Darunter fällt u.a. auch SRAM etc. Sollte alles kein Problem sein, jedoch stoße ich hier auf einen "Show Stopper". Sobald ich den Timer1 initialisiere + starte, sind die restlichen doppelt belegten PIN vom µC fest für Timer vergeben. Z.b. der Pin PD7(OC2). Gibt es eine Möglichkeit den Timer1 zu nutzen UND alle restlichen Pins (ausser PD4 & 5) als Ein und Ausgänge zu nutzen? So bald ich den Timer1 ausschalte (Prescaler auf 0) kann ich z.B. den Pin PD7 "High" oder "Low" setzen, jedoch nicht wenn der Timer1 läuft. Ich wäre um jeden Tipp sehr dankbar! Danke und Gruß
Hi >Sobald ich den Timer1 initialisiere + starte, sind die restlichen >doppelt belegten PIN vom µC fest für Timer vergeben. >Z.b. der Pin PD7(OC2). Da machst du etwas falsch. Zeig mal deine Initialisierungen. MfG Spess
Thomas D. schrieb: > Ich wäre um jeden Tipp sehr dankbar! PD7 hat mit Timer1 nicht das geringste zu tun. Richtiger Controller eingestellt? mfg.
Hi zusammen! Das ging ja flott! :) Genau das wundert mich ja, warum, wenn ich nur den Timer1 verwende, Pins vom Timer2 sich verstellen. Anbei mal der C-Code. Ich verwende den Timer1 um eine "PPM" zu erzeugen. Ich muss eine variable Frequenz (~1KHz - 16KHz) erzeugen, jedoch mit einer gleichbleibenden Pulsbreite (~26µs). Zudem sollte die Frequenz sehr fein änderbar sein (daher 16Bit Timer). Ich lasse den Timer im "normal Mode" laufen und schalte den direkten Ausgang vom OC1A und OC1B auf PD5 & PD4 ab. Timer Top = 0xFFFF Interrupt gesteuert. Ich lasse die beiden 16Bit Register OCR1A & OCR1B mit TCNT1 vergleichen, wenn "compare", dann löst es einen Interrupt aus. Dort wird dann ur der PD5 einmal ein und dann wieder ausgeschaltet. Wenn ich jetzt zu Testzwecken über RS232 die vorgeladenen Register verändere, kann ich mit OCR1A die Frequenz und OCR1B die Pulsbreite einstellen. Im einschaltzustand wird am PD5 eine Frequenz von ~14KHz und einer Pulsbreite von ~26µs erzeugt. Wenn ich jetzt in der While Schleife "PORTD = (1 << PD7);" oder "PORTD = (0 << PD7);" schalte, passiert nix, bleibt auf "LOW". Kann sein, das die Kommentare nicht mehr ganz passen, habe seit dem Fehler viel probiert. Vielen Dank schonmal!! Gruß
1 | #include <avr/io.h> |
2 | #include <stdlib.h> |
3 | #include <avr/interrupt.h> |
4 | #include <avr/iom32.h> |
5 | #include <stdio.h> |
6 | #include <util/delay.h> |
7 | |
8 | #define F_CPU 16000000
|
9 | #define UART_BAUD 19200
|
10 | #define MaxPuffer 2 //Maximaler Ringpuffer für USART (100 Zeilen á 8 Bit breit)
|
11 | |
12 | uint8_t puffer[MaxPuffer]; |
13 | uint8_t* read_ptr; |
14 | uint8_t* write_ptr; |
15 | uint8_t USART_Byte; |
16 | |
17 | |
18 | void controler_init() |
19 | {
|
20 | //Zu Testzwecken Port A, B, C und D als Ausgang und alle Ausgänge auf LOW
|
21 | DDRA = 0xFF; |
22 | PORTA |= (0 << PA0) | (0 << PA1) | (0 << PA2) | (0 << PA3) | (0 << PA4) | (0 << PA5) | (0 << PA6) | (0 << PA7); |
23 | DDRB = 0xFF; |
24 | PORTB |= (0 << PB0) | (0 << PB1) | (0 << PB2) | (0 << PB3) | (0 << PB4) | (0 << PB5) | (0 << PB6) | (0 << PB7); |
25 | DDRC = 0xFF; |
26 | PORTC |= (0 << PC0) | (0 << PC1) | (0 << PC2) | (0 << PC3) | (0 << PC4) | (0 << PC5) | (0 << PC6) | (0 << PC7); |
27 | DDRD = 0xFF; |
28 | PORTD |= (0 << PD0) | (0 << PD1) | (0 << PD2) | (0 << PD3) | (0 << PD4) | (0 << PD5) | (0 << PD6) | (0 << PD7); |
29 | }
|
30 | |
31 | void usart_init(void) |
32 | {
|
33 | read_ptr = puffer; |
34 | write_ptr = puffer; |
35 | UBRRH = 0; // Highbyte ist 0 |
36 | UBRRL = (F_CPU / (16UL * UART_BAUD)) - 1; |
37 | UCSRB |= (1 << RXCIE)|( 1 << TXEN )|( 1 << RXEN); // UART TX einschalten |
38 | UCSRC |= ( 1 << URSEL )|( 1<<UCSZ0 )|( 1<<UCSZ1 )|( 0<<UCSZ2 ); // Asynchron 8N1 |
39 | }
|
40 | |
41 | void timer1_init(void) |
42 | {
|
43 | //Timer1 (16 Bit) Mode 0
|
44 | TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0) | (0 << FOC1A) | (0 << FOC1B) | (1 << WGM11) | (1 << WGM10); //Normal port operation, OC1A/OC1B disconnected; Normal Timer Operation TOP = 0xFFFF |
45 | TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); //WGM13&WGM12&WGM11&WGM10 = Waveform Mode 0; CS12&CS11&CS10 = Timer On, Prescale = 8 |
46 | TIMSK = (1 << OCIE1A) | (1 << OCIE1B); |
47 | |
48 | //OCR1A = 0 -> 16MHz; OCR1A = 65535 -> 61Hz @ toggle the output | fPCPWM = F_CPU/(2*N*TOP) [N = Prescale, TOP = OCR1A Register] i.e. -> 16MHz/(2*1*65535) = 122Hz (122Hz High, 122Hz Low @ Toggle Pin => 61Hz)
|
49 | //See Datasheet Page 100
|
50 | //Minimum allowed is OCR1A = 0x0003 (2 Bit), Maximum is OCR1A = 0xFFFF (16 Bit)
|
51 | |
52 | OCR1A = 141; //or OCR1A = 0xFFFF; |
53 | OCR1B = 52; |
54 | }
|
55 | |
56 | |
57 | |
58 | void uart_write(USART_Byte); |
59 | int USART_get_Byte(void); |
60 | |
61 | |
62 | int main(void) |
63 | {
|
64 | controler_init(); |
65 | usart_init(); |
66 | timer1_init(); |
67 | sei(); |
68 | ; while(1) |
69 | {
|
70 | _delay_us(1); |
71 | if (write_ptr != read_ptr) |
72 | {
|
73 | USART_Byte = USART_get_Byte(); //Neue Daten holen |
74 | UDR = USART_Byte; |
75 | //uart_write(test);
|
76 | //UDR = USART_Byte; //Echo schicken
|
77 | //USART_Echo(USART_Byte);
|
78 | |
79 | if (USART_Byte == '7') OCR1A++; |
80 | if (USART_Byte == '4') OCR1A--; |
81 | |
82 | if (USART_Byte == '9') OCR1B++; |
83 | if (USART_Byte == '6') OCR1B--; |
84 | |
85 | }
|
86 | }
|
87 | }
|
88 | |
89 | |
90 | int USART_get_Byte(void) |
91 | {
|
92 | uint8_t Byte = 0; |
93 | |
94 | Byte = *read_ptr; |
95 | read_ptr++; |
96 | if (read_ptr == puffer+MaxPuffer) read_ptr = puffer; |
97 | |
98 | return Byte; |
99 | }
|
100 | |
101 | void uart_putchar(char c) |
102 | {
|
103 | while (!(UCSRA & (1 << UDRE))); // wait for buffer ready |
104 | UDR = c; |
105 | }
|
106 | |
107 | void uart_write(char *str) |
108 | {
|
109 | while(*str) {uart_putchar(*str); str++;} |
110 | }
|
111 | |
112 | // void USART_Echo(int Byte)
|
113 | // {
|
114 | // UDR = Byte; //Echo schicken
|
115 | // while (!(UCSRA & (1<<UDRE))); //Warte bis bereit
|
116 | // if (Byte == 13) UDR = 10; //Wenn "CR" geschickt wurde dann sende "LF"
|
117 | // }
|
118 | |
119 | |
120 | |
121 | ISR(TIMER1_COMPA_vect) |
122 | {
|
123 | PORTD = (1 << PD5); |
124 | }
|
125 | |
126 | ISR(TIMER1_COMPB_vect) |
127 | {
|
128 | PORTD = (0 << PD5); |
129 | }
|
130 | |
131 | ISR(USART_RXC_vect) |
132 | {
|
133 | *write_ptr = UDR; |
134 | write_ptr++; |
135 | if (write_ptr == puffer + MaxPuffer) write_ptr = puffer; |
136 | }
|
1 | ISR(TIMER1_COMPA_vect) |
2 | {
|
3 | PORTD = (1 << PD5); |
4 | }
|
5 | |
6 | ISR(TIMER1_COMPB_vect) |
7 | {
|
8 | PORTD = (0 << PD5); |
9 | }
|
Scherzkeks. Du selbst bist doch derjenige, der alle Pins von Port D laufend "überbügelt".
> PORTD = (1 << PD5); Da kannst du gleich schreiben PORTD = 0b00100000. Also alle anderen Pins außer PD5 werden auf 0V gesetzt. Und hier: > PORTD = (0 << PD5); PORTD = 0b00000000
Thomas D. schrieb: > PORTA |= (0 << PA0) | (0 << PA1) | (0 << PA2) | (0 << PA3) | (0 << PA4) | (0 << PA5) | (0 << PA6) | (0 << PA7); Scherzkeks, ein NOP geht auch einfacher. Geh an die Tafel und schreibe 100 mal: Ich lerne erst, was |= bedeutet, ehe ich es verwende! Peter
OMG! Du hast recht! Ich sollte wohl eher
1 | ISR(TIMER1_COMPA_vect) |
2 | {
|
3 | PORTD |= (1 << PD5); |
4 | }
|
5 | |
6 | ISR(TIMER1_COMPB_vect) |
7 | {
|
8 | PORTD &= ~(1 << PD5); |
9 | }
|
schreiben, oder? :) Manchmal sieht man vor lauter Bits das Byte nicht mehr... Ok, sorry fürs stören. Die Initialisierung sollte jedoch passen oder? Ich muss an einer bestehenden PCB anknüpfen, dort sind alle Pins belegt (Port C = Datenbus von SRAM, Port A & B = Adressbus SRAM, Port D = Timer, 2 Bits für einen Multiplexer [für die umschaltung von den insg. 4 SRAMs]) etc. Eine Frage hätte ich jedoch noch: Warum "muss" ich in der While schleife ein delay von 1 µs (oder weniger haben) damit die Daten von RS232 erkannt werden? Ich prüfe ja bei jedem Durchgang ob der lesepupperPointer != schreibepufferPointer ist, wenn ja = Datan vorhanden, wenn nicht, keine Daten vorhanden. Das gleiche wenn ich stings senden will, wird wohl in der func "uart_write" der Pointer überlaufen: wenn ich ein String sende z.B. "Test" kommt der am Terminal an, wenn ich jetzt nur ein Zeichen sende, kommt "Müll"+das Zeichen an. Leeren von der Variable str in der func "uart_write" hat leider ncihts gebracht. Gruß Thomas
@peda Lese mal mein Kommentar im ersten Code Beispiel. Da ich dem Fehler nicht auf die schliche kam, probiert mal auch dinge die eigentlich einfacher tun. Ich werde mich natürlich gleich an die Strafarbeit setzen... :)
Thomas D. schrieb: > Da ich dem Fehler nicht > auf die schliche kam, probiert mal auch dinge die eigentlich einfacher > tun. Nö, Du probierst Dinge, die garnichts tun. "x |= 0;" ist Code ohne Effekt. Sowas macht man nicht, erst recht nicht, um Fehler zu suchen. Peter
Thomas D. schrieb: > Eine Frage hätte ich jedoch noch: > Warum "muss" ich in der While schleife ein delay von 1 µs (oder weniger > haben) damit die Daten von RS232 erkannt werden? Ich prüfe ja bei jedem > Durchgang ob der lesepupperPointer != schreibepufferPointer ist, wenn ja > = Datan vorhanden, wenn nicht, keine Daten vorhanden. Da sehe ich direkt 2 Fehler: 1. Die globalen Variablen, die Du in der ISR änderst, müssen volatile deklariert werden, damit Du sie in main() benutzen darfst. 2. Die Variable write_ptr besteht aus jeweils 2 Bytes. Du musst in main() gewährleisten, dass der Zugriff atomar ist und nicht durch die ISR, welche zwischendurch aufgerufen werden könnte, geändert werden kann. Dein Delay versteckt nur den Fehler. Ich schlage vor, statt Pointer Indices zu verwenden. Dann kommst Du mit 1 Byte pro index aus (read_idx & write_idx) und kannst Punkt 2 abhaken. Ausserdem geht der Zugriff auf Deinen Buffer über Indices im allgemeinen flotter als mit Pointern - jedenfalls auf einem µC.
Ich weis, jedoch hatte ich mir alle Bits von den Ports einzeln aufgeschrieben, um jeweils ein Bit zu ändern wenns nötig ist (also einfach am entsprechenden Bit eine 1 statt der 0 eintragen). Aber wurst, ich habs ja verstanden was Du meintest. Hat einer eine Idee mit dem delay in der while, warum das dann erst tut? Würde gerne komplett ohne delay arbeiten. Gruß
Thomas D. schrieb: > Hat einer eine Idee mit dem delay in der while, warum das dann erst tut? Siehe mein Posting über Deinem.
@UKW Danke für Deine Antwort!! Klingt logisch was Du geschrieben hast. Ich werde mich mal in Indices einlesen, bin da noch grün hinter den Ohren. Zwecks den variablen und volatile. Ich dachte ich brauche das nur, wenn ich eine Variable im Interrupt UND in der Main ändere. Hier tue ich das ja nicht, ich frage höchsten die beiden pointer auf ungleichheut ab, oder irre ich mich damit?
Thomas D. schrieb: > Klingt logisch was Du geschrieben hast. Ich werde mich mal in Indices > einlesen, bin da noch grün hinter den Ohren. Komisch, eigentlich lernt man erst den Umgang mit buffer[idx] statt mit Pointern ;-) > Zwecks den variablen und volatile. > Ich dachte ich brauche das nur, wenn ich eine Variable im Interrupt UND > in der Main ändere. Nein, auch wenn Du lesend drauf zugreifst. Der Compiler könnte sonst write_ptr in ein Register(-Paar) packen, wenn er sieht, dass main() niemals beendet wird und keine Unterfunktion aufgerufen wird, die diese Variable ändert. Die ISR() wird ja nirgends explizit aufgerufen. > Hier tue ich das ja nicht, ich frage höchsten die beiden pointer auf > ungleichheut ab, oder irre ich mich damit? read_ptr wird nicht in der ISR verwendet, ist daher kein Problem. write_ptr aber schon. Benutze aber besser:
1 | uint8_t read_idx; |
2 | volatile uint8_t write_idx; |
3 | ...
|
4 | ISR(USART_RXC_vect) |
5 | {
|
6 | puffer[write_idx] = UDR; |
7 | write_idx++; |
8 | if (write_idx == MaxPuffer) write_idx = 0; |
9 | }
|
Rest analog. MaxPuffer würde ich als MAX_PUFFER schreiben - wie es sich für eine Preprocessor-Konstante gehört. Ausserdem ist sie mit dem Wert 2 unterirdisch klein ;-)
Hi UKW! Danke für Deine Hilfe! Ich werde mir morgen mal das ganze anschauen und dann posten wie es lief. :) Immer toll wenn man ein Forum hat indem es Leute gibt die einem weiter helfen, ich will ja kein code kopieren der komplett fertig ist o.ä. ich will das lernen um selber damit arbeiten zu können. Werde mir auch morgen mal Dein Beispiel dazu anschauen und versuchen das zu verwenden. Zwecks dem MAX_PUFFER und dem inhalt. Der lag eigentlich bei 100, habe ihn vergessen wieder auf 100 zu setzen. Aber danke, hätte ich glatt übersehen. :) Gruß Thomas
Was mir noch auffällt:
1 | USART_Byte = USART_get_Byte(); //Neue Daten holen |
2 | UDR = USART_Byte; |
Die zweite Zeile ist hoffentlich nur ein Test-Echo??? Denn hier schreibst Du in das Senderegister ohne Rücksicht auf Verluste. Wenn USART_Byte tatsächlich gesendet werden soll, dann benutze bitte Deine(!) Funktion uart_putchar(). Die ist dafür gedacht: Sie wartet, bis das Senderegister frei ist und beschreibt erst dann UDR. So, wie Du das oben machst, geht das in die Hose.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.