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
intUSART_Init()
2
{
3
/* see table 20-6 on page 189 in the datasheet */
4
unsignedlongubrrValue=51;
5
6
/* Set baud rate */
7
UBRR0H=(unsignedchar)(ubrrValue>>8);
8
UBRR0L=(unsignedchar)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 */
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...
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.
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...
>/* see table 20-6 on page 189 in the datasheet */
4
>unsignedlongubrrValue=51;
5
>
6
>/* Set baud rate */
7
>UBRR0H=(unsignedchar)(ubrrValue>>8);
8
>UBRR0L=(unsignedchar)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
>return0;
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?
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.
> 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.
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.
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>
> 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.
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 ;-)
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.
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.
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 ...
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.
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.
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.
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?
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
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