Forum: Mikrocontroller und Digitale Elektronik Timer passt nicht zu Simulation, Timer nicht genau


von Carsten (Gast)


Lesenswert?

Hallo,

ich möchte für mein Programm auf einem Atmega168 mit 16 MHz Quarz ein 
vorgeschriebene Programmlaufzeit einrichten.
Dafür verwende ich einen 8-Bit Timer wie im Code s.u. zu sehen. Das 
Programm läuft in der Simulation genau so wie es sein soll, ein 
Programmdurchlauf dauert genau 0,1ms bzw. 1ms (je nach Divisor).

16.000.000/8 = 2.000.000 --> zähler bis 200 ergibt 0,1ms pro Durchlauf
bzw.
16.000.000/64 = 250.000 --> zähler bis 250 ergibt 1ms pro Durchlauf

Unglücklicherwiese ist die Programmlaufzeit auf dem Controller DEUTLICH 
größer! Woran kann das liegen?!? Hab ich bei dem Prescaler etwas falsch 
verstanden?!

Hier mein Code:

main.c:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <general.h>
4
5
int main(void) 
6
{
7
  sei();          //Globale Interrupts aktivieren
8
  initPorts();    //Funktionen der Ports definieren
9
  initTimer8(0);  //Timer starten
10
11
  int a = 0;
12
13
  while(1)
14
  {
15
  
16
    if(a==1000)            //nach 100ms
17
    {
18
      PORTB = 0x04;  //Leuchtdiode ein
19
    }
20
    
21
    if(a==2000)            //nach 100ms
22
    {
23
      PORTB = 0x00;  //Leuchtdiode aus
24
      a=0;
25
    }
26
27
    a++;
28
        
29
    while(isTimerRunning(0)==0){}
30
  }
31
  return 0;
32
}


und hier der Timer:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <general.h>
4
5
volatile BYTE gbTimerIrqFlag0=0;  //Globale Variable für Interrupt-Flag
6
volatile BYTE gbTimerIrqFlag2=0;  //Globale Variable für Interrupt-Flag
7
8
9
void initTimer8(BYTE bNr)     //Timer initialisieren, Übergabe Nummer des Timers bNr 
10
11
{
12
    switch(bNr)               //Ansprechen des gewählten Timers
13
          
14
    {
15
    case 0 :      //Timer 0,1ms
16
      
17
    TCCR0A=0x02;    //Output-Compare-Pin aus, kein PWM, Timer-Typ: CTC
18
    TCCR0B=0x02;  //Timer auf Taktrate 2 MHz setzen (Teiler auf 8)
19
    TCNT0=0x00;  //Zähler Register auf 0 setzen
20
    OCR0A=200-1;  //Vergeich des Timers mit vorgegebenen Wert: Laufzeit 0,1ms
21
    OCR0B=0x00;  //Compare-Register B wird nciht verwendet
22
    TIMSK0=0x02;  //OCR0A-Interrupt ein, Overflow- und OCR0B-Interrupt aus
23
24
    break;
25
26
    case 2 :      //Timer 1ms
27
      
28
    
29
    TCCR2A=0x02;  //Output-Compare-Pin aus, kein PWM, Timer-Typ: CTC
30
    TCCR2B=0x03;  //Timer auf Taktrate 250 kHz setzen (Teiler auf 64)
31
    TCNT2=0x00;  //Zähler Register auf 0 setzen
32
    OCR2A=250-1;  //Vergeich des Timers mit vorgegebenen Wert: Laufzeit 1ms
33
    OCR2B=0x00;  //Compare-Register B wird nciht verwendet
34
    TIMSK2=0x02;  //OCR2A-Interrupt ein, Overflow- und OCR2B-Interrupt aus
35
36
    break;
37
  }
38
39
}
40
41
42
43
BYTE isTimerRunning(BYTE bNr)  //Funktion zum Feststellen, ob vorgegebene Zeit abgelaufen 
44
{
45
  BYTE bReturn=0;
46
47
  switch(bNr)    //Ansprechen des gewählten Timers
48
  {
49
  
50
  case 0 :
51
    bReturn=gbTimerIrqFlag0;  //Solange die OCR-Flag nicht gesetzt ist bleibt die Rückgabe 0, anderenfalls wird sie 1
52
    gbTimerIrqFlag0=0;    //OCR-Flag zurücksetzen
53
54
    break;
55
  
56
  case 2 :
57
    bReturn=gbTimerIrqFlag2;  //Solange die OCR-Flag nicht gesetzt ist bleibt die Rückgabe 0, anderenfalls wird sie 1
58
    gbTimerIrqFlag2=0;    //OCR-Flag zurücksetzen
59
    break;
60
  
61
  }
62
63
  return bReturn;
64
65
}
66
67
68
69
ISR(TIMER0_COMPA_vect)          //Interrupt-Behandlung Timer 0
70
{    
71
72
  gbTimerIrqFlag0=1;  //OCR-Flag setzen, wenn Interrupt ausgelöst
73
74
}
75
76
ISR(TIMER2_COMPA_vect)          //Interrupt-Behandlung Timer 2
77
{    
78
79
  gbTimerIrqFlag2=1;  //OCR-Flag setzen, wenn Interrupt ausgelöst
80
81
}

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Carsten schrieb:
> Unglücklicherwiese ist die Programmlaufzeit auf dem Controller DEUTLICH
> größer!

