Hi, ich hab ein Probelem, ich arbeite gerade dass tutorial durch, und habe eine frage zur UART Ausgabe... Ich will testweise einfach nur ein x ausgeben. Ich habe den ATMega8 und hab auch schon ins Datenblatt geschaut, komme aber nicht weiter.. Hier mein Code #ifndef F_CPU #define F_CPU 4000000UL #endif #define BAUD 9600UL #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) #if ((BAUD_ERROR<990) || (BAUD_ERROR>1010)) #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! #endif #include <avr/io.h> #include <stdint.h> void uart_init() { UCSRB |= (1<<TXEN); UCSRC |= (1<<URSEL)|(3<<UCSZ0); UBRRH = UBRR_VAL >> 8; UBRRL = UBRR_VAL & 0xFF; } int main(void) { uart_init(); while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */ { } UDR = 'x'; } Vielen Dank schonmal
Bitte. Michael Kuehn wrote: > Hi, > ich hab ein Probelem, ich arbeite gerade dass tutorial durch, und habe > eine frage zur UART Ausgabe... Ich will testweise einfach nur ein x > ausgeben. Ich habe den ATMega8 und hab auch schon ins Datenblatt > geschaut, komme aber nicht weiter.. > > Hier mein Code Vielleicht hülft's, die Frage auch zu stellen ;-)
Und wo genau ist das Problem? Du kannst die AVR Checkliste abarbeiten. da steht einiges Hilfreiches zu UART Problemen und mehr drin. Ich habe bei deinem Code derzeit nur den Verdacht, dass es Probleme mit der Taktquelle gibt. Die Definition von F_CPU deutet auf eine externe Taktquelle hin, die natürlich 1. vorhanden und richtig angeschlossen sein muss und 2. per richtig eingestellte AVR Fuses ggf. zum Schwingen gebracht werden muss. Erst dann hat die Angabe F_CPU eine Chance im folgenden Quellcode richtig interpretiert zu werden. In deinem Code wird auch nur ein einzelnes x gesendet. Stelle das doch mal auf "Dauerfeuer" um:
1 | int main(void) |
2 | {
|
3 | uart_init(); |
4 | for(;;) |
5 | {
|
6 | while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */ |
7 | {
|
8 | }
|
9 | UDR = 'x'; |
10 | }
|
11 | }
|
1) In den AVR-Sheets wird UBRRx vor UCSRx gesetzt. Warum änderst du dieses Prozedere? 2) Schreibe hier korrekter, klarer und kürzer
1 | UCSRx = ... |
anstatt
1 | UCSRx |= ... |
3) AFAIK sollte man eine Toleranz von +/- 0.2 % einhalten. Ob dein Prog richtig rechnet (sieht zumindest mal so aus), kannst zB hier gegenkontrollieren: http://www.gjlay.de/helferlein/avr-uart-rechner.html Hier noch ne funktionierende init-Funktion:
1 | #define F_CPU 4000000
|
2 | #define BAUDRATE 9600
|
3 | #define U2X_BIT 1
|
4 | |
5 | void uart_init(void) |
6 | {
|
7 | unsigned short ubrr = -.6 + F_CPU/((16L-8*U2X_BIT)*BAUDRATE); |
8 | |
9 | UBRRH = ubrr>>8; |
10 | UBRRL = ubrr; |
11 | |
12 | UCSRA = (U2X_BIT << U2X) | (1 << TXC); |
13 | |
14 | // Enable UART Receiver, Transmitter
|
15 | // Data mode 8N1, asynchronous
|
16 | |
17 | UCSRB = (1 << RXEN) | (1 << TXEN); |
18 | UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); |
19 | |
20 | // Flush Receive Buffer
|
21 | do
|
22 | UDR; |
23 | while (UCSRA & (1 << RXC)); |
24 | }
|
Das Problem ist, dass ich das gesendete Zeichen nicht auf der seriellen Schnittstelle empfange, sondern nur kryptischen Muell... #define F_CPU 3686400 #include <avr/io.h> #include <stdint.h> #include <inttypes.h> void USART_Init() { unsigned int baud = 1200; /* Set baud rate */ UBRRH = (unsigned char)(baud>>8); UBRRL = (unsigned char)baud; UCSRB = (1<<RXEN)|(1<<TXEN); UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0); } void USART_Transmit() { while ( !( UCSRA & (1<<UDRE)) ); UDR = 'x'; } int main () { USART_Init(); for(;;) { USART_Transmit(); } }
Das ist falsch: unsigned int baud = 1200; /* Set baud rate */ UBRRH = (unsigned char)(baud>>8); UBRRL = (unsigned char)baud; So kannst du die Baudrate nicht setzen. Im Datenblatt ist eine Tabelle, in der steht, welche Werte bei welcher Baudrate in die Register UBRRL und UBRRH müssen. Und im AVR GCC Tutorial ist eine Formel, die die Werte aus der Wunschbaudrate und der Taktrate berechnet und sogar meldet, wenn ein zu grosser Baudratenfehler auftreten würde. UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0); ^^^^ Warum hast du das dazu genommen? Das erfordert eine andere Einstellung im Terminalprogramm auf dem PC (dem Empfänger): 2 Stoppbits! Im allerersten Posting hattest du #define F_CPU 4000000UL und jetzt hast du #define F_CPU 3686400. Hast du inzwischen die externe Taktquelle gewechselt (anderer Quarz?). Wenn du eine externe Taktquelle hast (welche?), kannst du mal die Fuses auslesen, einen Screenshot machen und hier anhängen. Ich möchte nachsehen, ob die Taktquelle richtig eingestellt ist.
So, das mit den 2 Stoppbits, ist ok, dass habe ich bewusst gewählt und auch im Terminalprogramm eingestellt. Der Takt, wird ja von extern vorgegeben, über einen Quarz der mit 3,6864MHz läuft... Wie kann ich die Fuses auslesen? Ich benutze AVRStudio4 und das myavr Board Für 2400baud kann ich die Register so setzen? UBRRH = 0x50; //2400 UBRRL = 0x0f; gemäß Tabelle Datenblatt
Michael Kuehn wrote: > UBRRH = 0x50; //2400 > UBRRL = 0x0f; Nee. Ich lese im Datenblatt Tabelle 61 den Wert 95. Damit wäre die Zeile: UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen UBBR = 0x5F; // Alternativ Oder: UBRRH = 0; // Selbst 2 8-Bit Zugriffe machen UBRRL = 95; Alternativ: UBRRH = 0; // Selbst 2 8-Bit Zugriffe machen UBRRL = 0x5F; > Ich benutze AVRStudio4 und das myavr Board Die Angabe hilft bereits. Wenn der originale AVR drauf ist, brauchst du keine Fuses einzustellen. Das ist dann wohl schon ab Entwickler/Verkauf gemacht. Jedenfalls sehe ich keinen Fuses-Einstellschritt in der myAVR-Doku.
Stefan B. wrote: > UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen > UBBR = 0x5F; // Alternativ räusper Wie soll das denn gehen??? &UBRRH = 0x40 &UBRRL = 0x29 Fällt was auf...? Michael Kuehn wrote: > #define BAUD 9600UL Michael Kuehn wrote: > unsigned int baud = 1200; Michael Kuehn wrote: > Für 2400baud kann ich die Register so setzen? Etwas unentschlossen. Steht das Terminal immer noch richtig? Flusskontrolle aus?
Johann L. wrote: > Stefan B. wrote: >> UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen >> UBBR = 0x5F; // Alternativ > > *räusper* > > Wie soll das denn gehen??? > > &UBRRH = 0x40 > &UBRRL = 0x29 > > Fällt was auf...? Nein auf Anhieb nicht. Habe ich das Makro für den 16-Bit Zugriff auf das UBRR IO-Register falsch geschrieben? ADD: Ah, jetzt ja ;-) Beim Atmega8 liegen die beiden 8-Bit IO-Register nicht nebeneinander im Speicher. Wahrscheinlich habe ich das falsch von anderen IO-Registern übertragen (ADC?). Es gibt kein einzelnes UBRR Register. Man muss getrennt mit UBRRL und UBRRH arbeiten. Danke, ich glaube das werde ich nimmer vergessen, rotwerd ;-)
Stefan B. wrote: > ADD: Ah, jetzt ja ;-) > > Beim Atmega8 liegen die beiden 8-Bit IO-Register nicht nebeneinander im > Speicher. Wahrscheinlich habe ich das falsch von anderen IO-Registern > übertragen (ADC?). Es gibt kein einzelnes UBRR Register. Man *muss* > getrennt mit UBRRL und UBRRH arbeiten. Danke, ich glaube das werde ich > nimmer vergessen, rotwerd ;-) Ich hab's net ausprobiert, aber eigentlich müsste der Compiler warnen/der Linker mackern, daß er UBRR nicht kennt, wenn man diesen Zugriff versucht. Kann mir nämlich kaum vorstellen, daß das Makro in den Headern drinne ist (zumindest nicht für ATmega8). Keine Ahnung, warum Atmel das so seltsam gemacht hat, zudem zusammen mit UBSRC als Shadow. Ist wohl ein Silicon-Hack das... Jepp, ADC packt man besser via 16-Bit-Zugriff an, zumal die Reihenfolge auf lo/hi nicht egal ist.
Jetzt hast du mich mit runtergelassenen Hosen erwischt: Ich habe es nämlich auch nicht im Compiler ausprobiert, sondern einfach hingeschrieben. Wie gesagt, was falsch im Kopp drin ist, kommt nur durch Fehlermachen (und einen der es merkt) raus.
Stefan B. wrote:
> Jetzt hast du mich mit runtergelassenen Hosen erwischt:
Und das bei den Temperaturen ... brrr
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.