Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt funktioniert nicht


von Jürgen (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche gerade einen ganz einfachen Timer zu programmieren.
Ausrüstung:
Atmega 8515, 4Mhz Quarz, AVR-Studio, GCC.

Es will einfach nicht funktionieren.
Ich kann mit dem AVR Studio ja schön simulieren und habe festgestellt, 
dass die 100 an die Funktion wartems nicht weitergegeben wird. Siehe 
Bild1.jpg.

Mir ist der Verdacht aufgekommen, dass eventuell der Simulator Bugs hat 
und habe das Programm auf den Controller gespielt. Funktioniert aber 
auch nicht.

Habe ich irgend wo was vergessen?

Jürgen

PS: timer.c ist das Hauptprogramm

von Joachim (Gast)


Lesenswert?

Hallo

Schau dir mal warteus an. Kommst du da jemals wieder raus.
timer bleibt immer 0 und somit immer kleiner timerus (falls > 0)

Warum werden solche wartezeiten eigentlich immer neu erfunden??

Gruß
Joachim

von Karl H. (kbuchegg)


Lesenswert?

Joachim schrieb:
> Hallo
>
> Schau dir mal warteus an. Kommst du da jemals wieder raus.
> timer bleibt immer 0 und somit immer kleiner timerus (falls > 0)

Das ist nicht der Grund.
timer ist eine globale Variable, die in der ISR erhöht wird.

>     TCCR0 &= ~(1<<CS01)|(1<<CS00);  // Kein Prescaler

Ein Timer läuft, sobald du einen Prescaler zuweist.
Hat der Timer einen Prescaler von 0, so läuft er auch nicht. Ein Timer 
der nicht läuft, zählt auch nicht. Ein Timer der nicht zählt generiert 
auch keine Overflows. Keine Overflows, keine ISR. Den Rest kannst du dir 
denken

von Jürgen (Gast)


Lesenswert?

Danke für die Antworten.

ich habe das Programm folgender masen verändert:
1
   TCCR0 &= ~(1<<CS02)|(1<<CS01);  // Kein Prescaler 
2
   TCCR0 |= (1<<CS00);

Jetzt funktionierts zwar auf dem Controler aber die Simulation stimmt 
immer noch nicht. Auserdem stimmt die Wartezeit nicht. Eine Periode 
(Also LED an, LED aus) dauert 1.86s. Deshalb wollte ich ja eine eigene 
Routine machen um eine genaue Zeit zu bekommen.
Wo habe ich falsch gedacht?

von Karl H. (kbuchegg)


Lesenswert?

Jürgen schrieb:

> Wo habe ich falsch gedacht?

µC sind zwar schnell. Aber so schnell auch wieder nicht. Du gibst dem 
Timer genau 4 Taktzyklen Zeit ehe er den nächsten Overflow auslösen 
soll. 4 Takte, da ist der Inhalt deiner ISR schon länger.

Kurz gesagt: Deine Vorgaben sind nicht erfüllbar.

von Jürgen (Gast)


Lesenswert?

Ohh, da übervordere ich ihn ein bischen. :-)

muss ich woll ein wennig umrechnen.

Aber wieso funktioniert es in der Simulation nicht?

Danke.

von Jürgen (Gast)


Lesenswert?

Wenn ich den Timer mit 216 vorlade, dauert es 10µs bis der nächste 
Interrupt kommt. Ist das besser?

von Karl H. (kbuchegg)


Lesenswert?

Au´s dem Bauch heraus: 40 Takte ist immer noch verdammt wenig.

Und gewöhn dir den Quatsch mit Vorladen am besten gleich wieder ab, wenn 
du halbwegs vernünftige Timings haben willst (zumindest bei einem 
Vorteiler von 1). Vom Zeitpunkt wenn der Timer seinen Overflow auslöst, 
bis er sich zum ISR Aufruf bequemt, bis du in der ISR die Kontrolle 
kriegst ... da vergeht alles Zeit. Zeit in der der Timer in der 
Zwischenzeit weitergezählt hat. Zähltakte die du aber nirgends 
berücksichtigt. Wenn man eine Timer-ISR braucht, die abweichend von der 
Breite des Timers (8Bit oder 16 Bit) aufgerufen wird, dann nimmt man den 
CTC-Modus des Timers dafür.

