Timer springt - Sekundentakt hüpft

Gast #2636163
Lesenswert?

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?
Gast #2636185
Lesenswert?

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
Gast #2636193
Lesenswert?

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;
#2636212
Lesenswert?

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
Gast #2636303
Lesenswert?

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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren