Forum: Mikrocontroller und Digitale Elektronik ATMega644 UART mit untersch. Baudraten


von Max B. (citgo)


Lesenswert?

Nabend zusammen,

ich habe heute den ganzen Tag damit verbracht mit einem ATMega644 ein 
paar Zeichen an die serielle Schnittstelle zu senden.

Ich benutze die lib von Peter Fleury.
Atmega läuft, nein, lief mit 12MHz. Dann mal mit 8MHz und jetzt wieder 
12.

Terminalprogramm war TeraTerm. Mit dem habe ich bislang immer gute 
Erfahrungen gemacht.
Naja jedenfalls wollte ich einen String ("Hallo") und ein Zeichen ('C') 
senden.

Der PC hat immer etwas empfangen. Im Atmega war als Baudrate 9600 
eingestellt. Im Terminal auch aber da kamen nur wirre Zeichen.
Stelle ich nun im Terminal auf 14400 baud dann kam etwas in dieser Art 
an: H#--*C

Fast richtig! :)

Nunja, ich habe wie gesagt den ganzen Tag rumprobiert. Einen 8MHz Quarz 
genommen, Fuses tausendmal gecheckt. Nichts!!

Eben lud ich mir dann mal ein anderes Terminalprogramm runter und siehe 
da: Mein String und mein Zeichen kommen in Klartext an!!! JUHU

Aber: Atmega=9600 Baud, Terminal=14400 Baud

Frage: Warum bekomme ich bei gleicher Baudrate nur Müll angezeigt? Ich 
habe wie gesagt mehrere Frequenzen schon durch, mehrere Baud 
Berechnungen und nie hat es geklappt.

Frage 2: Trotz ungleicher Baudraten sehe ich meine gesendeten Sachen 
nicht mit TeraTerm sondern nur mit Putty oder HTerm. Warum??
Einstellungen sind die gleichen!

Und ja,
https://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART
kenne ich.
Und nein, CKDIV8 ist nicht gesetzt.

von Stefan F. (Gast)


Lesenswert?

Vielleicht hast du den Quarz mit falschen Kondensatoren belastet. 
Steckbrett?

von Jürgen (Gast)


Lesenswert?

9600:8MHzx12MHz=14400
Du hast nicht zufällig die Baudrate für 8MHz betechnet und mit 12MHz 
laufen lassen?

von Max B. (citgo)


Lesenswert?

Ne... Platine.
Naja hab 22pF. Konnte zwar nicht mit einem Oszi messen aber Quarz sollte 
laufen.
Da hängt noch ein LCD dran und 2 serielle ICs. Also das läuft alles 
soweit.

Mich wundert es halt nur, dass der String korrekt gesendet wird aber mit 
unterschiedlichen Baudraten und mit ausgewählten Terminal Programmen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Zeig doch bitte mal deinen Code - zumindest mal das USART Init. Da HTerm 
auch  unter Win10 völlig problemlos funktioniert, kann ich dir das nur 
ans Herz legen.
Ist für Entwickler, die irgendwas mit UART oder USB Serial zu tun haben, 
m.M.n. das universellste, was es gibt.

von Max B. (citgo)


Lesenswert?

Jürgen schrieb:
> 9600:8MHzx12MHz=14400
> Du hast nicht zufällig die Baudrate für 8MHz betechnet und mit 12MHz
> laufen lassen?

Mh... eigentlich nicht.
Hatte vorher ja alles auf 12MHz laufen und beim 8MHz die Berechnung neu 
gemacht.
Jetzt läuft er wieder mit 12MHz.
9600 im Atmeg und 14400 im Terminal

von Beo Bachta (Gast)


Lesenswert?

Max B. schrieb:
> Hatte vorher ja alles auf 12MHz laufen und beim 8MHz die Berechnung neu
> gemacht.
> Jetzt läuft er wieder mit 12MHz.

Da frage ich mich doch wie du die Änderungen auf die jeweils
andere Frequenz bewirkt hast. Denn so wie du dich gibst hast
du da womöglich Fehler gemacht.

