Forum: Mikrocontroller und Digitale Elektronik UART falsche Zeichen


von Ange (Gast)


Lesenswert?

Hallo,

ich versuche bei einem Atmega128 Zeichen über die UART-Schnittstelle zu 
senden, es werden Zeichen auf dem Hyperterminal angezeigt (richtige 
Anzahl),
aber leider nicht die richtigen.
An was kann das liegen?


#ifndef F_CPU
  #define F_CPU 10000000
#endif

/* UART baud rate */
#define UART_BAUD  9600

int main (void){
  //2 Stopbits, 8 bit Daten, Parity: No
  UCSR0C |= (1<<USBS)|(1<<UCSZ01)|(1<<UCSZ00)|(0<<UPM01)|(0<<UPM00);
  UBRR0L =64; //Baudrate 9600 bei 10 MHz
  UCSR0B |= (1<<TXEN1);


  for(;;){
    USART_transmit('a');
    _delay_ms(500);
    USART_transmit('b');
    _delay_ms(500);
    USART_transmit('c');
    _delay_ms(500);
  }
}
void USART_transmit(unsigned char a){
  while(!(UCSR0A &(1<<UDRE0))){}
  UDR0 = a;
}

Gruß
Angelika

von Niels H. (monarch35)


Lesenswert?

"falsche Zeichen" sind ein eindeutiger Hinweis auf falsche 
Parametrierung der seriellen Schnittstelle, meistens verursacht durch 
unstimmige Baudraten.

Überprüfmal ob der Systemtakt 10Mhz und der UBRR0L-Wert korrekt ist. 
Ausserdem solltest du UBRR0H auch initialisieren.

Zudem kommt mir jedoch der Parameter "2 Stoppbits" merkwürdig, weil 
unüblich vor. Eine "normale" serielle Parametrierung sieht meistens 
"8,N,1" vor. (8 Datenbits,No Parity, 1Stoppbit)

von crazy horse (Gast)


Lesenswert?

#ifndef F_CPU
  #define F_CPU 10000000
#endif

/* UART baud rate */
#define UART_BAUD  9600

Das ist ja alles recht schön - allerdings solltest du dann auch die 
Werte für das Baudratenregister daraus berechnen, sonst macht es wenig 
sind.
Bleibt als weitere Fehlerquelle zu dem schon gesagten noch, ob der Chip 
wirklich mit dem 10MHz-Quarz getaktet wird oder noch mit dem internen 
Clock läuft.

von Johannes M. (johnny-m)


Lesenswert?

_delay_ms(500) geht mit 10 MHz nicht. Mit der Frequenz gehen max. 26,2 
ms. Schau mal in die libc-Doku.

Baudrate checken, Takt checken, Einstellungen im Terminal checken...

An den zwei Stopbits kann es jedenfalls eigentlich nicht liegen.

von mef (Gast)


Lesenswert?

Hi,

ein Oszi hilft ungemein, damit kannst Du leicht überprüfen, ob der 
Fehler bei Hypereterm liegt (z.B. falsches Frameformat eingestellt) oder 
bei deinem µC (z.B. falsches Baudrate). Vllt. kennst Du ja jemanden, der 
Dir eines leihen kann. Es ist auf jeden Fall empfehlenswert, weil es 
Grübelzeit spart. ;-)

Solltest Du ein Ozsi haben, danke daran, dass das kleinste Bit zuerst 
übertragen wird und daher auf dem Oszi ganz rechts zu sehen ist, während 
das 128er-Bit z.B. ganz links steht.

Ansonsten:

* Probier' es doch mal mit einer anderen Baudrate, z.B. 2400Bd
* Vllt. haben einige Register nocht falsche Werte?
  Schreib' doch mal explizit noch UBRR0H = 0 oder das U2X0-Bit auf 0.
