Datum:
Meine "void Wait(uint16_t a)" Funktion sieht so aus: - eine Variable (a) wird in der Interruptroutine runtergezählt bis sie gleich Null ist. Timer0 OVF if(a!=0) a--; - Die Waitfunktion wartet einfach nur bis a = 0 ist. while(a != 0) dann ist die Pause zu Ende. Sobald aber "a" größer als 255, also 16Bit groß ist, kommt es zu Aussetzern. Lasse ich z.B. eine Led blinken, dann geht es 5 bis 10 mal gut, dann gibt es einen Sprung, nur kurzes Aufleuchten. WDR ist abgeschaltet, auch alle anderen IR habe ich mal weggenommen. Bei 8Bit (<256) geht es perfekt. Könnt Ihr helfen?
Datum:
Programm zeigen
Datum:
Du musst den Zugriff auf a in der Waitfunktion atomar machen.
Datum:
Na ist relativ einfach zu erklären. Du hast eine 16 Bit Variable auf einem 8 Bit µC Fall 1: Der Wert ist zwischen 0 und 255. Es wird nur ein Byte der Variable genutzt ==> R/W Zugriff auf das höhere Byte ist egal, da eine 0 mit einer 0 beschrieben / gelesen wird. ==> R/W zugriff auf das niedrige Byte ist eine einzelner Zugriff der nicht unterbrochen werden kann. ==> alles gut :-) Fall 2: Der Wert ist > 255 ==> R/W Zugriff auf das höhere Byte erfolgt. ==> und jetzt kommt der böse Interrupt und verändert den Zähler ==> R/W Zugriff auf das niedrige Byte erfolgt dann NACH dem Interrupt. ==> Variablen Wert ist somit korrumpiert worden. ==> Müll Und das ist dein Problem. Stichworte zur Lösung: * Interrupt sperre während der Variablenbearbeitung * Volatile * 2 Variablen nutzen mit definierter Werteübergabe
Datum:
wie atomar? Das Programm ist ganz simpel.
int main(void) { TCCR0 = 3; TIMSK |= (1<<TOIE0); InitPorts(); sei(); while(1) { LedOn; //Macro Wait(500); // bei 255 geht es bestens LedOff; //Macro Wait(500); } } ... ISR(TIMER0_OVF_vect) { if (TimerWait != 0) TimerWait --; } ... void Wait(uint16_t b) { TimerWait = b; while(TimerWait != 0) { b += 1; // nur so, damit ich beim Simulieren b -= 1; // b verändern kann } } ... volatile uint16_t TimerWait; |
Datum:
Jens schrieb: > wie atomar? > > Das Programm ist ganz simpel. Eben ein wenig zuu simpel. Der Vergleich in dieser Schleife "while(TimerWait != 0)" erfolgt in mehreren Schritten. Wenn der Interrupt zwischen drin kommt, kann es Probleme geben: - TimerWait ist 0x0100 - der Vergleich beginnt mit dem Low-Byte, das ist gleich 0 - jetzt kommt der Interrupt und ändert TimerWait auf 0x00ff - der Vergleich macht weiter mit dem High-Byte, das ist auch gleich 0 => Bedingung ist false, Schleife bricht ab
Datum:
ja, habe ich verstanden, Danke, kann mich auch an die Zeiten das Assembler-Programmierens erinnern - sehr lange her. Wie kann man es einfach ändern? Ich dachte volatile für TimerWait reicht.
Datum:
Danke, dann werde ich das so machen, dass nur ein Flag in der IR-Routine gesetzt wird und der Timer im Hauptprogramm, wenn Flag=1, ggf. -- gesetzt wird. Bedeutet "atomar" also lediglich, darauf achten, dass es nicht zur "Zerspaltung" der 16Bit Varianlen kommt?
Datum:
Jens schrieb: > Bedeutet "atomar" also lediglich, darauf achten, dass es nicht zur > "Zerspaltung" der 16Bit Varianlen kommt? > ja, gilt aber auch genauso für 32 , 64 , .... Bit Variablen