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

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.