Forum: Mikrocontroller und Digitale Elektronik UART Baudrate berechnen


von Yvonne J. (laserlight)


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

von Karl H. (kbuchegg)


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

von Tropenhitze (Gast)


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!

von Yvonne J. (laserlight)


Lesenswert?

Hallo Karl Heinz,

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

Gruß,
Yve

von Rick Dangerus (Gast)


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

von Uwe .. (uwegw)


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.

von Karl H. (kbuchegg)


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.

von Falk B. (falk)


Lesenswert?

Isses den sooooo schwer?
Siehe Baudratenquarz.

von Andreas F. (aferber)


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__util__setbaud.html).

> Ü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

von Yvonne J. (laserlight)


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

von Karl H. (kbuchegg)


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?

von Falk B. (falk)


Lesenswert?

@  Yvonne J. (laserlight)

>...ich nutze keinen Quarz...

Ob das so ein gute Idee ist?

http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART

von Yvonne J. (laserlight)


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

von Yvonne J. (laserlight)


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

von Yvonne J. (laserlight)


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

von Falk B. (falk)


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-Tutorial/Der_UART#UART_initialisieren

MFG
Falk

von roflkartoffel (Gast)


Lesenswert?

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

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

von Purzel H. (hacky)


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...

von Falk B. (falk)


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

von Michael U. (amiga)


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

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.