* Stimmt das Frameformat und die Baudrate bei Hyperterm.
* Welche Zeichen kommen denn an. Schick' doch mal Zeichen von 0x00-0xff 
vllt. bildet sich ein Schema, durch das Du auf den Fehler schliessen 
kannst.
* Atmel bietet zu einigen Controllern auch Bibliotheken, darunter auch 
UART. Vergleich doch mal die Atmel-Sourcen mit Deinen.

Ich hatte ähnliche Probleme und habe dazu auch schon einige 
Forenbeiträge gelesen und irgendwie lag es IMMER an der Baudrate ;-)

Grüße mef

PS: Ich hatte gestern 2 Stunden mal wider an meinen UART-Sourcen 
herumdebuggt, weil sie "plötzlich" nicht mehr gingen. Irgendwann fiehl 
mir dann auf, daß ich anstelle von uart_putchar('A') ausversehen 
uart_putchar("A") geschrieben hatte... 
SMILEY_DER_SEINEN_KOPF_AUF_DEN_TISCH_HAUT So, das musste ich jetzt 
unbedingt noch loswerden ;-)

von mef (Gast)


Lesenswert?

@Niels Hüsken: Die Stopbits dürften eigentlich keine Probleme machen. 
Wenn der µC die Frames mit so langen Pausen schickt, kann der Empfänger 
nicht unterscheiden, ob nun 1 oder 2 Stopbits verwendet werden. Macht 
auch in diesem Fall kein Unterschied, weil die Bits sich vom Idle-Pegel 
nicht unterscheiden.

Grüße mef

von Niels H. (monarch35)


Lesenswert?

Ich sagte ja auch lediglich, daß die Verwendung zweier Stoppbits 
unüblich ist. Problematisch wirds auf jeden Fall, wenn der Empfänger 
zwei Stoppbits erwartet, aber nur Eines kommt.

Auf jeden Fall möchte ich nochmal hervorheben, daß die initialisierung 
des UBRR0H-Registers fehlt. Das wäre äusserst wichtig, daß das passiert. 
Das delay_ms() falsch parametriert ist, interessiert hier nen Toten.

von Angelika V. (ange)


Lesenswert?

@Nils
mal eine Frage wie kann ich den Systemtakt feststellen? Ich habe hier 
ein begonnenes Projekt übernommen, im Datenblatt ist ein Takt von 16 MHz 
angegeben
Stopbit habe ich auf 1 geändert
UCSR0C |= (0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00)|(0<<UPM01)|(0<<UPM00);
UBRR0H = 0  beschrieben

@mef
habe leider kein Oszi
unterschiedliche Baudraten habe ich auch ausprobiert

von Niels H. (monarch35)


Lesenswert?

@Angelika:
Das "e" ist kein Tippfehler. Mein Name ist "Niels" :)
Um den Systemtakt festzustellen gibt es mehrere Möglichkeiten:
Fusebits auslesen und schauen, was konfiguriert ist. Ist ein externer 
Taktgeber konfiguriert, müsste also ein Quarz oder ein Ozillator 
angeschlossen sein, auf dem die Taktfrequenz draufsteht.

Ist über die Fuses ein interner Taktgeber konfiguriert, müsste hier 
beistehen, wie schnell der klappert. In diesem Fall ist häufig jedoch 
die Taktfrequenztolleranz ausserhalb die der für seriellen Übertragung 
nötigen präzision. Ein externer Taktgeber ist auf jeden Fall von nöten.

Bitte schau auch bezüglich des UBRR0H-Registers in die Dokumentation des 
Mega128. Die Reihenfolge in der man die UBRR0H und UBRR0L beschreibt ist 
wichtig. Ich habe sie nur gerade nicht im Kopf.

von mef (Gast)


Lesenswert?

Ich hätte jetzt einfach auf den Quarz geschaut und überprüft, ob die 
Fuses richtig gesetzt sind. Es gibt IMO eine Fuse, die angibt, ob die 
interne oder externe Taktquelle verwendet werden soll. Ich habe gelesen, 
daß die Interne Taktquelle nicht für UART geeignet ist, weil zu ungenau 
(temperaturabhängig, usw.). Apropos Fuses, vllt. ist bei Dir auch die 
Fuse für die Kompatiblität zum ATMega103 gesetzt. Vielleicht macht das 
auch Probleme.

