Falsche Zeichen per UART

OP #4421779
Lesenswert?

Hallo zusammen,
ich weiß, dass falsche Zeichen auf der UART oft an der fehlerhaften 
Baudrate liegen. Leider sehe ich bei meinem Code den Fehler nicht. Ich 
benutze einen ATMega8-16PU, CuteCom und einen Polulu CP2102 unter Linux.
Die Fuse-Bits sind 0xE1 und 0xD9, im Makefile ist F_CPU = 1000000. Sieht 
jemand den Fehler?

Gruß
Dennis
1
#include <avr/io.h>
2
#include <util/delay.h>
3

4
// define some macros
5
#define BAUD 9600                                   // define baud
6
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)
7

8
void uart_init(void)
9
{
10
    UBRRH = (BAUDRATE>>8);                      // shift the register right by 8 bits
11
    UBRRL = BAUDRATE;                           // set baud rate
12
    UCSRB|= (1<<TXEN)|(1<<RXEN);                // enable receiver and transmitter
13
    UCSRC|= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);   // 8bit data format
14
}
15

16
// function to send data
17
void uart_transmit (char data)
18
{
19
    while (!( UCSRA & (1<<UDRE)));                // wait while register is free
20
    UDR = data;                                   // load data in the register
21
}
22

23
// function to receive data
24
char uart_recieve (void)
25
{
26
    while(!(UCSRA) & (1<<RXC));                   // wait while data is being received
27
    return UDR;                                   // return 8-bit data
28
}
29

30
int main( void )
31
{
32

33
    DDRB = 0xFF;
34
    PORTB = 0xFF;
35

36
    UCSRB |= (1<<TXEN);
37
    uart_init();
38

39
    while(1){
40
        _delay_ms( 500 );
41
        uart_transmit('x');
42
    }
43
}
#4421814
Lesenswert?

Warum glaubst du, 9600 ist eine gute Baudrate für einen Mega mit 1MHz? 
Wie in deinem Beispiel wundern mich falschen Zeichen nicht. Du hast hier 
eine Fehlerquote von 7% !!. Nutze die Makros aus der <util/setbaud.h> 
Libary.

Denn um mit 9600 ordentlich Zeichen zu empfangen und/oder senden, sollte 
in UCSRA das Bit für U2X gesetzt sein. Beispiele findest du ebenfalls in 
der <util/setbaud.h>
OP #4421829
Lesenswert?

Stefan S. schrieb:
> Warum glaubst du, 9600 ist eine gute Baudrate für einen Mega mit 1MHz?
> Wie in deinem Beispiel wundern mich falschen Zeichen nicht. Du hast hier
> eine Fehlerquote von 7% !!. Nutze die Makros aus der <util/setbaud.h>
> Libary.
>
> Denn um mit 9600 ordentlich Zeichen zu empfangen und/oder senden, sollte
> in UCSRA das Bit für U2X gesetzt sein. Beispiele findest du ebenfalls in
> der <util/setbaud.h>

Ahh... okay, vielen Dank! Die Baudrate habe ich gewählt, weil ich dachte 
die wäre schon langsam genug... Mir fehlt einfach völlig das Gefühl 
dafür. Mit 4800 Baud funktioniert es, aber ich schaue mir auch mal das 
U2X-Bit und die Header-Datei an.

Gruß
Dennis
#4421857
Lesenswert?

Folgender Code kann helfen:
1
#define baudRate                19200UL
2

3
#define UBRR_VAL (F_CPU+baudRate*8)/(baudRate*16)-1     // clever runden
4
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))             // Reale Baudrate
5
#define BAUD_ERROR ((BAUD_REAL*1000)/baudRate)          // Fehler in Promille, 1000 = kein Fehler.
6

7
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
8
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
9
#endif

Wenn der Fehler größer oder gleich 1 % ist bleibt der Compiler mit einem 
Fehler stehen ;)

Ich finde deine Namensgebung übrigens ungünstig. Dein BAUDRATE ist ja in 
Wirklichkeit UBRR.
#4421913
Lesenswert?

Dennis S. schrieb:
> wie komme ich
> auf die maximal sinnvolle Baudrate in Abhängigkeit von der CPU-Frequenz?
> Mal abgesehen

Der Controller muß das empfangene Byte verarbeiten können, bevor das 
nächste aufläuft. Angenommen du kalibrierst den Oszillator auf 921600Hz, 
dann hast du eine Fehlerrate von 0. Egal bei welcher Standardbaudrate. 
Aber bei 115K2 hast du nur 80 Takte Zeit, bis das nächste Byte auflaufen 
kann. Das ist ne Menge Zeit und geht auch problemlos, aber rumtrödeln, 
zB. in irgendwelchen ISRs, darfst du nicht. D.h. wenn empfangen wird, 
wird empfangen und fast nichts anderes.

Gibt deine Anwendung das nicht her, mußt du mit der Baudrate runter oder 
mit dem Takt hoch.

