Forum: Mikrocontroller und Digitale Elektronik Timer macht nicht das, was er soll?


von Jonathan K. (burgerohnealles)


Lesenswert?

Hallo,

ich wollte zuerst einen einfachen Timer programmieren, der jede Sekunde 
eine Variable auf 1 setzt. Dazu habe ich den 8-Bit Timer2 genommen, den 
Prescaler auf 1024 gesetzt und den Overflow Interrupt eingeschaltet. 
Jetzt sollte dieser Interrupt alle 1 / (16.000.000 / 1.024 / 256) = ca. 
61 Millisekunden ausgelöst werden. Dies geschieht aber bei mir nur ca. 
alle 3 bis 5 Millisekunden. Mein Code:

1
#define SET_BIT(x,y) x|=(1<<y)
2
#define CLR_BIT(x,y) x&=~(1<<y)
3
#define TGL_BIT(x,y) x^=(1<<y)
4
#define IS_BIT(x,y)  (x&(1<<y))
5
6
7
volatile int changed = 0;
8
9
10
void setup () {
11
  Serial.begin(9600);
12
  
13
  SET_BIT(TCCR2B, CS20);
14
  SET_BIT(TCCR2B, CS22);
15
  SET_BIT(TIMSK2, TOIE2);
16
}
17
18
void loop () {
19
  long t = millis();
20
  while(changed == 0);
21
  t = millis() - t;
22
  Serial.println(t);
23
  changed = 0;
24
}
25
26
ISR (TIMER2_OVF_vect) {
27
  changed = 1;
28
}

Was mache ich falsch?


Danke schon mal
burgerohnealles

von Thomas E. (thomase)


Lesenswert?

Jonathan K. schrieb:
> Jetzt sollte dieser Interrupt alle 1 / (16.000.000 / 1.024 / 256) = ca.
> 61 Millisekunden ausgelöst werden

Jonathan K. schrieb:
> SET_BIT(TCCR2B, CS20);
> SET_BIT(TCCR2B, CS22);

Dann stell deinen Prescaler auch auf 1024.

mfg.

von Electronics'nStuff (Gast)


Angehängte Dateien:

Lesenswert?

Nicht sonderlich gut gelesen, oder?

von Uwe (Gast)


Lesenswert?

1/16000000=62.5ns Pro Takt
Er braucht 1024*256 Takte a 62.5ns
Also 62.5ns*1024*256=16,384ms
Also alle ca. alle 16ms

von Jonathan K. (burgerohnealles)


Lesenswert?

Thomas Eckmann schrieb:
> Dann stell deinen Prescaler auch auf 1024.

Hab ich das nicht gemacht? Laut 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Zähler_des_AVR#8-Bit_Timer.2FCounter 
muss ich CS20 und CS22 setzen. Und das hab ich doch gemacht!? Wo ist 
mein Fehler?

von Jonathan K. (burgerohnealles)


Lesenswert?


von Walter S. (avatar)


Lesenswert?

Jonathan K. schrieb:
> Wo ist
> mein Fehler?

du verwendest timer2, dann musst du auch die Werte für timer2 nehmen

von Electronics'nStuff (Gast)


Lesenswert?

Vor allem schaut man diese Dinge im DB nach und nicht im Tutorial. Die 
Garantie, dass es kompatibel ist hast du nie zu 100%.

von Jonathan K. (burgerohnealles)


Lesenswert?

Walter S. schrieb:
> du verwendest timer2, dann musst du auch die Werte für timer2 nehmen

Ahh. Ok. Ich habe jetzt dieses Bit noch gesetzt, aber es funktioniert 
trotzdem noch nicht ganz. Nach meinem Programm wird der Interrupt ca. 
alle 32ms ausgelöst. Es müsste doch ca. alle 16ms sein. Wo ist jetzt der 
Fehler?

von Electronics'nStuff (Gast)


Lesenswert?

Naja, dann hast du offensichtlich die falsche Taktquelle.