von Jürgen (Gast)


Lesenswert?

Danke, CTC-Modus, interessant. Wir in der Schule haben immer nur den 
einen Timer verwendet. CTC-Modus werde ich mir morgen mal anschauen.

Fühle mich bei euch gut aufgehoben.

Gute Nacht und nochmals Danke.

von Karl H. (kbuchegg)


Lesenswert?

Jürgen schrieb:
> Danke, CTC-Modus, interessant. Wir in der Schule haben immer nur den
> einen Timer verwendet. CTC-Modus werde ich mir morgen mal anschauen.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Uhr

von Jürgen (Gast)


Lesenswert?

Hallo,

hab mich jetzt ein wennig reingelesen.
Jetzt funktioniert´s auch. Aber ich weis nicht warum. :-)
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "warten.h"
5
#include "var.h"
6
7
ISR(TIMER0_COMP_vect)
8
{
9
    timer ++;
10
}
11
12
//Hauptprogram
13
14
int main(void)
15
{
16
  //Ein - Ausgänge Definieren
17
18
  DDRC  = 0xff;    //PORTC Ausgang (LEDs)
19
  PORTA = 0xff;    //PORTA Pullup aktivieren (Taster)
20
21
  DDRD  = 0xff;    //PORTD (Display Daten) auf Ausgang setzten
22
  DDRB  =  0x07; // Asugänge schalten für Display RS/RW/E
23
24
25
  // Timer 0 konfigurieren
26
27
  //Prescalerkonfiguration
28
    TCCR0 &= ~(1<<CS02)|(1<<CS01);  // Kein Prescaler 
29
    TCCR0 |= (1<<CS00);        //    "
30
  
31
  //CTC Modus aktivieren
32
  TCCR0 &= ~(1<<WGM00);
33
  TCCR0 |= (1<<WGM01);
34
35
  //Output Compare Interrupt erlauben
36
  TIMSK |= (1<<OCIE0);
37
  
38
  /*Output Compare Register vorladen mit 40
39
    Interrupt Aktion alle (4000000/40 = 1000.000Hz = 10µs
40
    ausführen
41
  */
42
  OCR0 = 0x19;
43
  
44
  //Interupt starten
45
  sei();
46
47
48
49
  while(1)
50
  {
51
      LED = 0x00;
52
      wartems(250);
53
      wartems(250);
54
      wartems(250);
55
      wartems(250);
56
      LED = 0xff;
57
      wartems(250);
58
      wartems(250);
59
      wartems(250);
60
      wartems(250);
61
  }
62
63
}


Durch rumprobieren habe ich herausgefunden das ich das Register OCR0 mit 
HEX 19 also DEZ 25 beschreiben muss um auf die z.B. 1s zu kommen.
Dass würde aber nicht meiner Rechnung entsprechen die folgendermaßen 
aussieht: 4.000.000/40 = 100.000 Hz = 10µs.

Mit HEX 19 sieht es aber so aus: 4.000.000/25 = 160.000 Hz = 6,25µs.

Wie kommt das?

Außerdem habe ich nicht ganz verstanden wo der Unterschied zwischen den 
beiden Modusen ist. Ich muss doch beide Vorladen.

Auch das simulieren funktioniert nicht. Es kommt immer noch die 
Meldung:"Location not valid"

Wo mache ich Fehler?

von Karl H. (kbuchegg)


Lesenswert?

25 Takte von einem Interrupt zum nächsten ist immer noch sehr eng.
Lass doch dem µC etwas Zeit!

Deine 4Mhz, wo kommen die her?
interner Oszillator, Quarz?

> Außerdem habe ich nicht ganz verstanden wo der Unterschied zwischen
> den beiden Modusen ist. Ich muss doch beide Vorladen.