Kannst du "DEUTLICH größer" in Zahlen ausdrücken?

> Woran kann das liegen?!?

Dein Controller läuft nicht mit den von dir angenommenen 16MHz.

Gruß,
Magnetus

von Carsten (Gast)


Lesenswert?

Grob gestoppt sind es ca. 1,7 statt der erwarteten 0,1 sekunden!!

Mit welcher geschwindigkeit läuft denn der Controller... bei dem 
verhältnis würde ich vermuten dass der nur auf 1 MHz läuft, aber warum 
?!

von ElektroMaus (Gast)


Lesenswert?

Die Standard-Taktquelle ist ein interner RC-Oszillator.

So lange du den Chip nicht so umkonfigurierst, dass er mit einer 
externen Taktquelle zusammenarbeitet, läuft der Chip mit den internen 
1MHz (Stichwort: Fuse-Bits, aber GRÜNDLICH lesen!)

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Carsten schrieb:
> Grob gestoppt sind es ca. 1,7 statt der erwarteten 0,1 sekunden!!

Das wäre dann Faktor 17.

> Mit welcher geschwindigkeit läuft denn der Controller... bei dem
> verhältnis würde ich vermuten dass der nur auf 1 MHz läuft,

Richtig

> aber warum?!

Siehe Beitrag von ElektoMaus.

Gruß,
Magnetus

von Carsten (Gast)


Lesenswert?

17 wäre es bei einer genauen Messung, aber 16 wird ja vermutlich eher 
passen, da die controller vermutlich nicht auf 941.176 Hz laufen.

Mit den Fuse Bits ist das beim AVR-Studio ja recht komfortabel 
gestaltet, dort kann man ja einfach den externen Quarz wählen... nun ist 
aber die Frage, welchen ich denn nehme, für einen 16MHz Quarz, es gibt 
dor ja viele zur auswahl!
Klar ist natürlich einer mit 8-...MHz, alle anderen sind langsamer, aber 
was hat es mit dem "Reset" auf sich... leider kann man die unteren 
auswahlmöglichkeiten im AVR-Studio nicht mehr ganz lesen!

Wenn mir das eben jemand sagen könnte, wäre super!

Ja, ich weiß, ich kann jetzt auch 3 Stunden danach googlen und finde es 
evtl. dann auch...

von Carsten (Gast)


Lesenswert?

hmm, mit dem
"Ext. Crystal Osc.; Frequency 8.0-   MHz; Start-up time PWRDWN/RESET: 
16K CK/14CK + 65 ms; [CKSEL=1111 SUT=11]"

funktioniert es jedenfalls, allerdings komme ich jetzt auf 0,7s statt 
0,1s... was passt denn da nicht ?!?!

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Carsten schrieb:
> funktioniert es jedenfalls, allerdings komme ich jetzt auf 0,7s statt
>
> 0,1s... was passt denn da nicht ?!?!

CKDIV8 Fuse.

von Carsten (Gast)


Lesenswert?

CKDIV8 Fuse ist gestzt, also im AVR-Studio ein Haken dran... soll das 
ding gesetzt sein, oder nicht ?!

von Carsten (Gast)


Lesenswert?

Aha, alles klar, wird geteilt durch 8... soll natürlch nicht!!

jetzt funktionierts... naja, besser... nun zeigt er nach 1minute nur 46 
sekunden an!

Aber trotzdem schonla danke!!

Noch ne idee, wo diese restabweichung herkommen könnte?!

von Remote O. (remote1)


Lesenswert?


von Magnus M. (magnetus) Benutzerseite


Lesenswert?

By the way:
1
int main(void) 
2
{
3
  sei();          //Globale Interrupts aktivieren
4
  initPorts();    //Funktionen der Ports definieren
5
  initTimer8(0);  //Timer starten

Das sei(); solltest du lieber hinter die Initialisierung setzen.

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.