von Max B. (citgo)


Lesenswert?

1
void uart_init(unsigned int baudrate)
2
{
3
    UART_TxHead = 0;
4
    UART_TxTail = 0;
5
    UART_RxHead = 0;
6
    UART_RxTail = 0;
7
    
8
#if defined( AT90_UART )
9
    /* set baud rate */
10
    UBRR = (unsigned char)baudrate; 
11
12
    /* enable UART receiver and transmmitter and receive complete interrupt */
13
    UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);
14
15
#elif defined (ATMEGA_USART)
16
    /* Set baud rate */
17
    if ( baudrate & 0x8000 ) UART0_STATUS = (1<<U2X);  //Enable 2x speed 
18
    UBRRH = ((unsigned char)(baudrate>>8))&0x80;
19
    UBRRL = (unsigned char) baudrate;
20
   
21
    /* Enable USART receiver and transmitter and receive complete interrupt */
22
    UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
23
    
24
    /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
25
    #ifdef URSEL
26
    UCSRC = (1<<URSEL)|(3<<UCSZ0);
27
    #else
28
    UCSRC = (3<<UCSZ0);
29
    #endif 
30
    
31
#elif defined (ATMEGA_USART0 )
32
    /* Set baud rate */
33
    if ( baudrate & 0x8000 ) UART0_STATUS = (1<<U2X0);  //Enable 2x speed 
34
    UBRR0H = ((unsigned char)(baudrate>>8))&0x80;
35
    UBRR0L = (unsigned char) baudrate;
36
37
    /* Enable USART receiver and transmitter and receive complete interrupt */
38
    UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
39
    
40
    /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
41
    #ifdef URSEL0
42
    UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
43
    #else
44
    UCSR0C = (3<<UCSZ00);
45
    #endif 
46
47
#elif defined ( ATMEGA_UART )
48
    /* set baud rate */
49
    if ( baudrate & 0x8000 ) UART0_STATUS = (1<<U2X);  //Enable 2x speed 
50
    UBRRHI = ((unsigned char)(baudrate>>8))&0x80;
51
    UBRR   = (unsigned char) baudrate;
52
53
    /* Enable UART receiver and transmitter and receive complete interrupt */
54
    UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
55
56
#endif
57
58
}/* uart_init */

Und hier die defines für die Baudrate:
1
/** @brief  UART Baudrate Expression
2
 *  @param  xtalcpu  system clock in Mhz, e.g. 4000000L for 4Mhz          
3
 *  @param  baudrate baudrate in bps, e.g. 1200, 2400, 9600     
4
 */
5
#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1)
6
7
/** @brief  UART Baudrate Expression for ATmega double speed mode
8
 *  @param  xtalcpu  system clock in Mhz, e.g. 4000000L for 4Mhz           
9
 *  @param  baudrate baudrate in bps, e.g. 1200, 2400, 9600     
10
 */
11
#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Max B. schrieb:
> 9600 im Atmeg und 14400 im Terminal
> Jetzt läuft er wieder mit 12MHz.

 14400B / 9600B = 1,5
 12Mhz  / 8Mhz  = 1.5

 Komisch, nicht wahr?

 Kaum zu fassen...

: Bearbeitet durch User
von Beo Bachta (Gast)


Lesenswert?

Max B. schrieb:
> Und hier die defines für die Baudrate:

Nein, ich würde gern wissen wie du das Einstellen der
8MHz bzw 12MHz erreicht hast.

von Max B. (citgo)


Lesenswert?

So, danke... ich hab's!

Aus:
1
#define baudrate 9600

mach:
1
#define baudrate 9600UL

und jetzt läuft es mit gleicher Baudrate und auch mit TeraTerm.
Kann mir einer sagen warum?

Ich habe jetzt ganz oft beide Möglichkeiten gesehen aber mir nichts 
dabei gedacht das mal auszuprobieren.

von Beo Bachta (Gast)


