www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik UART Baudrate berechnen


Autor: Yvonne J. (laserlight)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich nutze hier diese Methode zur Berechnung:

  #define BAUD 9600l
  #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   //

das geht auch bei:

#define F_CPU 800000

wunderbar. Doch bei 1Mhz ist das wohl nicht funktional.

Ich nutze den Atmega168 bzw 48. Wenn jemand ein funktionierendes 
Beispiel hätte wäre das sehr hilfreich!

Übrigens, was treibt der fleury hier:

/*********************************************************************** 
**
Function: uart_init()
Purpose:  initialize UART and set baudrate
Input:    baudrate using macro UART_BAUD_SELECT()
Returns:  none
************************************************************************ 
**/
void uart_init(unsigned int baudrate)
{
    UART_TxHead = 0;
    UART_TxTail = 0;
    UART_RxHead = 0;
    UART_RxTail = 0;

#if defined( AT90_UART )
    /* set baud rate */
    UBRR = (unsigned char)baudrate;

    /* enable UART receiver and transmmitter and receive complete 
interrupt */
    UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);

#elif defined (ATMEGA_USART)
    /* Set baud rate */
    if ( baudrate & 0x8000 )
    {
       UART0_STATUS = (1<<U2X);  //Enable 2x speed
       baudrate &= ~0x8000;
    }
    UBRRH = (unsigned char)(baudrate>>8);
    UBRRL = (unsigned char) baudrate;

    /* Enable USART receiver and transmitter and receive complete 
interrupt */
    UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);

    /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
    #ifdef URSEL
    UCSRC = (1<<URSEL)|(3<<UCSZ0);
    #else
    UCSRC = (3<<UCSZ0);
    #endif

#elif defined (ATMEGA_USART0 )
    /* Set baud rate */
    if ( baudrate & 0x8000 )
    {
       UART0_STATUS = (1<<U2X0);  //Enable 2x speed
       baudrate &= ~0x8000;
     }
    UBRR0H = (unsigned char)(baudrate>>8);
    UBRR0L = (unsigned char) baudrate;

    /* Enable USART receiver and transmitter and receive complete 
interrupt */
    UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);

    /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
    #ifdef URSEL0
    UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
    #else
    UCSR0C = (3<<UCSZ00);
    #endif

#elif defined ( ATMEGA_UART )
    /* set baud rate */
    if ( baudrate & 0x8000 )
    {
      UART0_STATUS = (1<<U2X);  //Enable 2x speed
      baudrate &= ~0x8000;
    }
    UBRRHI = (unsigned char)(baudrate>>8);
    UBRR   = (unsigned char) baudrate;

    /* Enable UART receiver and transmitter and receive complete 
interrupt */
    UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);

#endif

}/* uart_init */


da steige ich nicht durch. Der scheint es ohne F_CPU zu berechnen...?

Gruß,
Yve

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yvonne J. schrieb:
> Hi,
>
> ich nutze hier diese Methode zur Berechnung:
>
>   #define BAUD 9600l
>   #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   //
>
> das geht auch bei:
>
> #define F_CPU 800000
>
> wunderbar. Doch bei 1Mhz ist das wohl nicht funktional.

Warum sollte das nicht funktional sein?

> da steige ich nicht durch. Der scheint es ohne F_CPU zu berechnen...?

er berechnet es gar nicht.

> Input:    baudrate using macro UART_BAUD_SELECT()

er erwartet schon den umgerechneten Wert als Argument

Autor: Tropenhitze (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   //

Da fehlt die Rundung!
Faktor 2 höher rechnen und vor der Division +1 addieren. Das schaffst Du 
schon!

Autor: Yvonne J. (laserlight)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,

wenn ich F_CPU auf 1Mhz setzte und das div8 Bit setze, dann kommt nur 
noch Grütze :-)

Gruß,
Yve

Autor: Rick Dangerus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yvonne J. schrieb:
> was treibt der fleury hier
> if ( baudrate & 0x8000 )

Na ohne Baudrate geht es bei ihm auch nicht. Aber je nach Chip guckt er 
nach ob das MSB gesetzt ist und verwendet den 2X-Mode.

