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
voiduart_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
voiduart_transmit(chardata)
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
charuart_recieve(void)
25
{
26
while(!(UCSRA)&(1<<RXC));// wait while data is being received
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>
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
Dennis S. schrieb:> Mit 4800 Baud funktioniert es, aber ich schaue mir auch mal das> U2X-Bit und die Header-Datei an.
Setz das Bit einfach und du hast 9K6.
Mein grosses V. schrieb:> Setz das Bit einfach und du hast 9K6.
Jepp... läuft alles! Aber um den Lerneffekt zu erhöhen: wie komme ich
auf die maximal sinnvolle Baudrate in Abhängigkeit von der CPU-Frequenz?
Mal abgesehen, dass die Fehlerrate nicht zu hoch sein sollte (<1%?).
Gruß
Dennis
#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.
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.
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.
Lothar M. schrieb:> 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:
Na da kann man dann selbst kalibrieren, dann kommt man auf 1 %…ist dann
zwar immer noch sehr grenzwertig, kann aber funktionieren.
Michael K. schrieb:> Folgender Code kann helfen:
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.
Gruß
Dennis
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
Stefan U. schrieb:> R/C Oszillator und serielle Schnittstelle:> Zum Debuggen reichts, ich würde sie Schnittstelle aber nicht funktional> nutzen.
Ohja, für was Kommerzielles würde ich das auch nicht machen, nur für
etwas im Bastelkeller.
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?
Es ist auch nur eine Bastelei! Sind externe RC-Oszillatoren tendenziell
besser als die internen? Oder lohnt sich der Unterschied nicht und man
"muss" gleich auf einen Quarzoszillator ausweichen?
Gruß
Dennis
Dennis S. schrieb:> Sind externe RC-Oszillatoren tendenziell> besser als die internen?
Besser als externe RC-Oszillatoren? Eher nicht. Aber so ein
Quarz-Oszillator ist deutlich besser/genauer/stabiler als ein
RC-Oszillator ;)
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
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
voiduart_init(uint8_tbaud)
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 */
@ 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