Lesenswert?

Max B. schrieb:
> Kann mir einer sagen warum?

Du redest nicht mit jedem der dir helfen will ...
... heute keine Bauernsprechstunde, wa?

Nur weiter so!

von Max B. (citgo)


Lesenswert?

Beo Bachta schrieb:
> Max B. schrieb:
>> Kann mir einer sagen warum?
>
> Du redest nicht mit jedem der dir helfen will ...
> ... heute keine Bauernsprechstunde, wa?
>
> Nur weiter so!

Doch, schon.
Aber ich habe mir meine Frage gerade schon selber beantwortet.
Bei den 12MHz sollte das UL hinter die Baudrate um den Überlauf zu 
umgehen.
Warum das aber bei 8MHz nicht geklappt hat weiß icj nicht.

Und die MHz hab ich auch schön in Hz angegeben.

von Max B. (citgo)


Lesenswert?

Ich hatte das mit dem unsigned Long einfach nicht mehr auf dem Schirm, 
da viele Beiträge und Tutorials mit weniger MHz beschrieben sind.

von Beo Bachta (Gast)


Lesenswert?

Max B. schrieb:
> Doch, schon.
> Aber ich habe mir meine Frage gerade schon selber beantwortet.
> Bei den 12MHz sollte das UL hinter die Baudrate um den Überlauf zu
> umgehen.

Damit steht fest dass du nichts von dem verstanden hast was
ich gefragt habe.

von Max B. (citgo)


Lesenswert?

Beo Bachta schrieb:
> Max B. schrieb:
>> Doch, schon.
>> Aber ich habe mir meine Frage gerade schon selber beantwortet.
>> Bei den 12MHz sollte das UL hinter die Baudrate um den Überlauf zu
>> umgehen.
>
> Damit steht fest dass du nichts von dem verstanden hast was
> ich gefragt habe.

Okay...

von Stefan F. (Gast)


Lesenswert?

Ich würde empfehlen, die Datei setbaud.h zu benutzen:

https://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html

Dann können solche Dinge nicht schief gehen.

von Max B. (citgo)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich würde empfehlen, die Datei setbaud.h zu benutzen:
>
> https://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html
>
> Dann können solche Dinge nicht schief gehen.

Danke für den Tipp!
Die kannte ich gar nicht.

von Sebastian S. (amateur)


Lesenswert?

Einige "Wenns"

Wenn Du den Quarz richtig zappeln lässt - also den richtigen Quarz
     und die richtigen Kondensatoren verwendest.
Wenn Du die Fuses (Quarztyp) richtig eingestellt hast.
     Auch der DIV8 sollte stimmen!
Wenn Du die Teilerfaktoren passend zum Quarz richtig eingestellt hast.
Wenn die zur seriellen Schnittstelle gehörigen Register richtig
     initialisiert wurden. Das ist ein ganzer Haufen.

Es kann natürlich nicht schaden, wenn der Quarz nach dem 3-ten Mal 
herunterfallen auf die Fliesen noch lebt und der Prozessor den 
Überschlag beim letzten Anfassen überlebt hat.

Eins ist nämlich sicher: Hätte der Chip einen internen Fehler, so hätte 
sich das längst herumgesprochen. Ist nämlich schon etliche Jahre auf dem 
Markt.

von LED-Blinker (Gast)


Lesenswert?

Wenn ich so ein Problem habe (lange nicht mehr passiert), dann lasse ich 
im Sekundentakt einen Piezo piepsen und hole mir eine Uhr mit 
Sekundenzeiger auf den Bildschirm. Wenn synchron, dann gut. 
https://www.uhrzeit.org/atomuhr.php

von Yalu X. (yalu) (Moderator)


Lesenswert?

Max B. schrieb:
> So, danke... ich hab's!
>
> Aus:
>
> #define baudrate 9600
>
> mach:
>
> #define baudrate 9600UL
>
> und jetzt läuft es mit gleicher Baudrate und auch mit TeraTerm.
> Kann mir einer sagen warum?