Rechne doch mal per Hand nach, welche Werte bei Dir rausrommen und 
welche rauskommen müssten. Läuft Dein Chip auch mit dem richtigen Speed? 
Sind die Fuses (8x) richtig gesetzt?

Rick

Autor: Uwe ... (uwegw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yvonne J. schrieb:
> da steige ich nicht durch. Der scheint es ohne F_CPU zu berechnen...?

Übergeben wird dieser Funktion nicht die Baudrate selbst, sondern schon 
der Wert des Baudratenregisters (mit dem Makro UART_BAUD_SELECT() 
berechnet).
Der Aufruf sieht dann also z.B. so aus:
uart_init( UART_BAUD_SELECT(19200,F_CPU) );
Also auch wieder mit F_CPU...

Der Vorteil dabei ist, dass das Makro schon zur compile-Zeit berechnet 
wird.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yvonne J. schrieb:
> Hallo Karl Heinz,
>
> wenn ich F_CPU auf 1Mhz setzte und das div8 Bit setze, dann kommt nur
> noch Grütze :-)

Allerdings solltest du mal einen Blick ins Datenblatt riskieren. Da gibt
es im USAR Kapitel Tabellen, bei denen auch für häufig benutzte 
Taktfrequenzen und Baudraten die UBRR Werte angegeben sind und auch die 
Fehler die durch in einer spezifischen Kombination entstehen.

Alles über 3% Fehler ist nicht akzeptabel.
Deine Kombination: 1Mhz / 9600 Baud
hat 7% Fehler wenn U2X auf 0 bleibt

Wenn du U2X auf 1 stellst, dann sinkt der Fehler auf nur noch 0.2%

Dein Job: Den Code durchgehen und rausfinden, wie du die Lib dazu 
zwingen kannst U2X zu benutzen. Peter hat da schon was dafür vorgesehen.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Isses den sooooo schwer?
Siehe Baudratenquarz.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yvonne J. schrieb:
> ich nutze hier diese Methode zur Berechnung:
>
>   #define BAUD 9600l
>   #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   //
>
> das geht auch bei:
>
> #define F_CPU 800000
>
> wunderbar. Doch bei 1Mhz ist das wohl nicht funktional.

Die Formel ist prinzipiell schon richtig. Aber bei 1MHz Takt und 9600 
Baud ist der Fehler dann 7%, das ist viel zu viel. Du musst U2X 
aktivieren und die 16 in der Formel durch 8 ersetzen, wenn du diese 
Takt-/Baudraten-Kombination verwenden willst.

Schau dir auch mal <util/setbaud.h> aus der avr-libc an, das nimmt dir 
die Berechnung ab, du brauchst dann nur noch die Werte in die Register 
schreiben. Ausserdem sorgt es dafür, dass du eine Compilerwarnung 
erhältst, wenn der Baudratenfehler zu gross wird.

> Ich nutze den Atmega168 bzw 48. Wenn jemand ein funktionierendes
> Beispiel hätte wäre das sehr hilfreich!

Ein Beispiel steht in der Doku zu <util/setbaud.h> 
(http://www.nongnu.org/avr-libc/user-manual/group__...).

> Übrigens, was treibt der fleury hier:
[...]
> da steige ich nicht durch. Der scheint es ohne F_CPU zu berechnen...?

Zur Parameterübergabe musst du hier eines der beiden Makros 
"UART_BAUD_SELECT" oder "UART_BAUD_SELECT_DOUBLE_SPEED" benutzen, darin 
steckt dann die Berechnung. In deinem Fall müsstest du das erste der 
beiden bei 8MHz und das zweite bei 1MHz verwenden.

Andreas

Autor: Yvonne J. (laserlight)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...ich nutze keinen Quarz...

spiele gerad rum:

  #define BAUD 9600l
  #define UART_BAUD_SELECT(baudRate,xtalCpu) 
((xtalCpu)/((baudRate)*16l)-1)
  #define UBRR_VAL UART_BAUD_SELECT(BAUD,F_CPU)

hmmm

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yvonne J. schrieb:
> ...ich nutze keinen Quarz...

Das ist schon mal ein Fehler :-)

> spiele gerad rum:
>
>   #define BAUD 9600l
>   #define UART_BAUD_SELECT(baudRate,xtalCpu)
> ((xtalCpu)/((baudRate)*16l)-1)
>   #define UBRR_VAL UART_BAUD_SELECT(BAUD,F_CPU)