Das ist alles eine Frage von Tests, Erfahrung und Wissen, wo die Grenzen 
liegen.

Beim Senden dagegen, hast du im Prinzip alle Zeit der Welt.
Moderator (Firma: Titel) Persönliche Seite #4421943
Lesenswert?

Dennis S. schrieb:
> Die Fuse-Bits sind 0xE1 und 0xD9
Es ist übrigens auch keine allzu gute Idee, den internen RC-Oszillator 
mit seinen +-3% Fehler für die serielle Schnitte zu verwenden:
1
At 5V, 25°C and 1.0MHz Oscillator frequency selected, this calibration 
2
gives a frequency within ±3% of the nominal frequency.
Angehängte Dateien:
#4422320
Lesenswert?

Den CP2102 kannst Du auch auf Nicht-Standard-Baudraten konfigurieren. 
Dafür gibt es ein Tool vom Chip-Hersteller. Damit kannst Du auch höhere 
Baudraten komplett ohne Fehler erreichen. Ich benutze z.B. 125kbaud bei 
einem 8Mhz-Quarz.
(Den FTDI kann man ähnlich behandeln, beim CP2102 finde ich es aber 
wesentlich einfacher).

Gruß, Stefan
#4422432
Lesenswert?

Dennis S. schrieb:
> Wenn ich die setbaud.h einbinde und BAUD_TOL gegebenenfalls umdefiniere
> sollte das die gleiche Funktionalität haben oder? Mal abgesehen davon,
> dass du einen Fehler schmeißen lässt und in der AVRlib lediglich eine
> Warnung ausgegeben wird.

Genau, nur eine Warnung gibts nicht bei korrekter Einbindung. Ist der 
Fehler 1% oder größer wird ein Fehler geworfen und der Linker wird nicht 
weiter kompiliert.
Wieso sollte es denn eine Warnung geben?
OP #4422456
Lesenswert?

Michael K. schrieb:
> Genau, nur eine Warnung gibts nicht bei korrekter Einbindung. Ist der
> Fehler 1% oder größer wird ein Fehler geworfen und der Linker wird nicht
> weiter kompiliert.
> Wieso sollte es denn eine Warnung geben?

Ich bin jetzt von dem Quellcode auf der Homepage ausgegangen [1]. In den 
Zeilen 222 und 227 wird doch nach meinem Verständnis die Abweichung 
errechnet und lediglich eine Warnung ausgegeben...

Gruß
Dennis

[1] http://www.nongnu.org/avr-libc/user-manual/setbaud_8h_source.html
#4422475
Lesenswert?

Dennis S. schrieb:
> Michael K. schrieb:
>> Genau, nur eine Warnung gibts nicht bei korrekter Einbindung. Ist der
>> Fehler 1% oder größer wird ein Fehler geworfen und der Linker wird nicht
>> weiter kompiliert.
>> Wieso sollte es denn eine Warnung geben?
>
> Ich bin jetzt von dem Quellcode auf der Homepage ausgegangen [1]. In den
> Zeilen 222 und 227 wird doch nach meinem Verständnis die Abweichung
> errechnet und lediglich eine Warnung ausgegeben...
>
> Gruß
> Dennis
>
> [1] http://www.nongnu.org/avr-libc/user-manual/setbaud_8h_source.html

Da du meinen Beitrag zitiert hattest bin ich davon ausgegangen, dass du 
meinen Codeteil meintest.
Ich benutze setbaud.h nicht, ehrlich gesagt finde ich das auch etwas 
überflüssig. Sich mal ne Stunde mit der Materie beschäftigen und man 
baut sich sowas selbst. Meine #defines kennst du ja oben schon, die 
Funktion zum setzen der Baudrate (in extra Header- und C-File für den 
UART) schaut dann so aus:
1
void uart_init(uint8_t baud)   
2
{
3
  /*set UBRR for baudrate */
4
  UBRRH = (baud >> 8);
5
  UBRRL = baud;
6
  /* Enable receiver and transmitter */
7
  UCSRB |= (1<<RXEN)|(1<<TXEN) | (1<<RXCIE);
8
  /*set Framesize with register UCSRC, initial value: 8 bit, 1 stopbit, look at doc2503 for atmega32 */
9
}
#4422493
Lesenswert?

@  Michael Köhler (sylaina)

>Da du meinen Beitrag zitiert hattest bin ich davon ausgegangen, dass du
>meinen Codeteil meintest.

>Funktion zum setzen der Baudrate (in extra Header- und C-File für den
>UART) schaut dann so aus:

>  /*set UBRR for baudrate */
>  UBRRH = (baud >> 8);
>  UBRRL = baud;

BAUD ist nicht UBRR, schlechte Namenswahl! Warum kopiert man nicht 
einfach den Teil aus dem Tutorial, dort steht es gescheit drin!

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART#UART_initialisieren

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