Das UL ist hier nicht erforderlich, da die Makros UART_BAUD_SELECT und
UART_BAUD_SELECT_DOUBLE_SPEED bereits dafür sorgen, dass die Berechnung
der Baudrate in long erfolgt.

Vermutlich hat aber erst diese Änderung bewirkt, dass das Programm neu
kompiliert wurde. Die Änderung von F_CPU im Makefile führt nur dann zur
Neukompilierung, wenn nicht nur die C-Quelldateien, sondern auch das
Makefile selbst in den Make-Regeln berücksichtigt wird.

Mach im Zweifelsfall einfach

1
make clean
2
make

(wenn dein Makefile ein clean-Target hat) oder lösche alle kompilierten
Dateien, um eine vollständige Neukompilierung zu erzwingen.


Noch etwas:

1
    UBRRH = ((unsigned char)(baudrate>>8))&0x80;
2
    ...
3
    UBRR0H = ((unsigned char)(baudrate>>8))&0x80;
4
    ...
5
    UBRRHI = ((unsigned char)(baudrate>>8))&0x80;

Das ist ein Bug. Da müsste statt 0x80 jeweils ~0x80 oder besser 0x0f
stehen. Da der Fehler nur bei niedrigen Baudraten in Erscheinung tritt,
ist wohl noch kaum jemand darüber gestolpert.

Das von Stefan vorgeschlagene setbaud.h aus der AVR-Libc funktioniert
auch mit niedrigen Baudraten. Zudem wird dort eine Warnung ausgegeben,
wenn eine bestimmte Baudrate nicht oder nur mit unzureichender
Genauigkeit umgesetzt werden kann.


Edit:

Ich sehe gerade, dass der o.g. Bug auch schon anderen aufgefallen ist:

  Beitrag "Fehler in uart-lib von Peter Fleury?"

: Bearbeitet durch Moderator
von Max B. (citgo)


Lesenswert?

Danke Yalu!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Das ist ein Bug. Da müsste statt 0x80 jeweils ~0x80 oder besser 0x0f
> stehen.

Sehr guter Hinweis! Müsste es aber dann nicht "besser 0x7f" heißen? 
Okay, es könnte sein, dass die 3 Bits im oberen Nibble keine Bewandnis 
haben, da müsste ich das Datenblatt mal heranziehen...

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Yalu X. schrieb:
> Das UL ist hier nicht erforderlich, da die Makros UART_BAUD_SELECT und
> UART_BAUD_SELECT_DOUBLE_SPEED bereits dafür sorgen, dass die Berechnung
> der Baudrate in long erfolgt.

Da bin ich aber erleichtert. Ich habe nämlich gestern eine halbe Stunde 
darüber gegrübelt und konnte mir nicht erklären, warum das "UL" nötig 
sein sollte.

von Max B. (citgo)


Lesenswert?

Ja ich hatte gestern noch testweise eine andere UART Init im Programm. 
Deswegen habe ich mir die von Peter nicht mehr angeguckt.

Es läuft aber jetzt. Habe auch den Bug behoben in der Init. Läuft jetzt 
einwandfrei!
Danke nochmal an Alle!

von Yalu X. (yalu) (Moderator)


Lesenswert?

Frank M. schrieb:
> Okay, es könnte sein, dass die 3 Bits im oberen Nibble keine Bewandnis
> haben, da müsste ich das Datenblatt mal heranziehen...

Diese Bits sind "reserved" und sollten nur mit 0 beschrieben werden.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Frank M. schrieb:
> Okay, es könnte sein, dass die 3 Bits im oberen Nibble keine Bewandnis
> haben, da müsste ich das Datenblatt mal heranziehen...
>
> Diese Bits sind "reserved" und sollten nur mit 0 beschrieben werden.

Okay, dann wäre ~0x80 sogar falsch. Danke fürs Nachschauen :-)

: Bearbeitet durch Moderator
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
Noch kein Account? Hier anmelden.