Grüße aus Ulm

von mef (Gast)


Lesenswert?

im Datenblatt wird zuerst High geschrieben

von Falk B. (falk)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

mef wrote:

> (temperaturabhängig, usw.). Apropos Fuses, vllt. ist bei Dir auch die
> Fuse für die Kompatiblität zum ATMega103 gesetzt. Vielleicht macht das
> auch Probleme.

Eher unwahrscheinlich.
Wenn die 103-Fuse falsch steht, stürzt der Prozessor beim ersten
Funktionsaufruf ab, weil der Stack nicht dort liegt wo er sollte.

Das Wahrschinlichste ist immer noch Takt und daher die
Baudrate.
Wenn man mit den Fuses nicht klarkommt, kann man auch folgendes
machen: Mittels _delay_ms einfach mal eine LED im Sekundentakt
blinken lassen. Den Unterschied zwischen 10Mhz und 1Mhz internem
Takt kann man deutlich sehen.

von Angelika V. (ange)


Lesenswert?

@ Niels ;-)
also auf der Platine ist ein Quartz auf dem steht 16.000H6D
ich nehme an 16 Mhz
das mit zuerst UBRR0H und dann UBRR0L beschreiben ist richtig
was die Fusebits betrifft, die habe ich gestern auf alle möglichen Arten 
versucht auszulesen. Das Problem:
Ponyprog kann ich nicht verwenden, mein Spi-Adapter ist über die 
Parallele Schnittstelle(stk200), das wird nicht unterstützt.
Mit Averdude GUIscheint zwar irgendetwas gelesen zu werden
... reading efuse memory..
...writing outputfile "con"
nur das outputfile kann ich nicht finden

was nun?
Gruß
Angelika

von Karl H. (kbuchegg)


Lesenswert?

Angelika Voß wrote:
> @ Niels ;-)
> also auf der Platine ist ein Quartz auf dem steht 16.000H6D
> ich nehme an 16 Mhz

Das heist noch lange nicht, dass der auch verwendet wird.
Einfacher Test: Mittels _delay_ms (welches den delay aus
der angegebenen Taktfrequenz F_CPU berechnet) eine Blinkschleife
bauen und nachsehen ob die Zeiten stimmen können.
Einfach 100 mal _delay_ms(10) aufrufen und LED umschalten.
Ist der Wert für F_CPU korrekt, dann blinkt deine LED alle
1 Sekunde. Läuft der interne Oszillator dann blinkt sie alle
16 Sekunden. Ist deutlich unterscheidbar.

Aber ich muss mich schon wundern.
Wenn du einen 16Mhz Quarz hast, dann solltest du nicht lügen
und hier

#ifndef F_CPU
  #define F_CPU 10000000
#endif

10Mhz angeben. Sicher ist sicher. Solche Zahlen sollten immer
stimmen (auch wenn die tatsächliche Frequenz zb. im AVR-Studio
noch mal eingegeben werden kann). Das hat zwar jetzt keine
Auswirkungen auf deine UART (weil da momentan die Baudrate nicht
von der F_CPU abgeleitet wird), aber es geht ums Prinzip.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg)

>machen: Mittels _delay_ms einfach mal eine LED im Sekundentakt
>blinken lassen. Den Unterschied zwischen 10Mhz und 1Mhz internem
>Takt kann man deutlich sehen.

Ja, aber auch nur, wenn man es richtig macht.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Warteschleifen_.28delay.h.29

MFG
Falk

von Niels H. (monarch35)


Lesenswert?

@Angelika
Vergiss die gui. Die macht desöfteren schonmal probleme. Geh auf 
Kommandozeile und starte avrdude im interactive-mode.

