Forum: Mikrocontroller und Digitale Elektronik Blutiger Anfänger mit Timer Problem


von Mario D. (drmario)


Angehängte Dateien:

Lesenswert?

Hallo Leute,
ich bin ein blutiger Anfänger und trau mich kaum ne Frage über Timer zu 
stellen, aber ich seh den Wald vor lauter Bäumen wohl nicht mehr. Ich 
hab mal meinen kompletten C Code angehängt, aber ich wollte kurz auf die 
interessanten Teile eingehen:

Ich hab nen externen Crystal mit 16GHz an nem Atmega644


Meine Frage ist nun, wenn ich oben in meinem Timer die Kommentare weg 
mache, dann blinken die LEDs alle 3 bis 4 Sekunden auf einmal 
unregelmäßig, danach für 3 Sekunden wieder normal.

Mach ich was Grundlegendes falsch? Mache ich zu viele Berechnungen im 
Timer?


Ich hab den Timer mit Clear Timer on Compare Match eingestellt:
1
void timerInit(void) {
2
  TCCR0A = (1 << WGM01); //Mode2: CTC Clear Timer on compare match
3
  TCCR0B = (1 << CS01) | (1 << CS00); // prescaler = 64
4
  OCR0A = 250; //250 Takte = 1ms
5
6
//  TCCR1A = 0; // kein pwm
7
  TIMSK0 = (1 << OCIE0A); //Compare Interrupt aktivieren
8
}
9
10
Meine Timer Interrupt Funktion sieht so aus:
11
ISR (TIMER0_COMPA_vect) {
12
  if (led1on)
13
    led1on--;
14
  millisekunden++;
15
/*  if(millisekunden == 1000) {
16
    sekunde++;
17
    millisekunden = 0;
18
  }
19
    if(sekunde == 60) {
20
         minute++;
21
         sekunde = 0;
22
    }
23
    if(minute == 60) {
24
      stunde++;
25
      minute = 0;
26
    }*/
27
}
28
29
Dann hier noch meine main:
30
int main(void) {
31
32
  uint16_t delay;
33
34
  cli();
35
  systemInit();
36
  timerInit();
37
  sei();
38
  while (1) {
39
    if (IN(SWITCH_PORT, SWITCH_PIN))
40
      delay = 500;
41
    else
42
      delay = 1000;
43
    if (!led1on) {
44
      leds();
45
      led1on = delay;
46
47
    }
48
  }
49
}

von Frank L. (franklink)


Lesenswert?

Hallo,
ich geb mal einen Tip ohne Gewähr ab, led1on = delay ist kein atomarer 
Zugriff, weil delay ein uint16_t ist.

Mach mal vor der Zuweisung ein cli() und danach ein sei() rein.

Gruß
Frank

von Coder (Gast)


Lesenswert?

Ein
1
volatile uint16_t led1on;
könnte nützlich sein.

von Mario D. (drmario)


Lesenswert?

@Coder:
die led1on ist schon volatile! Hatte ich in dem kurzen Abschnitt nicht 
kopiert aber im main.c ist das zu sehen...

@Frank Link
ich hab jetzt mehrere Sachen versucht, aber irgendwie ist das Springen 
der LEDs immer noch da...

Meine main sieht jetzt so aus, oder hatte ich das falsch verstanden mit 
dem sei cli?
1
int main(void) {
2
  cli();
3
4
  uint16_t delay;
5
6
  systemInit();
7
  timerInit();
8
  sei();
9
  while (1) {
10
    if (IN(SWITCH_PORT, SWITCH_PIN)) {
11
      cli();
12
      delay = 500;
13
      sei();
14
    } else {
15
      cli();
16
      delay = 1000;
17
      sei();
18
    }
19
    if (!led1on) {
20
      leds();
21
      led1on = delay;
22
23
    }
24
  }
25
}

von Frank L. (franklink)


Lesenswert?

