UART Baudrate berechnen

#1714169
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
#1714181
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
Gast #1714195
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
#1714196
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.
#1714199
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.
#1714210
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
#1714234
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
Gast #1714603
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;
#1714609
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...
#1714636
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
#1714652
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren