Forum: Mikrocontroller und Digitale Elektronik ATMEGA328P-PU: USART sendet ungültige Zeichen bei 8MHz, funktioniert aber bei 1 MHz


von Klaus V. (klausvalse)


Angehängte Dateien:

Lesenswert?

Guten Tag!

Ich versuche die serielle Schnittstelle am ATMEGA328P-PU zu 
programmieren. Ist ja mit den ganzen Code-Beispielen im Datenblatt nicht 
so schwer, aber jetzt stehe ich vor einem Problem, bei dem ich nicht 
mehr weiterweiß...

Die Fusebits sind so gesetzt, dass der µC auf dem internen RC Oszillator 
läuft, bzw. laufen sollte:
FUSES = -U lfuse:w:0xE2:m -U hfuse:w:0xd9:m

Leider bekomme ich auf meinem Serial-Terminal nur Fragezeichen, egal 
welche Baudrate ich beiderseits eingestellt habe.
Wenn ich jedoch das Clock Division Fusebit setze, sodass der µC auf 1Mhz 
läuft funktioniert alles wunderbar und ich habe keine Ahnung warum.
Wenn möglich würde ich gerne auf einen externen Quarz verzichten, vor 
allem kann's doch nicht nicht sein dass die USART mit schnellerem 
Systemtakt schlechter funktioniert.

Vielleicht hilft ist ja ein Fehler in meinem Init-Code, den ich 
übersehen habe, obwohl er eigentlich aus dem Datenblatt übernommen 
ist...
Den Wert für das UBRR Register habe ich aus dem Datenblatt (siehe 
Screenshot im Anhang). Der Wert sollte am µC 9600 Baud einstellen.

1
int USART_Init()
2
{
3
    /* see table 20-6 on page 189 in the datasheet */
4
    unsigned long ubrrValue = 51;
5
        
6
    /* Set baud rate */
7
    UBRR0H = (unsigned char)(ubrrValue>>8);
8
    UBRR0L = (unsigned char)ubrrValue;
9
    /* Enable receiver and transmitter */
10
    /* See page 192 in the datasheet */
11
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
12
    /* Set frame format: 8 data, 2 stop bits */
13
    /* USART mode is set to asynchronous by default */
14
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
15
    return 0;
16
}

Ich bin dankbar für jeden Versuch mir zu helfen!

: Bearbeitet durch User
von K. J. (Gast)


Lesenswert?

Ich kann jetzt weder C noch AVR aber tip ins Blaue:
"unsigned long ubrrValue = BR4800F_CPU1MHZ;"

von Klaus V. (klausvalse)


Lesenswert?

Danke für deine Zeit. Habe übersehen, dass noch diese Missverständliche 
Zeile drinnen hatte. Hab es jetzt durch den konkreten Wert ersetzt - 
funktioniert zwar noch immer nicht, ist aber jetzt vielleicht weniger 
irreführend...

von Quarzbastler (Gast)


Lesenswert?

Klaus V. schrieb:
> Ich bin dankbar für jeden Versuch mir zu helfen!

Der interne Oszillator ist warscheinlich nicht genau genug
um die Baudrate ausreichend korrekt zu erzeugen.

Du wirst womöglich auf längere Sicht einen Quarz
verwenden müssen.

Klaus V. schrieb:
> /* Set frame format: 8 data, 2 stop bits */

2 Stop Bits sind eher ungewöhnlich .....
..... vielleicht willst du das nicht. Alles was ich so kenne
kommuniziert mit 1 Stop Bit und no parity.

von c-hater (Gast)


Lesenswert?

Klaus V. schrieb:

> Wenn möglich würde ich gerne auf einen externen Quarz verzichten

Das ist natürlich möglich, aber dann musst du eben den Takt kalibrieren. 
Der interne RC-Oszillator ist einfach von Hause aus nicht genau genug, 
um das zuverlässig garantieren zu können.

Ja klar, jetzt werden wieder die ganzen Idioten rumschreien, dass es bei 
ihnen auch ohne Kalibrierung geht, aber das ist nur reiner Zufall. Die 
Toleranzen sind einfach so, dass es tatsächlich mit einer einigermaßen 
hohen Wahrscheinlichkeit gehen wird, aber eben noch lange nicht mit 
einer Wahrscheinlichkeit, die man als "zuverlässige Funktion" durchgehen 
lassen kann.

Und selbst mit erfolgter Kalibrierung hängt es dann davon ab, ob 
danach die Umweltbedingungen, inbesondere die Temperatur hinreichend 
konstant sind. Denn die Kalibrierung optimimiert den Takt natürlich nur 
für die Umweltbedingungen zum Zeitpunkt der Kalibrierung.

> vor
> allem kann's doch nicht nicht sein dass die USART mit schnellerem
> Systemtakt schlechter funktioniert.

Doch, natürlich kann das sein. Das liegt an der Rundung bei der 
Berechnung des Teilers aus der gewünschten Baudrate und dem ja leider 
nur rein hypothetischen Takt, der als Ausgangspunkt dieser Berechnung 
dient.

Würde dieser hypothetische Takt dann tatsächlich geliefert, dann könnte 
es tatsächlich nicht sein, dann würde tendenziell bei höheren Takt die 
Wahrscheinlichkeit für die Funktion steigen, aber er wird ja eben mit 
hoher Wahrscheinlichkeit NICHT geliefert, weil der RC-Oszillator halt 
nicht genau genug ist. Genau deswegen nimmt man ja einen Quarz, 
Resonator oder kalibriert wenigstens den RC-Oszillator...

von Wilhelm M. (wimalopaan)


Lesenswert?

Klaus V. schrieb:

>
1
> int USART_Init()
2
> {
3
>     /* see table 20-6 on page 189 in the datasheet */
4
>     unsigned long ubrrValue = 51;
5
> 
6
>     /* Set baud rate */
7
>     UBRR0H = (unsigned char)(ubrrValue>>8);
8
>     UBRR0L = (unsigned char)ubrrValue;
9
>     /* Enable receiver and transmitter */
10
>     /* See page 192 in the datasheet */
11
>     UCSR0B = (1<<RXEN0)|(1<<TXEN0);
12
>     /* Set frame format: 8 data, 2 stop bits */
13
>     /* USART mode is set to asynchronous by default */
14
>     UCSR0C = (1<<USBS0)|(3<<UCSZ00);
15
>     return 0;
16
> }
17
>
>

Dies scheint direkt aus dem Datenblatt entnommen worden zu sein. 
Allerdings wird dort eben ein Modus mit 2(!!!)-Stop-Bits eingeschaltet: 
(1<<USBS0). Das steht auch so im Kommentar, und der ist auch richtig ;-)

Benutzt man irgendwelche Terminalprogramme auf dem Host, etwa picocom 
(Linux), dann ist der default-Modus dort meistens: 1(!!!)-Stop-Bit.

Also: welches Terminalprogramm mit welchen Einstellungen verwendest Du?

von grundschüler (Gast)


Lesenswert?

Wenn der unveränderte Code bei 1mhz funktioniert und bei 8mhz nicht, ist 
das wohl code für 1mhz und das ganze problem hat mit kalibrierung nichts 
zu tun.

Also schauen wie die Usart-Einstellungen an die Taktfrequenz angepasst 
werden.

von g457 (Gast)


Lesenswert?

2 Stoppbits beim Sender und nur eines beim Empfänger ist ungünstig aber 
hier irrelevant.

von g457 (Gast)


Lesenswert?

> FUSES = -U lfuse:w:0xE2:m -U hfuse:w:0xd9:m

Das setzt CKDIV8 (=0).

> Wenn ich jedoch das Clock Division Fusebit setze, sodass der µC auf 1Mhz
> läuft funktioniert alles wunderbar und ich habe keine Ahnung warum.

Das hat obiger Parameter getan. Hast Ich vermute Du hast CKDIV8 hier 
stattdessen gelöscht (=1) - Problem gelöst.

von Wolfgang (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Benutzt man irgendwelche Terminalprogramme auf dem Host, etwa picocom
> (Linux), dann ist der default-Modus dort meistens: 1(!!!)-Stop-Bit.

Und was hat das jetzt mit dem Problem zu tun. Wenn der Sender ein 
Stop-Bit mehr sendet als der Empfänger erwartet, heißt das lediglich, 
dass das nächste Byte eine Bit-Dauer später gesendet wird, als es 
minimal nötig wäre.

Das Terminalprogramm funktioniert doch auch, wenn nur ab und zu mal ein 
Zeichen vom Sender kommt ;-)

g457 schrieb:
> 2 Stoppbits beim Sender und nur eines beim Empfänger ist ungünstig aber
> hier irrelevant.

Das einzige, was daran ungünstig ist, ist das die Übertragung 10% länger 
dauert, man also etwas Zeit verschenkt.

von g457 (Gast)


Lesenswert?

arrgs, sollte erst mehr Kaffee trinken.

>> FUSES = -U lfuse:w:0xE2:m -U hfuse:w:0xd9:m
>
> Das setzt CKDIV8 (=0).

Das löscht CKDIV (=1). Damit läuft er mit 8MHz.

> Ich vermute Du hast CKDIV8 hier stattdessen gelöscht (=1) - Problem
> gelöst.

..gesetzt (=0), damit läuft der µC mit 1MHz.

</Ingrid>

von g457 (Gast)


Lesenswert?

> Das einzige, was daran ungünstig ist, ist das die Übertragung 10% länger
> dauert, man also etwas Zeit verschenkt.

Nein, was ungünstig ist dass zukünfigt Probleme vorprogrammiert sind 
wenn Empfänger und Sender ihre Rollen mal tauschen sollen und der Sender 
dann mit 1 Stoppbit sendet und der Empfänger mit zweien zu empfangen 
versucht.

von Wolfgang (Gast)


Lesenswert?

g457 schrieb:
> Nein, was ungünstig ist dass zukünfigt Probleme vorprogrammiert sind ...

Manchmal ist es ganz hilfreich, wenn man einfach weiss, was man tut ;-)

von Klaus V. (klausvalse)


Lesenswert?

Vielen Dank für eure Antworten! Ich werde mal versuchen einen 16MHz 
Quarz anschließen und mich mit den Start und Stop Bits spielen.
Stay tuned!

von eProfi (Gast)


Lesenswert?

Zwei Stoppbits bezieht sich beim 328 nur auf den Sender.
Beim Empfänger ist die Einstellung der Stopbits egal.
> Stop Bit Select bit (UCSRnC.USBSn) select the number of stop bits.
> The Receiver ignores the second stop bit.
Das dürfte bei vielen anderen Geräten genau so sein.

2 Stoppbits sind auf jeden Fall sicherer, wenn die Baudrate nicht ganz 
stimmt, denn der Empfänger kann sich besser synchronisieren.

Versuche, die Frequenz des RC-Oszillators zu bestimmen, z.B. eine LED 60 
mal im Sekundenrythmus blinken zu lassen und schauen, ob das eine Minute 
dauert.  Viele Multimeter haben inzwischen einen Frequenzzähler.

von Axel S. (a-za-z0-9)


Lesenswert?

Wilhelm M. schrieb:
> Dies scheint direkt aus dem Datenblatt entnommen worden zu sein.
> Allerdings wird dort eben ein Modus mit 2(!!!)-Stop-Bits eingeschaltet:
> (1<<USBS0). Das steht auch so im Kommentar, und der ist auch richtig ;-)
>
> Benutzt man irgendwelche Terminalprogramme auf dem Host, etwa picocom
> (Linux), dann ist der default-Modus dort meistens: 1(!!!)-Stop-Bit.

Und? Das ist doch vollkommen Wumpe. Die Stoppbit-Einstellung gilt 
sowieso immer nur für den Sender. Und auch da spielt sie nur dann eine 
Rolle, wenn das Programm einen dauerhaften Datenstrom in das Sende- 
Register schreibt. Was entweder eine Pufferung auf Senderseite 
voraussetzt oder eine enge Schleife oder eine Sende-Routine mit Buffer 
und Interrupt. Wenn der Sender nichts zu senden hat, dann "sendet" er 
permanent Stopbits.

