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?
Du musst den Zugriff auf a in der Waitfunktion atomar machen.
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
wie atomar? Das Programm ist ganz simpel.
1 | int main(void) |
2 | {
|
3 | TCCR0 = 3; |
4 | TIMSK |= (1<<TOIE0); |
5 | |
6 | InitPorts(); |
7 | |
8 | sei(); |
9 | |
10 | while(1) |
11 | {
|
12 | LedOn; //Macro |
13 | Wait(500); // bei 255 geht es bestens |
14 | LedOff; //Macro |
15 | Wait(500); |
16 | }
|
17 | }
|
18 | |
19 | ...
|
20 | |
21 | ISR(TIMER0_OVF_vect) |
22 | {
|
23 | if (TimerWait != 0) TimerWait --; |
24 | }
|
25 | ...
|
26 | |
27 | void Wait(uint16_t b) |
28 | {
|
29 | TimerWait = b; |
30 | |
31 | while(TimerWait != 0) |
32 | {
|
33 | b += 1; // nur so, damit ich beim Simulieren |
34 | b -= 1; // b verändern kann |
35 | }
|
36 | }
|
37 | |
38 | ...
|
39 | |
40 | volatile uint16_t TimerWait; |
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
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.
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?
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
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.