von Karl H. (kbuchegg)


Lesenswert?

Jonathan K. schrieb:
> Warum steht da:
> http://www.mikrocontroller.net/attachment/173218/table.png was anderes
> als da:
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Zähler_des_AVR#8-Bit_Timer.2FCounter
> ?

Weil Atmel zig-verschiedene µC produziert mit jeweils unterschiedlicher 
Ausstattung an Timern.
Ein Tutorial zeigt immer die Dinge beispielsweise anhand eines 
spezifischen µC (und in diesem Fall anhand eines spezfischen Timers, den 
dieser im Tutorial benutzte µC besitzt).

Für dich ist das Tutorial ein Überblick, was die Timer so können und wie 
man sei konfiguriert. Aber deine Bibel, die einzig für dich relevante 
Dokumentation, ist das Datenblatt zu deinem Prozessor.

von Electronics'nStuff (Gast)


Lesenswert?

Electronics'nStuff schrieb:
> Naja, dann hast du offensichtlich die falsche Taktquelle.

EDIT: Ich tippe mal auf interne Taktquelle, 8MHz.

von Karl H. (kbuchegg)


Lesenswert?

Mach da mal
1
void loop () {
2
3
  while(changed == 0)
4
    ;
5
  changed = 0;
6
7
  long t = millis();
8
  while(changed == 0)
9
    ;
10
  t = millis() - t;
11
12
  Serial.println(t);
13
  changed = 0;
14
}

draus.
je nach Baudrate braucht auch der println seine Zeit. Wenn du da einen 
Timer-Interrupt verpasst, dann misst du die Zeit zwischen 2 Interrupts.

von Jonathan K. (burgerohnealles)


Lesenswert?

Electronics'nStuff schrieb:
> Electronics'nStuff schrieb:
>> Naja, dann hast du offensichtlich die falsche Taktquelle.
>
> EDIT: Ich tippe mal auf interne Taktquelle, 8MHz.

Hab mal die Fuses gecheckt: FF DE 05 -> Das heißt Ext. Crystal Osc.
Der Arduino läuft mit 16Mhz. Das heißt daran kann es schon mal nicht 
liegen.

Karl Heinz Buchegger schrieb:
> Mach da mal
> void loop () {
>
>   while(changed == 0)
>     ;
>   changed = 0;
>
>   long t = millis();
>   while(changed == 0)
>     ;
>   t = millis() - t;
>
>   Serial.println(t);
>   changed = 0;
> }
>
> draus.
> je nach Baudrate braucht auch der println seine Zeit. Wenn du da einen
> Timer-Interrupt verpasst, dann misst du die Zeit zwischen 2 Interrupts.

Das geht leider auch nicht. Der Arduino gibt immer noch 32 aus.

von Jonathan K. (burgerohnealles)


Lesenswert?

Hab jetzt nochmal ein bisschen herumprobiert. Ich dachte schon evtl. ist 
mein Arduino kaputt. Aber mit der Library "TimerOne" funktionierts 
perfekt. Der folgende Code sollte ca. alle 4 Sekunden die LED auf dem 
Arduino ein-/ausschalten (1 / (16.000.000Hz/1024/65536) = ca. 4,2s). 
Warum funktioniert der folgende Code nicht (die LED blink gar nicht)?
1
#define SET_BIT(x,y) x|=(1<<y)
2
3
void setup () {
4
  pinMode(13, OUTPUT);
5
6
  // prescaler: 1024
7
  SET_BIT(TCCR1B, CS12);
8
  SET_BIT(TCCR1B, CS11);
9
  SET_BIT(TCCR1B, CS10);
10
  
11
  // overflow interrupt enable
12
  SET_BIT(TIMSK1, TOIE1);
13
  
14
  // enable global interrupts
15
  sei();
16
}
17
18
ISR (TIMER1_OVF_vect) {
19
  digitalWrite(13, digitalRead(13)^1);
20
}
21
22
void loop () {
23
  // nothing
24
}

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.