g457 schrieb:
> dass zukünfigt Probleme vorprogrammiert sind
> wenn Empfänger und Sender ihre Rollen mal tauschen sollen und der Sender
> dann mit 1 Stoppbit sendet und der Empfänger mit zweien zu empfangen
> versucht.

Blödsinn. Kein UART den ich jemals gesehen habe, hatte eine Einstellung 
für die Anzahl der Stopbits auf Empfangsseite. Wozu auch? Das Startbit 
wird benötigt, um den Empfangstakt wieder zu synchronisieren (das "U" in 
UART steht nämlich wofür?). Und das Stopbit garantiert nur, daß es 
zwischen dem letzten Datenbit und dem Startbit eine Pause gibt.

Die Einstellung "2 Stopbits" ist eine Hommage an schlechte UARTs aus der 
Vergangenheit, die noch kein 16x Oversampling konnten und sich nicht so 
gut synchronisieren konnten.

von Wilhelm M. (wimalopaan)


Lesenswert?

Axel S. schrieb:
> Wilhelm M. schrieb:
>> Dies scheint direkt aus dem Datenblatt entnommen worden zu sein.
>> Allerdings wird dort eben ein Modus mit 2(!!!)-Stop-Bits eingeschaltet:
>> (1<<USBS0). Das steht auch so im Kommentar, und der ist auch richtig ;-)
>>
>> Benutzt man irgendwelche Terminalprogramme auf dem Host, etwa picocom
>> (Linux), dann ist der default-Modus dort meistens: 1(!!!)-Stop-Bit.
>
> Und? Das ist doch vollkommen Wumpe.

Ok, oben habe ich mich falsch ausgedrückt, und es ist hier kein Problem.

> Die Stoppbit-Einstellung gilt
> sowieso immer nur für den Sender.

Das stimmt wahrscheinlich meistens, aber nicht immer. Der 
FreeBSD-Serial-Treiber liefert bspw. ein FrameError, wenn er auf 
2-Stop-Bits eingestellt ist, aber nur eins kommt: weil der Sender schon 
wieder startet (weil 1-Stop-Bit) oder die Übertragung fehlerhaft ist.

> Und auch da spielt sie nur dann eine
> Rolle, wenn das Programm einen dauerhaften Datenstrom in das Sende-
> Register schreibt. Was entweder eine Pufferung auf Senderseite
> voraussetzt oder eine enge Schleife oder eine Sende-Routine mit Buffer
> und Interrupt. Wenn der Sender nichts zu senden hat, dann "sendet" er
> permanent Stopbits.

Genau: und das wissen wir nicht ...

von M. K. (sylaina)


Lesenswert?

Klaus V. schrieb:
> Wenn ich jedoch das Clock Division Fusebit setze, sodass der µC auf 1Mhz
> läuft funktioniert alles wunderbar und ich habe keine Ahnung warum.

Wenn du nur das Fuse-Bit änderst und es dann geht dann stimmt schlicht 
dein UBBR-Wert nich.

von Phantomix X. (phantomix)


Lesenswert?

Axel S. schrieb:
> Das Startbit wird benötigt, um den Empfangstakt wieder zu synchronisieren
> (das "U" in UART steht nämlich wofür?).

Universal.
Meinten Sie: "das \"A\" in UART steht nämlich wofür"?

M. K. schrieb:
> Wenn du nur das Fuse-Bit änderst und es dann geht dann stimmt schlicht
> dein UBBR-Wert nich.

Das wollte ich auch schon anmerken. Die UART-Konfig ist abhängig vom 
Eingangstakt.

von Klaus V. (klausvalse)


Lesenswert?

M. K. schrieb:
> Wenn du nur das Fuse-Bit änderst und es dann geht dann stimmt schlicht
> dein UBBR-Wert nich.

Ja ich hab die Werte für UBRR eh geändert, je nach Wert in der Tabelle. 
Hat auch nichts gebracht. Das schöne ist: auf der Suche nach der Lösung 
dieses Problems bin ich in ein noch viel größeres gelaufen: die CPU 
Frequenz einstellen. Ein Quarz wird ignoriert, da kann ich mich auf den 
Kopf stellen und 10 mal die Fusebits so einstellen dass ein externen 
Oscillator ausgewählt wird - bringt nichts. Das #define F_CPU 8000000 
ist ihm auch wurst, da kann ich 123 reinschreiben - es ändert sich 
nichts. Wenn ich aber das Compiler Argument im Makefile ändere, dann 
ändert sich F_CPU sehr wohl.
1
-DF_CPU=$(CLOCK)

