Forum: Mikrocontroller und Digitale Elektronik Timerinterrupts howto


von student (Gast)


Lesenswert?

Hallo,

ich versuche einen Timer zu schreiben, der alle 100µs eine Variable 
hochzählt...
Leider wird der Interrupt nie ausgeführt. Woran könnte das liegen?
1
void enableTime2()
2
{
3
  u8 tmpSREG = SREG;
4
  cli();
5
6
  //normal mode
7
  TCCR0 &= ~(1<<WGM01);
8
  TCCR0 &= ~(1<<WGM00);
9
10
  //normal port operation for OC0
11
  TCCR0 &= ~(1<<COM01);
12
  TCCR0 &= ~(1<<COM00);
13
  TCCR0 &= ~(1<<CS02);
14
15
  //set prescaler to 64
16
  TCCR0 |= 1<<CS01;
17
  TCCR0 |= 1<<CS00;
18
19
  //preload
20
  TCNT0 = 230;
21
22
  //enable overflow interrupts
23
  TIMSK |= 1<<TOIE0;
24
25
  SREG = tmpSREG;
26
27
  //enable interrupts
28
  SREG |= 1<<7;
29
}
30
31
volatile u64 _time;
32
33
void setTime(u64 time)
34
{
35
  u8 tmpSREG = SREG;
36
  cli();
37
  _time = time;
38
  SREG = tmpSREG;
39
}
40
41
u64 getTime()
42
{
43
  u8 tmpSREG = SREG;
44
  cli();
45
  u64 ret = _time;
46
  SREG = tmpSREG;
47
  return ret;
48
}
49
50
ISR(TIMER0_OVF_vect)
51
{
52
  _time += 100;
53
  TCNT1 = 230;
54
  toggleOutputPin(led3);
55
}
56
57
int main()
58
{
59
  Pin* led1 = allocPin(2, 0);
60
  Pin* led2 = allocPin(2, 1);
61
  led3 = allocPin(2, 3);
62
  setAsOutputPin(led1);
63
  setAsOutputPin(led2);
64
  setOutputPin(led1);
65
  setOutputPin(led2);
66
  setTime(0);
67
  enableTime2();
68
  while (1)
69
  {
70
    u64 time = getTime();
71
    if (time != 0 && time%1000000 == 0)
72
    {
73
      toggleOutputPin(led1);
74
    }
75
    _delay_ms(50);
76
    toggleOutputPin(led2);
77
  }
78
  freePin(&led1);
79
  freePin(&led2);
80
  freePin(&led3);
81
}

von student (Gast)


Lesenswert?

edit: led3 wurde auch als ausgang gesetzt

von Dirk (devnull)


Lesenswert?

Hallo,

Du musst erstmal die Interrupts mit sei() freigeben. Wenn Du oben cli() 
benutzt,
solltest Du die Interrupts hinterher mit sei() wieder freigeben.

Schönen Abend noch,
Dirk

von student (Gast)


Lesenswert?

Mach ich doch:
[c]
  SREG = tmpSREG;

  //enable interrupts
  SREG |= 1<<7;
[/]

von Krapao (Gast)


Lesenswert?

Hier mit dem Atmega32 bei 1 MHz habe ich kein Problem.

Um das Programm simulierbar zu machen musste ich ein paar typedefs 
machen, eine Variable definieren und ein paar Funktionen als Dummymakros 
erstellen.

Die ISR wird zum ersten Mal nach 1730 µs ausgeführt. Bis zum 2. und den 
folgenden Aufrufen vergehen dann jeweils 16384 µs. Die unterschiedlichen 
Zeiten kommen davon, dass du in der ISR den falschen Timer Counter 
vorlädst.
Bei F_CPU 16.64 MHz komme ich auch auf ~100µs.

von Stefan E. (sternst)


Lesenswert?

student schrieb:
> Leider wird der Interrupt nie ausgeführt.

Welche Build-Umgebung? AVR-Studio, eigenes Makefile, ...?

von student (Gast)


Lesenswert?

Bei euch blinkt led1 jede Sekunde, led2 schnell und led3 "blinkt" mit 
einer nicht mehr wahrnembaren Frequenz?

Ich verwende Linux + Eclipse + CDT-Plugin + AVR-Plugin(->avr-gcc + 
avrdude) + AVRISPmkII + RNControl + ATmega32

von student (Gast)


Lesenswert?

TCNT1 ist natürlich falsch. Danke für den Hinweis. Das muss TCNT0 sein.

von student (Gast)


Lesenswert?

Mhh, jetzt geht es mehr oder weniger. So ganz rund läuft das aber immer 
noch nicht...
Jedenfalls danke für die Hilfe!
Ich werde am Monrag noch mal in der Uni mit nem Logikanalysator da dran 
gehen.

von Krapao (Gast)


Lesenswert?

> Bei euch blinkt led1 jede Sekunde, led2 schnell und led3 "blinkt" mit
> einer nicht mehr wahrnembaren Frequenz?

Natürlich nicht.

Du hattest geschrieben "IRQ wird nicht aufgerufen", daher habe ich mir 
dieses Problem i Simulator angesehen. Für einen Hardwaretest fehlt doch 
schon der AVR Typ und das Anschlussbild der LEDs!

Aber selbst für die IRQ-Untersuchung fehlten im Sourcecode mehrere 
Funktionen, Variaben und typedefs.

Die Funktionen habe ich kurz und schmerzlos als Dummys implementiert und 
dabei implizit vorausgesetzt, dass die keinen Seiteneffekt auf den IRQ 
haben.

von student (Gast)


Lesenswert?

Das ist klar.
Irgendwie geht es jetzt. Aber wo der Fehler war, kann ich nicht sagen.
Bloß blinkte die LED nicht so, wie ich es erwartet habe:
led an, 1s warten, led aus, 1s warten, ...
sondern etwa recht zufällig:
an, aus, an, aus, 5s warten, an, 10 sek warten,...
teilweise geht die led auch nicht "ganz" an, sondern man sieht es nur im 
unteren bereich kurz aufblitzen
mein toggle habe ich aber ganz normal als xor realisiert
PORT ^= 1<<PIN;

von Krapao (Gast)


Lesenswert?

Timergesteuertes Tooglen und Delay-gesteuertes Toggeln in einem Programm 
vertragen sich nicht besonders gut. Bei dem 50ms Warten hast du 500 
Timer0 IRQs... es ist sehr wahrscheinlich, dass du dadurch den genauen 
Zeitpunkt verpasst, bei dem time%1000000 == 0 ist.

von Krapao (Gast)


Lesenswert?

Bei genau 50ms = 500 IRQs würde es sogar noch klappen. Sobald es aber 
schon 499 oder 501 sind, klappt es schon nicht mehr. Und diese 
Abweichung hast du drin, wenn die Timerberechnung und die 
Delay-Implementierung nicht 100% exakt aufeinander passen.

von student (Gast)


Lesenswert?

VIELEN VIELEN DANK!!!!
Da war mein Denkfehler!

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.