und weiter?
Wie zwingst du die Fleury Lib U2X zu benutzen?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Yvonne J. (laserlight)

>...ich nutze keinen Quarz...

Ob das so ein gute Idee ist?

http://www.mikrocontroller.net/articles/AVR_Checkl...

Autor: Yvonne J. (laserlight)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...ich habe gerad versucht das Makro von Fleury für die oben aufgeführte 
Berechnung zu nutzen, also nicht für die Fleury lib...

@ Andreas, das klingt interessant... ich schaue mich um.

Gruß,
Yve

Autor: Yvonne J. (laserlight)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk, bei 8Mhz und mit der zuerst geposteten Berechnung, läuft es 
durchgehend 1A, ich habe mein F_CPU Define an eine globale Stelle 
genommen, und nun habe ich den Porzessor mal auf 1Mhz gestellt, und das 
Define entsprechend angepasst, es zieht auch alles mit, bis auf den 
UART. Jetzt suche ich nach einer Möglichkeit diese Sache auch soweit es 
geht mit zu automatisieren...
Yve

Autor: Yvonne J. (laserlight)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Tropenhitze,

so wie ich das bis jetzt verstehe muss ich den 2X mode des Uarts mit ins 
Spiel holen, anders scheint es nicht zu gehen, wenn doch, bitte 
verdeutliche mal deinen Vorschlag.

Yve

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Yvonne J. (laserlight)

>UART. Jetzt suche ich nach einer Möglichkeit diese Sache auch soweit es
>geht mit zu automatisieren...

Dann nimm dei Makros aus dem Tutorial und gut ist. Die spucken sogar 
einen Error, wenn das mit der Baudrate nicht klappt.

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

MFG
Falk

Autor: roflkartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zu 2X mode .. in der lib ist das :
    if ( baudrate & 0x8000 )
    {
       UART0_STATUS = (1<<U2X);  //Enable 2x speed
       baudrate &= ~0x8000;
    }

beachten muss man das die baudrate anders berechnet wird
zB
  unsigned int ubrr = ( (F_CPU/(8*baud))-1); 
  UBRR1H = (unsigned char)(ubrr>>8);
  UBRR1L = (unsigned char) ubrr;
  UCSR1A |= (1<<U2X1);
ohne u2x
  unsigned int ubrr = ( (F_CPU/(16*baud))-1); 
  UBRR1H = (unsigned char)(ubrr>>8);
  UBRR1L = (unsigned char) ubrr;

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt immer wieder Leute, die wollen die Baudrate dem Compiler 
ueberlassen. Manch ein Programm scheitert so, bevor es begonnen hat. 
Dabei ist es ja nur eine Konstante, die man einmal vom Datenblatt her 
rechnen muss. Die meisten Datenblaetter haben sogar Tabellen fuer die 
Werte...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Hey noch Was (Firma: Mumpitz) (hacky)

>Es gibt immer wieder Leute, die wollen die Baudrate dem Compiler
>ueberlassen.

Der Mensch ist von Natur aus faul.

> Manch ein Programm scheitert so, bevor es begonnen hat.

That's life.

>Dabei ist es ja nur eine Konstante, die man einmal vom Datenblatt her
>rechnen muss.

Dumm nur, dass die Konstante fix mal vaiabel ist, wenn sich die 
Taktfrequenz ändert.

> Die meisten Datenblaetter haben sogar Tabellen fuer die Werte...

Mit allen möglichen Taktfrequenzen? Außerdem, der Compiler kann DEUTLICH 
mehr, als ne popelige Baudrate ausrechnen.

MFG
Falk

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Hey noch Was schrieb:
> Es gibt immer wieder Leute, die wollen die Baudrate dem Compiler
> ueberlassen. Manch ein Programm scheitert so, bevor es begonnen hat.
> Dabei ist es ja nur eine Konstante, die man einmal vom Datenblatt her
> rechnen muss. Die meisten Datenblaetter haben sogar Tabellen fuer die
> Werte...

und warum nicht? Dafür hat der GCC doch util/setbaud.h und das klappt 
auch...

Gruß aus Berlin
Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.