ATMega644 UART mit untersch. Baudraten

OP #6150274
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.
OP #6150286
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.
(Firma: matzetronics) #6150287
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.
OP #6150289
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
Gast #6150291
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.
OP #6150295
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)
OP #6150317
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.
OP #6150329
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.
Gast #6150338
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.
#6150372
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.
Moderator #6150649
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?"
Gast #6150699
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.
OP #6150706
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!

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.