Hallo, Ich habe ein Problem mit einem meiner kleinen Projekte: *Zielsetzung:* Ansteuerung eines HD44780-Displays Daten und Befehle werden über UART entgegen genommen => ("C" gefolgt von Kommando, "D" gefolgt von Daten) *Randbedingungen:* 9600 Baud, 8 Datenbits, 1 Stoppbit, keine Parität Interner Takt, 1MHz => Ja, mir ist die Ungenauigkeit des internen Quarzes bekannt! Siehe "Was funktioniert nicht:" *Hardware:* Aufbau auf Steckbrett, mySmartUSB MK2 als UART-Bridge *Was funkioniert:* LCD-Initialisierung, (testweise) angezeigter Text, sekündlich abwechselnder Text (_delay_ms(1000) passt) Anzeige der Ziffern 0 bis 9 und "!" *Was funktioniert nicht:* Anzeige anderer eingehender Zeichen aus UDR => und dadurch funktioniert auch die Abfrage von "C" und "D" nicht Mein Oszi zeigt mir, was ich erwarte: 104µs Bitzeit, Startbit, 8 Datenbits, Stoppbit. Alles entsprechend der gesendeten Bytes. - Dazu verwende ich "putty" unter Windows sowie "screen" unter Debian Stable. In der angehängten ZIP ist das komplette Projekt zu finden. Ich vermute den Fehler allerdings entweder in der State-Machine oder einer falschen UART-Konfiguration. Ich bin zur Zeit etwas überfragt, was den Fehler angeht, und hoffe, dass mir hier jemand helfen kann, oder mal nen Baumstamm nimmt und auf den Fehler zeigt. ;) Ich hoffe, der Code ist verständlich und ausreichend kommentiert. Vielen Dank schonmal im vorraus.
>Ich vermute den Fehler allerdings entweder in der State-Machine oder >einer falschen UART-Konfiguration. Warum schreibst du dir dann nicht einfach ein Minimal-Programm ohne State-Machine? Also in der Hauptschleife nur auf die USART warten und dann sofort auf LCD ausgeben?
Noch einfacher zum Testen: Gibt doch mal einen String auf das Display aus. Vielleicht hast Du da was nicht so ganz verstanden. Wenn das klappt, dann UART -> LCD.
spontan schrieb: > Gibt doch mal einen String auf das Display aus. Vielleicht hast Du da > was nicht so ganz verstanden. Das klappt seit Jahren - und ich habe es auch schon in diesem Projekt erfolgreich getestet. - Steht ja unter "Was funktioniert:" ;) Volker schrieb: > Also in der Hauptschleife nur auf die USART warten und dann sofort auf > LCD ausgeben? Das wird der nächste Schritt sein. Danke für den Tipp.
chris schrieb: > schau dir doch mal das hier an: > Beitrag "LCD über nur einen IO-Pin ansteuern" Das Projekt ist mir durchaus bekannt, jedoch geht es mir in erster Linie um den Lerneffekt und nicht um das bloße einsetzen eines Programmausschnitts. Von den Leuten gibt es ja leider zu viele. - Ist aber zu OT. Wo verstecken sich solche Fehler und wie wird etwas am besten umgesetzt? - Das ist das, was ich wissen möchte. :)
Hallo nochmal, ich habe jetzt mal ein Minimal-Programm aufgespielt:
1 | while(1) |
2 | { |
3 | while((UCSRA & (1 << RXC)) != (1 << RXC)); |
4 | lcd_data(UDR); |
5 | } |
Das Ergebnis ist leider dasselbe, wie initial von mir beschrieben. Ein Tastendruck auf "a" lässt auf dem Display die Zeichenfolge "$?" erscheinen. Das "b" sorgt für "!?". Die Ziffern 0-9 sowie ! und " werden ebenfalls korrekt angezeigt. Das Oszi gibt mir mit Start- und Stoppbit: Bitfolge für "a": L H L L L L H H L H / Hex: 0x61 / ASCII: a Bitfolge für "b": L L H L L L H H L H / Hex: 0x62 / ASCII: b Bitfolge für "1": L H L L L H H L L H / Hex: 0x31 / ASCII: 1 EDIT: Ok, Kommando zurück. Ich habe den Fehler ausfindig machen können. - 50cm vor dem Bildschirm hat jemand vergessen, dass UCSRC:0 für die Polarität ist. - Der jenige nahm fälschlicherweise an, die Bits 1:0 seien UCSZ1 und UCSZ0...
Hmmm schwerwiegender Fehler in OSI-Ebene 8. :-)
Hast du schonmal die 1MHz nachgemessen (Clock per Fuses am entsprechendem Pin ausgeben)? Die kann ohne Abstimmung richtig weit danebenliegen.
Ich würde dir empfehlen, in deiner UART-ISR einen Ringpuffer zu benutzen, damit du mehr Zeichen puffern kannst. Momentan speicherst du nur ein Zeichen. Ist deine Main zu langsam können so Zeichen verloren gehen. Ich nehme meistens als Puffer 80 Byte, es seiden ist gibt einen Grund RAM zu sparen.
Hallo Marcel, Wie Du oben schon beschrieben hast, nutzt Du den internen Takt. Dieser ist recht ungenau und von vielen Parametern abhängig. Das Du auf dem Oszi alles richtig siehst, ist nicht verwunderlich, da hier das Timing auf der PC Seite gemacht wird. Da er der Sender ist. Wer aber sagt Dir, dass der MC seine Abtastung richtig durchführt? Ich würde dennoch mal im Bereich Timing/Takt suchen. Alternativ mal was vom MC senden lassen, dann sieht man dessen Timing. Gruß Jochen
Marcel Papst schrieb: > Wo verstecken sich solche Fehler und wie wird etwas am besten umgesetzt? > - Das ist das, was ich wissen möchte. :) Fang erst mal an, derartige Schreibweisen
1 | void mcuinit(void) |
2 | {
|
3 | // UART initialisieren
|
4 | UCSRA = 0x02; // doppelte übertragungsgeschwindigkeit |
5 | UCSRB = 0x90; // empänger aktivieren, empänger-interrupt |
6 | UCSRC = 0x03; // asynchron, keine Parität, 1 stop-bit, 8 daten-bit |
7 | UBRRH = 0x00; // wird nicht gebraucht, da cpu langsam |
8 | UBRRL = 12; // 9600 Baud bei U2X=1, 0.2% fehler |
zu meiden wie der Teufel das Weihwasser. Damit hast du dann schnon viel
gewonnen. Atmel hat den Bits Namen gegeben und die sollst du auch
benutzen. Dann wird dein Code lesbarer und Fehler fallen hier leichter
auf als wie wenn man erst mal die Bits auseinander dröseln muss.
> jedoch geht es mir in erster Linie um den Lerneffekt
Noble Einstellung. Jedoch kann man sich von anderen auch abschauen, wie
die ihren Code gestalten, so dass er leichter verständlich, lesbarer und
damit weniger fehleranfällig wird. Der Unterschied zwischen guten
Programmiereren und miesen Programmierern besteht nicht nur darin, dass
die ersteren ihre Sprache beherrschen und zig Algorithmen im Kopf haben.
Gute Programmierer schaffen es auch mühelos einen Code so zu schreiben,
dass man ihn in ein paar Sekunden erfassen und verstehen kann. Miese
Programmierer hingegen schmeissen einem beim Codelesen Prügel zwischen
die Beine. Motto "Es war schwer zu schreiben, also soll es auch schwer
zu lesen sein. Und der COmpiler soll mir überhaupt nicht helfen. WO
kommen wir denn da hin, wenn der Compiler für mich aus Taktfrequenz und
Baudrate die Konstante für das UBRR ausrechnen würde? Das wär doch viel
zu einfach, wenn man einen derartigen Parameter simpel ändern könnte.
Nein! Das muss möglichst kryptisch und schwer zu kontrollieren sein. Das
sichert meinen Arbeitsplatz!"
Marcel Papst schrieb: > EDIT: > Ok, Kommando zurück. Ich habe den Fehler ausfindig machen können. - 50cm > vor dem Bildschirm hat jemand vergessen, dass UCSRC:0 für die Polarität > ist. - Der jenige nahm fälschlicherweise an, die Bits 1:0 seien UCSZ1 > und UCSZ0... Hier nochmal mein Edit von gestern Abend. ;) Alle anderen Tipps werde ich in Zukunft beachten, vielen Dank dafür.
Karl Heinz schrieb: > zu lesen sein. Und der COmpiler soll mir überhaupt nicht helfen. WO > kommen wir denn da hin, wenn der Compiler für mich aus Taktfrequenz und > Baudrate die Konstante für das UBRR ausrechnen würde? Das wär doch viel > zu einfach, wenn man einen derartigen Parameter simpel ändern könnte. > Nein! Das muss möglichst kryptisch und schwer zu kontrollieren sein. Das > sichert meinen Arbeitsplatz!" Zusammenhängende Codeteile ordentlich auseinanderlegen, Kommentare löschen oder erst gar nicht schreiben, möglichst oft vor- und zurückspringen, versuchen, gar keine Konstanten zu deklarieren, Variablen und Routinen möglichst kryptische, sinnlose und überlange Namen geben, die sich (wenn irgendwie machbar) möglichst nur in einem Buchstaben voneinander unterscheiden, hilft auch ungemein.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.