> avrdude -p m128 -c stk200 -t -F

und dann kannst du mit "read lfuse" und "read hfuse" die Fuses auslesen. 
Den Hexadizimalcode musst du in Binär umwandeln (Windows-Taschenrechner) 
und kannst dann Anhand der Fuses-Tabelle in der Atmel-Doku die einzelnen 
Flags bestimmen. Wichtig für die Taktangabe sind die flags für CKSEL und 
CKOPT.

Eine "1" als "High" bedeutet übrigens "unprogrammed"

von Angelika V. (ange)


Lesenswert?

@ Karl heinz Buchegger
ich habe hier 2 Boards und konnte mit der Wartefunktion (danke @Falk) 
herausfinden:
Board1 blinkt bei F_CPU von 16 MHz im Sekundentakt
Board2 ist langsamer
@ Niels
na dann werd ich mich mal an das Auslesen der Fuses machen

von mef (Gast)


Lesenswert?

Sollte Dein µC doch nicht mit 10Mhz laufen, dann stimmen die Werte im 
UBRR-Register nicht mehr. Im Datenblatt stehen meistens Tabellen mit 
passenden Werten, Baudraten und Fehlerraten. Ich würde das gleich mal 
anpassen und schauen ob's jetzt geht, vielleicht war das schon der 
Fehler und Du sparst Dir das mit den Fuses.

Für 16Mhz und 2400bd bei 0% Fehler: UBBRxH = 3 und UBBRxL = 64

UBBR berechnet man so: F_OSC / (16*Baudrate) - 1
*   Der Faktor 16, weil die UART 16-fach sampled (sagt man das so?).
*   - 1 weil IMO bis 0 runtergezählt wird.aDo je nach Prozessortakt 
keine ganzen Zahlen herauskommen hat man einen gewissen Fehler, der 0.2% 
nicht überschreiten sollte.

Grüße mef

von Angelika V. (ange)


Lesenswert?

@mef
das habe ich schon versucht, leider kein Erfolg

@Niels
bei den zwei Atmega128-Boards mit verschiedener Einstellung hat
das Auslesen der Fusebits hat fogendes ergeben:

        Low Fuse Byte:      High Fuse Byte:   Extendet Fuse Byte:
Board1  00000100            11011001          11111111
Board2  11101110            10000001          11111111

nun werde ich mal das Datenblatt studieren

von Angelika V. (ange)


Lesenswert?

Ich werd' aus dem Datenblatt nicht schlau,
nun habe ich aber getestet von Board2 über serielle Schnittstelle Daten 
an den Rechner zu schicken
Einstellungen: CPU-Takt:  16MHz
               Baudrate:  9600
               8N1
Fusebits wie oben beschrieben,
es funktioniert!!
macht es nun Sinn die EInstellungen der Fusebits von Board2 auf Board1 
zu übertragen?

@Niels lautet der Befehl für das Schreiben z.B. write hfuse?

von Niels H. (monarch35)


Lesenswert?

@Angelika

> write hfuse 0 <byte>

für <byte> beispielsweise 0xa0... Die '0' bedeutet, das offset 0 von der 
basis beschrieben werden soll.

Board1 hat CKSEL 0100 CKOPT 1
und Board2 CKSEL 1110 CKOPT 0

Bei Board 1 bedeutet das laut Tabelle 6 auf Seite 37/38, daß interne 
Resonator auf 8Mhz (tabelle 13) schwingt.

Bei Board 2 ist der externe Crystal-Resonator ab 1Mhz aufwärts 
selektiert  (Tabelle 8) und konfiguriert.

Wenn die Boards auf den externen 16Mhz laufen soll, solltest du auf 
Board1 die Einstellungen von Board2 übernehmen.... sowohl lfuse, als 
auch hfuse

von Karl H. (kbuchegg)


Lesenswert?

Angelika Voß wrote:
> Ich werd' aus dem Datenblatt nicht schlau,

Datenblatt, Seite 288