Lasse ich es jedoch weg, und auch das #define im main File, funktioniert 
der Code auch - nur halt nicht so wie ich es einstellen will. Keine 
Ahnung. Ich hab bisher mit dem 328p-pu nur Probleme gehabt. Der 
ATTINY2313 hat immer funktioniert wie er soll, aber der 328er ist so ein 
Dreck. Derzeit antwortet er gar nicht mehr (obwohl ich keine Fusebits 
verpfuscht hab und er mit den selben Einstellungen am Computer und auf 
dem Steckbrett 3 Sekunden vorher schon 1000 Mal erflogreich flashte). 
Also langsam gehen mir die Ideen und die Lust aus.
Wahrscheinlich werde ich eh noch einen Thread diesbezüglich aufmachen 
müssen, da ich sonst wahrscheinlich eh nicht weiterkomme. Ich weiß eben 
nur noch nicht wie ich ihn nennen soll "ATMEGA328p ist eine blöde Hure" 
oder so vielleicht.

von M. K. (sylaina)


Lesenswert?

Das hat nichts mit dem Atemga328p zu tun sondern mit deiner IDE bzw. 
deinen Einstellungen. Und da liegt was im argen, das ist daran zu 
erkennen, dass bei dir die Fuse-Einstellung für den Quarz ignoriert 
wird.
Was benutzt du denn als IDE? Wie bringst du das Programm in den uC? Wie 
sieht dein Makefile aus?

von Klaus V. (klausvalse)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:
> Das hat nichts mit dem Atemga328p zu tun sondern mit deiner IDE bzw.
> deinen Einstellungen. Und da liegt was im argen, das ist daran zu
> erkennen, dass bei dir die Fuse-Einstellung für den Quarz ignoriert
> wird.
> Was benutzt du denn als IDE? Wie bringst du das Programm in den uC? Wie
> sieht dein Makefile aus?

Danke, du hast mir den entscheidenden Hinweis gegeben, damit jetzt alles 
funktioniert.
Also, so wie es aussieht ist mein altes Powerbook G4 der Übeltäter. Ich 
wollte den kleinen eigentlich zum AVR programmieren benutzen, da man 
sonst aufgrund des Alters eigentlich nicht mehr viel damit machen kann. 
Na jedenfalls hat es von einer flash session auf die andere nicht mehr 
funktioniert. Ich hab's auf deine Antwort hin wieder an meinem Macbook 
probiert und da geht es ohne Probleme.
Nun zu den weiteren Fehlern, wegen denen dieser Thread eigentlich erst 
eröffnet wurde:
- Anfängerfehler Nummer 1:
1
#define F_CPU 8000000UL
muss vor
1
#include <util/delay.h>
stehen, damit der Controller rechtzeitig den Wert kriegt um delays 
richtig berechnen zu können.

- Anfängerfehler Nummer 2:
In meinem selbstzusammengebastelten Makefile habe ich nicht gecheckt 
dass
1
make flash
keine Fusebits setzt. Um das zu tun muss ich zuerst
1
make fuse
aufrufen und dann erst flashen. Jetzt funkt alles wie es soll.

Für alle zukünftig vom 328er gebeutelten, hänge ich meine Dateien an. 
Vielleicht spart das ja irgendjemandem Zeit.

Danke für eure Zeit, Hilfe und Diskussion.
LG, Klaus

von M. K. (sylaina)


Lesenswert?

Einen Tipp zum delay-Problem: Schreib das F_CPU = 80000000UL in das 
Makefile, dann ist es dem gesamten Projekt bekannt ;)

Welche IDE benutzt du denn? Ich nutze das Crosspack und hab auch mit so 
alten Rechnern (bei mir ists ein iBook G4) kein Problem mit dem flashen 
von AVRs

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.