Im CTC lädst du in der ISR den Timer nicht vor.
Der Timer zählt von sich aus nur bis zu einer bestimmten Zahl


> Es kommt immer noch die
> Meldung:"Location not valid"

Du hast den Optimizer eingeschaltet und der Optimizer hat die Variable 
rausgeworfen, weil er sie nicht braucht.

von Jürgen (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Lass doch dem µC etwas Zeit!

Am Anfang wollte ich eine Routine schreiben um eine Funktion zu haben 
Portionsweise 1 µs hochzuzählen.
Jetzt muss ich die Portionen schon erhöhen um 10. Das muss dem doch 
reichen!! :-)

Aber im ernst, wie kann ichs besser machen. Und komm mir ja nicht mit 
_delay ... . ;-) Genau das möchte ich umgehen. Ich habe gelesen, sobald 
ein Interrupt dazwischen kommt, stimmt die Zeit nicht mehr. Deshalb 
wollte ich was eigenes machen.
Und da ich die Timer sowieso besser kennen lernen wollte habe ich es als 
Übung versucht.

Karl heinz Buchegger schrieb:
> Deine 4Mhz, wo kommen die her?
> interner Oszillator, Quarz?

externem Quarz.

Karl heinz Buchegger schrieb:
> Im CTC lädst du in der ISR den Timer nicht vor.
> Der Timer zählt von sich aus nur bis zu einer bestimmten Zahl

Verstanden. Danke.

von Karl H. (kbuchegg)


Lesenswert?

Jürgen schrieb:

> Jetzt muss ich die Portionen schon erhöhen um 10. Das muss dem doch
> reichen!! :-)

Wenn du im Büro sitzt und alle 15 Sekunden kommt wer rein und will was 
von dir, kriegst du auch deine eigentliche Arbeit nicht mehr auf die 
Reihe.

Beschränkst du aber den Zugang zu dir auf alle 5 Minuten, dann geht auch 
bei dir was weiter.

>> Deine 4Mhz, wo kommen die her?
>> interner Oszillator, Quarz?
>
> externem Quarz.

ok.
Das erklärt dann nicht den zeitlichen Versatz

>> Im CTC lädst du in der ISR den Timer nicht vor.
>> Der Timer zählt von sich aus nur bis zu einer bestimmten Zahl
>
> Verstanden. Danke.

Der springende Punkt ist:
Der Timer zählt von sich aus exakt die angegebene Anzahl an Takten ab. 
Beim vorladen hast du immer einen Versatz drinnen, durch Dinge die du 
nicht beeinflussen kannst.

von Jürgen (Gast)


Lesenswert?

Das heist ich muss mir die 10µs abschmincken?

von Karl H. (kbuchegg)


Lesenswert?

Jürgen schrieb:

> Aber im ernst, wie kann ichs besser machen. Und komm mir ja nicht mit
> _delay ... . ;-) Genau das möchte ich umgehen.

Das kann man so pauschal nicht sagen.
Das hängt natürlich auch immer von der Taktfrequenz ab.
Bis zu einer gewissen Grenze sind _delay... schon in Ordnung. Vor allen 
Dingen, weil du das auch mit einem Timer nicht genauer hinkriegst, ganz 
im Gegenteil.

> Ich habe gelesen, sobald
> ein Interrupt dazwischen kommt, stimmt die Zeit nicht mehr.

Vor den _delay.. einfach die Interrupts deaktivieren und danach wieder 
einschalten.


Ich würde mal aus dem Bauch heraus sagen:
Bis zu ~500µs sind _delay... durchaus verschmerzbar, wenn es nicht im 
Programm andere Gründe gibt, warum man auf keinen fall warten möchte.

Denn: Auch ein Timer ist kein Allheilmittel. Vor allen bei kleinen 
Zeiten wirds mit einem Timer schin knifflig.

von Jürgen (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Vor allen bei kleinen
> Zeiten wirds mit einem Timer schin knifflig.

Das habe ich jetzt auch gemerkt.

Okay, habs jetzt soweit verstanden.

Herzlichen Dank für deine Mühe.

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.