Jepp,
hast Du.
1
cli();
2
led1on = delay;
3
sei();

Alle anderen sind nutzlos.

Gruß
Frank

von Mario D. (drmario)


Lesenswert?

Ok, macht Sinn, sind ja 16bit Operationen...
Aber helfen tut es leider auch nicht :-(

von Karl H. (kbuchegg)


Lesenswert?

Mario Dejung schrieb:
> Ok, macht Sinn, sind ja 16bit Operationen...
> Aber helfen tut es leider auch nicht :-(

Das reicht nicht.
Du hast ja noch einen Zugriff auf led1on, den du kapseln musst
1
    cli();
2
    uint16_t tmp = led1on;
3
    sei();
4
5
    if (!tmp) {
6
      leds();
7
      cli();
8
      led1on = delay;
9
      sei();
10
    }

Du hast natürlich dadurch, dass du die ganzen Zeitvariablen alle
unsigned int( also 16 Bit) gemacht hast, dem µC jede Menge unnötige
Fleissaufgabe aufgebürdet. Die solltest du (bis auf Millisekunden) alle
als uint8_t führen. Das langt dicke für Sekunden, Minuten, Stunden.

von Mario D. (drmario)


Lesenswert?

Ok, das scheint des Rätsels Lösung zu sein :-) Danke, auch wenn ich es 
nicht wirklich verstehe... Aber vielleicht kommt da noch bald die 
Routine...

von Rüttiger (Gast)


Lesenswert?

das Problem ist halt dass led1on an zwei Stellen verändert/benutzt wird.

wenn jetzt im main vielleicht gerade das erste Byte geladen wurde, funkt 
plötzlich der IRQ dazwischen, ändert beide Bytes des Wortes und 
plötzlich passen im main die beiden Bytes aus denen ein Wort besteht 
nicht mehr zusammen

von Mario D. (drmario)


Lesenswert?

Hätte man da dann nicht einfacher Weise die komplette if Abfrage in cli 
und sei setzen können, anstatt noch mal drumrum in ne andere Variable u 
speichern? So ungefähr:
1
  while (1) {
2
    if (IN(SWITCH_PORT, SWITCH_PIN)) {
3
      delay = 500;
4
    } else {
5
      delay = 1000;
6
    }
7
    cli();
8
    if (!led1on) {
9
      leds();
10
      led1on = delay;
11
    }
12
    sei();
13
  }

von Roland H. (batchman)


Lesenswert?

Mario Dejung schrieb:
> Ich hab nen externen Crystal mit 16GHz an nem Atmega644

16 GHz? Hoffentlich wird es da dem atmega644 nicht schwindlig :-)

von Mario D. (drmario)


Lesenswert?

Mega Giga, kann man doch mal verwechseln... :-)

By the Way, ich hab die Änderungen mit dem cli und sei gemacht wie in 
meinem letzten Post und das scheint zu funktionieren...

von Karl H. (kbuchegg)


Lesenswert?

Mario Dejung schrieb:
> Hätte man da dann nicht einfacher Weise die komplette if Abfrage in cli
> und sei setzen können, anstatt noch mal drumrum in ne andere Variable u
> speichern? So ungefähr:

Natürlich kann man.
Wichtig ist nur, dass weder bei Abfrage noch beim Beschreiben der 
Variable ein Interrupt dazwischen funken kann.
Du musst dich eben fragen, wie lange du die Interrupts gesperrt haben 
willst.

Ein Schlüsselnotdienst, der sofort reagiert, hilft dir nun mal nichts, 
wenn wegen Telefonsperre keiner abhebt.

von Mario D. (drmario)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ein Schlüsselnotdienst, der sofort reagiert, hilft dir nun mal nichts,
> wenn wegen Telefonsperre keiner abhebt.

:-) Danke, den Vergleich hab ich gebraucht! :-)

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
Noch kein Account? Hier anmelden.