(Ein kleines Echo zum Testen des USARTs beim ATmega 8, eigentlich nichts
dolles...). serialReceivedDataWaiting() ist definiert als
1
unsignedcharserialReceivedDataWaiting(){
2
return(rxBufferNextPut!=rxBufferNextGet);
3
}
rxBufferNextPut und rxBufferNextGet sind Indizes in einen Ringpuffer.
Bevor serialReceivedDataWaiting () das erste mal eine 1 zurücmkgibt,
funktioniert alles wie erwartet. War das Ergebnis jedoch einmal 1, wird
der then-Block bei jedem Durchlauf ausgeführt. Behelfe ich mir jedoch
mit einer temporären Variable
1
unsignedchartemp2;
2
[...]
3
temp2=serialReceivedDataWaiting();
4
if(temp2){serialPutC(serialGetC());}
funktioniert alles, wie es soll. Was übersehe ich hier?
Gruß & Dank,
Michael
Mit den kleinen Codeschnipseln wird es schwierig dir zu helfen. Zeig mal
den ganze Code. In die Autowerkstatt geht man ja auch mit dem ganzen
Wagen, und nicht nur mit dem Zündschlüssel.
versuche es mal mit if (Bedingung)
also in der Form
zahl = serialReceivedDataWaiting();
if (zahl<3) { ;};
Dann wird klarer was passiert, vor allem wenn das Funktionsergebnis
vorher in eine Variable abgespeichert wird, kann besser der
Programmablauf verfolgt werden.
Ähm... Wenn das Funktionsergebnis vorher in einer Variable abgespeichert
wird, funktioniert es, wenn nicht, nicht. Das schrieb ich oben...
Dieses Verhalten tritt bei -O0 genauso auf wie bei -Os, ist also kein
Optimierungsartefakt. In meiner Verzweiflung habe ich tatsächlich sogar
mal mit
1
if(serialReceivedDataWaiting()!=0)
probiert, dies macht keinen Unterchied (und sollte es ja auch nicht).
Hat nichts mit deinem Problem zu tun: Der Test auf die race condition in
serialPutC funktioniert so nicht. Wenn UDR mit cli leer läuft, der
Puffer aber nicht leer ist, dann sendest du in verkehrter Reihenfolge.
Rein von der Logik her müsste es eigentlich gehen.
Möglicherweise solltest Du mal mit der Optimierung "spielen". Vielleicht
haut die irgendwas raus.
Alternativ kannst Du auch eine .lss Datei erzeugen lassen und Dir die
Stelle, die spinnt, aus der Nähe anschauen.
Das Wegoptimieren von: serialGetC () wäre so ein Kandidat. Dann geht’s
dauernd rund.
A. K. schrieb:> Hat nichts mit deinem Problem zu tun: Der Test auf die race condition in> serialPutC funktioniert so nicht. Wenn UDR mit cli leer läuft, der> Puffer aber nicht leer ist, dann sendest du in verkehrter Reihenfolge.
Stimmt, danke!
Michael Graf schrieb:> müsste dann aber funktionieren - oder?
Spar dir den Zirkus mit der Optimierung darin, schreib den Kram stets in
den Puffer und schalte den Interrupt ein. cli/sei ist dann völlig
überflüssig. Worst case ist ein unnötiger Interrupt.
A. K. schrieb:> Spar dir den Zirkus mit der Optimierung darin, schreib den Kram stets in> den Puffer und schalte den Interrupt ein. cli/sei ist dann völlig> überflüssig. Worst case ist ein unnötiger Interrupt.
Hast Recht. Als ich den Mechanismus eingebaut habe, dachte ich noch, der
UDRE-Interrupt würde durch den Übergang von 0 nach 1 ausgelöst, nicht
davon, dass UDRE 1 ist, so dass ich das erste Byte immer manuell
schreiben müsste... Danach habe ich ihn nicht mehr ausgebaut.
> Das Wegoptimieren von: serialGetC () wäre so ein Kandidat. Dann geht’s> dauernd rund.
Ich habe mir den Sourcecode noch nicht reingezogen, aber zu einem
Empfang gehört auch das Löschen (wie auch immer) des abgeholten
Zeichens.
Sagt die Routine serialReceivedDataWaiting(): jemand ist zuhause - so
lange das nicht der Fall ist, geht's ja gut und erfolgt ein Aufruf von:
serialPutC () ohne das eingefügte serialGetC (), so wird auch der
Empfangspuffer nicht aktualisiert und die Abfrage liefert somit auch
beim nächsten Durchlauf true. Usw.
Hier wird die Funktion serialReceivedDataWaiting() 2x aufgerufen
temp2 = serialReceivedDataWaiting();
// serialPutC (temp2+0x30);
if (serialReceivedDataWaiting()
Möglicherweise sind beim 2. mal die Daten schon als nicht mehr als
Waiting
registriert, weil keine neuen Daten empfangen wurden, und angenommen
wird das die Daten abgeholt werden, wenn die Funktion
serialReceivedDataWaiting() aufgerufen wird ? Deshalb liefert diese ein
anderes Ergebnis.
Kenne leider die Funktionsbeschreibung nicht.
lutz h. schrieb:> Hier wird die Funktion serialReceivedDataWaiting() 2x aufgerufen> Möglicherweise sind beim 2. mal die Daten schon als nicht mehr als> Waiting> registriert, weil keine neuen Daten empfangen wurden, und angenommen> wird das die Daten abgeholt werden, wenn die Funktion> serialReceivedDataWaiting() aufgerufen wird ? Deshalb liefert diese ein> anderes Ergebnis.>> Kenne leider die Funktionsbeschreibung nicht.
Die steht im ersten Post (und später im angehängten Quelltext).
serialReceivedDataWaiting() greift nur lesend auf die Indizes zu.
Hast du mal die Warnungen eingeschaltet oder gar gelesen? Mir fehlt in
AVRGCC2.c ein #include "mjgSerial.h" oder so, mit der Deklaration der
entsprechenden Funktionen. Weshalb der Return-Typ von
serialReceivedDataWaiting in alter K&R-Tradition als int angenommen
wird.
Ist er aber nicht, und so steht in der oberen Hälfte des vom Aufrufer
angenommenen 16-Bit Werts zufällig einer der Indizes drin. Und der ist
nach dem ersten Byte erst einmal ein Weilchen != 0.
A. K. schrieb:
Danke, das war's!
> Hast du mal die Warnungen eingeschaltet oder gar gelesen?
Doch, aber ich hatte die "implicit declaration" nur für einen
Schönheitsfehler gehalten, und angenommen, dass wenn der Linker die
Funktion findet, es schon irgendwie passen wird.
> Weshalb der Return-Typ von> serialReceivedDataWaiting in alter K&R-Tradition als int angenommen> wird.> Ist er aber nicht, und so steht in der oberen Hälfte des vom Aufrufer> angenommenen 16-Bit Werts zufällig einer der Indizes drin. Und der ist> nach dem ersten Byte erst einmal ein Weilchen != 0.
Danke, dass Du mir das Brett vom Kopf genommen hast. Rückblickend hätte
es mir klar sein sollen...