PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : while, 16 Bit Zahlen und Interrupt.



BioSniper
15.06.2010, 16:27
Hatte eben ein merkwürdiges Phänomen:

Ich habe einen 16 Bit-Counter, der in einem TMR0 Interrupt alle 0,68ms dekrementiert wird.
Ab und an wurde der Counter in der while-Schleife als 0 erkannt, obwohl er auf 0xFF stand.
Nach kurzer Überlegung bin ich drauf gekommen, dass es an daran liegen muss, dass der Counter 16-Bit lang ist und während der while Schleife ein TMR0-Int auftritt, der einen Unterlauf im Counter verursacht.



while (tmrFREQcounter) ;


Gelöst habe ich das jetzt so:



while (tmrFREQcounter) while (tmrFREQcounter);;


Das funktioniert auch, aber vielleicht gibt es ja eine bessere Lösung. Globale Interrupts verbieten kommt nicht in betracht.

Ich bin jetzt erstmal auf ein char umgestiegen, da habe ich das Problem nicht.

Besserwessi
15.06.2010, 17:38
So schlecht ist die Lösung mit dem 2 mal Abfragen gar nicht. Es geht aber auch besser. Die normale Lösung für eine Atomaren zugriff ist es Interrupts kurz zu sperren und dann wieder freizugeben.

Die erste bessere Lösung ist es die Abfrage in der ISR zu machen, und dann ein extra Flag zu nutzen, das halt nur 1 Byte groß ist.

Die 2 te besser Lösung ist es das Porgramm anders zu schreiben. Es gibt bessere Methoden um Zeiten zu messen oder defierniert zu warten, als in einer ISR zu zählen. Für die Zeitmessung kann man gleich das Timer Regeistser nutzen, und dann ggf. nur noch die Überläufe Zählen. Für eine Wartezeit kann man ähnlich nur die Überläufe Zählen, und den Startwert des Timers passend vorladen. Das Hauptprogramm kann dann ggf. auch den sleep Befehl nutzen. Das gibt dann zyklus-genaue Wartezeiten, und nebenbei weniger Stromverbrauch.

BioSniper
15.06.2010, 18:22
Das mit dem Flag gefällt mir.

Siro
17.06.2010, 21:01
Hallo,
mit dem 16 Bit (2 Byte) Problem hatte ich auch zu kämpfen.
Das Problem tritt unter Umständen immer dann auf, wenn Der Zählerstand zum Beispiel grad auf 256 steht.
Dann ist das High Byte auf 1 und das Low Byte auf 0.

während jetzt das Low Byte abgefragt wird, welches im Moment noch 0 war, springt der Wert eins runter.
dadurch steht nun im Low Byte plötzlich 255 und im High Byte ein 0
Jenachdem, wie der C Compiler seinen Code erstellt hat, kommt dann sicher Blödsinn raus.

Da der PIC nicht 16 Bit direkt vergleichen kann, kommt es hier zu "Unannehmlichkeiten"
Er läd z.B den Wert den Highbytes. Dieser stand auf 1 (wegen dem Zählerstand 256)
durch einen erneuten Zählerwechsel steht aber nun das Lowbyte auf 255 und das High Byte auf 0
Nun erfolgt der Zugriff aufs Low Byte, welches plötzlich auf 255 steht. Das muss unweigerlich in die Hose gehen.

Ich habe meine 16 Bit Timer Null Abfrage zum Beispiel so gelöst:

Lade das Low Byte des Zählers
oderiere das High Byte des Zählers.
oderiere nun nochmal das Low Byte des Zählers.

Wenn jetzt 0 rauskommt, ist der Zähler wirklich auf 0. Selbst wenn innerhalb der Abfrage sich der Zählerstand per Interrupt geändert hat.
Das macht sich in Assembler recht einfach. In "C" hat man nicht so ohne weiteres Zugriff auf die einzelnen Bytes eines
16 Bit Wertes.

in Assembler würde es dann so aussehen:

; warte bis der 16 Bit Zählerwert, welcher im Interrupt runtergezählt wird, Null wird

WarteAufNull:
movf ZaehlerLowByte,W
iorwf ZaehlerHighByte,W
iorwf ZaehlerLowByte,W
btfss STATUS,Z
goto WarteAufNull


vielleicht kannst Du ja etwas damit anfangen.
mfg. Siro