Fuse Low Byte

    Name        Bit     Default
   -----------------------------
    BODLEVEL    7         1
    BODEN       6         1
    SUT1        5         1
    SUT0        4         0
    CKSEL3      3         0
    CKSEL2      2         0
    CKSEL1      1         0
    CKSEL0      0         1


Board1  00000100
Board2  11101110


Bei deinem Board1 sind die CKSEL Bits also so 0100.
Laut Tabelle 6 auf Seite 38, bedeutet dies, dass der
interne RC-Oszillator aktiv ist.

Bei deinem Board2 sind die CKSEL Bits 1110
Laut derselben Tabelle heist das, das dort ein externer
Quarz (external Crystal) verwendet wird.

Die Einstellung external Crystal ist die, die du haben willst.
Kein Wunder dass dein Board1 nicht die vorgegebene Baudrate
erreicht. Der Prozessor arbeitet nicht mit dem Quarz, sondern
läuft immer noch auf dem internen Oszillator.

von Angelika V. (ange)


Lesenswert?

Karl heiz Buchegger
vielen Dank es wird mir klarer,
wenn ich nun auch die Einstellung für SUT1..0 von Board2, also laut 
Datenblatt bei CKSEL0 auf 0 somit auf "Chystal Oscillator, fast rising 
power", übernehmen würde, wäre ich damit wahrscheinlich im grünen 
Bereich.
Brownout(Spannungseinbruch)-Detektor ist bei Board2 ausgeschaltet.
d.h. ich kann die Einstellung für Fuse Low Byte (11101110) von Board2 
übernehmen.
ich hoffe das stimmt so,
nun noch eins, wie kann ich das im Interaktive Terminal Mode von Avrdude 
eingeben?

von Niels H. (monarch35)


Lesenswert?

Angelika Voß wrote:

> nun noch eins, wie kann ich das im Interaktive Terminal Mode von Avrdude
> eingeben?

Die Antwort auf diese Frage hatte ich bereits ein Post vor Herrn 
Bucheggers Posting gegeben.

von Angelika V. (ange)


Lesenswert?

ist das dann so ok?
averdude -p m128 -u -c stk200 -t -F
und dann:
averdude> d lfuse
averdude> w lfuse 0 0xee

von Niels H. (monarch35)


Lesenswert?

Angelika Voß wrote:

> averdude> w lfuse 0 0xee

sollte passen. Die hfuse nicht vergessen! Die beinhaltet nämlich CKOPT.

von Karl H. (kbuchegg)


Lesenswert?

Niels Hüsken wrote:

> vor Herrn Bucheggers Posting gegeben.

Einfach nur 'Karl Heinz' oder noch einfacher 'Heinz'.
Herr Buchegger, das ist mein Vater :-)

von Angelika V. (ange)


Lesenswert?

ist klar,
ich habe hfuse und lfuse geändert,
und das Testprogramm laufen lassen, dass Daten über serielle 
Schnittstelle an den Rechner sendet. Es funktioniert auf beiden Boards!!
Die Werte werden korrekt auf dem Hyperterminal angezeigt.
Ich danke euch allen für euren freundlichen Rat.
Angelika

von Niels H. (monarch35)


Lesenswert?

Karl heinz Buchegger wrote:

> Einfach nur 'Karl Heinz' oder noch einfacher 'Heinz'.
> Herr Buchegger, das ist mein Vater :-)

Ist schon klar. Die Nettiquette sagt eindeutig "Im de-Usenet duzt man 
sich". Deshalb gehe ich eigentlich auch immer davon aus, daß das "du" 
okey ist.

Das hier sollte sich allerdings absichtlich etwas "literarisch" 
anhören.... mache ich in R/L mit meinen Freunden auch öfter so :)

von Angelika V. (ange)


Lesenswert?

Herr Niels ;)
ich hoffe ich bin Ihnen da nicht über den großen Zehen geschlappt
auf jeden Fall viele Grüsse

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.