Forum: Mikrocontroller und Digitale Elektronik Software-Timer abweichung


von Wiz (Gast)


Lesenswert?

Hallo,

wollte eine konstante Zeit vom Timer-Interrupt ableiten, nur stimmt 
irgendwie meine errechnete Zeit mit der realen Zeit nicht überein. Zum 
Ablauf der Timerinterrupt wird alle 4,096 ms aufgerufen dort wird eine 
Variable hochgezählt bis die Zeit von 200,704 ms erreicht wurden.

Dann wird eine globale Variable auf 60000 (soll 1 Min entsprechen) 
initialisiert die dann dekrementiert wird und die LED toggelt von grün 
auf rot.

Tatsächlich wird die LED aber nach 6 sekunden auf rot geschaltet und 
nicht nach 1 min wie ursprüglich berechnet.

Woran kann es liegen?

Über eine Info würde ich mich freuen.


1
void init_timer2 (void)
2
{
3
  TCC1.PER = 2; //Timer top value (overflow at 4µs)
4
  TCC1.CTRLB = TC_TC1_WGMODE_NORMAL_gc; // Mode: Normal mode
5
  TCC1.CTRLA = TC_TC0_CLKSEL_DIV1_gc; // Prescaler 1
6
  TCC1.INTCTRLA = TC_TC1_OVFINTLVL_LO_gc; //Interrupt modus active priority low
7
}
8
9
10
void interrupt_init (void)
11
{
12
  PMIC.CTRL |= PMIC_LOLVLEN_bm; //Interrupt on
13
  sei(); //Interrupt enable
14
}
15
16
s_IO.ulLaufzeit = 60000; 
17
18
int main (void)
19
{  
20
  PORTB.DIRSET = PIN2_bm;  
21
  PORTB.DIRSET = PIN3_bm;
22
  PORTB.OUTSET = PIN3_bm;
23
    
24
  
25
  
26
  
27
  
28
  while (1)
29
  {    
30
    if (s_IO.ulLaufzeit == 0)
31
    {
32
      
33
      PORTB.OUTSET = PIN2_bm;
34
      PORTB.DIRCLR = PIN3_bm;
35
    }    
36
  }  
37
}
38
39
40
ISR(TCC1_OVF_vect)
41
{  
42
  static unsigned char ucMsTimer = 0;  
43
  
44
  
45
  if ( ucMsTimer >= 49 ) //51
46
  {
47
    ucMsTimer = 0;
48
  }
49
  else
50
  {
51
    ucMsTimer++;
52
  }
53
  
54
  if ( ucMsTimer == 0 )
55
  {
56
    if (s_IO.ulLaufzeit > 0)
57
    {
58
      s_IO.ulLaufzeit--;
59
    }
60
  }
61
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wiz schrieb:
> s_IO.ulLaufzeit

Wie ist das deklariert? Volatile?

Takt richtig gesetzt? Auch die sogenannten "Fuses"?

von Wiz (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Takt richtig gesetzt? Auch die sogenannten "Fuses"?

ist ein ATxmega256A3BU dort wird der clock software mäßig eingestellt 
nicht über fuses wie beim mega...


läuft mit 32 Mhz
1
void clock_init (void)
2
{
3
  OSC.CTRL = OSC_RC32MEN_bm; //oscillator at 32 MHz
4
  while(!(OSC.STATUS & OSC_RC32MRDY_bm)); //wait for oscillator ready
5
  CCP = CCP_IOREG_gc; //protect I/O register, interrupts are ignored
6
  CLK.CTRL = CLK_SCLKSEL_RC32M_gc; //activate internal oscillator
7
}

Rufus Τ. F. schrieb:
> Wie ist das deklariert? Volatile?

ist eine Variable ausm struct

T_IO s_IO;



muss es unbedigt volatile sein ich veränder die Variable ja nicht 
außerhalb der ISR ?

von Stefan E. (sternst)


Lesenswert?

Wiz schrieb:
> Ablauf der Timerinterrupt wird alle 4,096 ms aufgerufen

Im Kommentar steht aber 4µS?

Wiz schrieb:
> Variable hochgezählt bis die Zeit von 200,704 ms erreicht wurden.
>
> Dann wird eine globale Variable auf 60000 (soll 1 Min entsprechen)
> initialisiert die dann dekrementiert wird

200ms * 60000 = 1 Min?
Merkwürdige Rechnung.

von Wiz (Gast)


Lesenswert?

Stefan E. schrieb:
> Im Kommentar steht aber 4µS?

stimmt kommentar ist falsch

Stefan E. schrieb:
> 200ms * 60000 = 1 Min?
> Merkwürdige Rechnung.

200ms * 5 = 1000 ms (1s)

1s *60 = 1 min

müsste also 300 sein.


Habe ich gerade ausprobiert aber dann leuchtet die rote LED sofort 
auf...

hmm was könnte es sonst sein?

von Stefan E. (sternst)


Lesenswert?

Wiz schrieb:
> Stefan E. schrieb:
>> Im Kommentar steht aber 4µS?
>
> stimmt kommentar ist falsch

4ms ist es offenkundig ja aber auch nicht.

Wiz schrieb:
> Tatsächlich wird die LED aber nach 6 sekunden auf rot geschaltet

Das über die Software-Zähler zurückgerechnet würde 20µs pro Interrupt 
bedeuten.

Für dich gilt es jetzt erst mal zu klären, mit welchem Takt der Zähler 
läuft, und mit welchem Abstand der Interrupt nun tatsächlich kommt.

von Wiz (Gast)


Lesenswert?

Stefan E. schrieb:
> Das über die Software-Zähler zurückgerechnet würde 20µs pro Interrupt
> bedeuten.
>
> Für dich gilt es jetzt erst mal zu klären, mit welchem Takt der Zähler
> läuft, und mit welchem Abstand der Interrupt nun tatsächlich kommt.

wenn ich mir sysclock aufm pin ausgeben lasse dann messe ich mit dem 
oszi 32 Mhz als passt das schon mal der Timer hat den Prescaler 1 und 
der Top Wert ist 2 also läuft er mit 244 Hz... oder sehe ich das falsch?

von Stefan E. (sternst)


Lesenswert?

Und übrigens:

Wiz schrieb:
> muss es unbedigt volatile sein ich veränder die Variable ja nicht
> außerhalb der ISR ?

Ja, muss sie. Es spielt keine Rolle, wo sie verändert, und wo nur 
gelesen wird. Wenn sie sowohl in der ISR, wie auch außerhalb verwendet 
wird, muss sie volatile sein.
Ist aber nicht Ursache deines aktuellen Problems, denn dann würde sie 
nie, statt zu früh angehen.

Du hast aber auch ein Atomic-Problem, und das kann sehr wohl die Ursache 
sein.

von Stefan E. (sternst)


Lesenswert?

Wiz schrieb:
> wenn ich mir sysclock aufm pin ausgeben lasse dann messe ich mit dem
> oszi 32 Mhz als passt das schon mal der Timer hat den Prescaler 1 und
> der Top Wert ist 2 also läuft er mit 244 Hz...

Auch eine Rechnung, die du mir mal erklären musst.

von Wiz (Gast)


Lesenswert?

Stefan E. schrieb:
> Du hast aber auch ein Atomic-Problem, und das kann sehr wohl die Ursache
> sein.

was meinst du mit 'Atomic-Problem' genau?

Stefan E. schrieb:
> Auch eine Rechnung, die du mir mal erklären musst.

laut http://eleccelerator.com/avr-timer-calculator/ oder muss man es 
anders berechnen bei den xmegas?

von Stefan E. (sternst)


Lesenswert?

Wiz schrieb:
> was meinst du mit 'Atomic-Problem' genau?

Jeder Zugriff auf s_IO.ulLaufzeit außerhalb der ISR muss atomar sein.

Wiz schrieb:
> laut http://eleccelerator.com/avr-timer-calculator/

Kann ich nicht nachvollziehen. Was hast du denn da wo eingegeben, um auf 
diese 244Hz zu kommen?

von Wiz (Gast)


Angehängte Dateien:

Lesenswert?

Stefan E. schrieb:
> Jeder Zugriff auf s_IO.ulLaufzeit außerhalb der ISR muss atomar sein.

heißt es ich muss beim zugriff auf die Variable (auch beim 
Initialisieren und bei der If-Abfrage) die intterupts sperren??

Stefan E. schrieb:
> Kann ich nicht nachvollziehen. Was hast du denn da wo eingegeben, um auf
> diese 244Hz zu kommen?

siehe Anhang

von Stefan E. (sternst)


Lesenswert?

Wiz schrieb:
> heißt es ich muss beim zugriff auf die Variable (auch beim
> Initialisieren und bei der If-Abfrage) die intterupts sperren??

Bei der Initialisierung sind Interrupts noch nicht aktiv, aber 
ansonsten: ja.

Wiz schrieb:
> siehe Anhang

Wo kommt die Zahl für "Total Timer Ticks" her?
Wieso landet dein Timer-Top bei "Overflow Count"?

von Wiz (Gast)


Lesenswert?

Stefan E. schrieb:
> Wo kommt die Zahl für "Total Timer Ticks" her?
wurde automatisch eigetragen nachdem ich "Overflow count" eingegeben 
habe

> Wieso landet dein Timer-Top bei "Overflow Count"?

wie müsste es in meinem Fall lauten??? Stehe auf dem Schlau danke für 
die Hilfe

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Dein Timer muß 2x überlaufen und dann noch 0 Timer-Takte, damit Du auf 
Deine Zeiten kommst.

NICHT alle 2 Timer-Takte, sondern Überläufe (OVL).

Wobei dann die 6 Sekunden (statt 60 Sekunden) auch nicht hinkommen.
Die Total_Timer-Ticks sind die Timer-Durchläufe, bis die Zeit 
'abgearbeitet' ist - sind halt etwas mehr als 65536 (16 Bit), ziemlich 
genau sogar 2x so viel.

Trotzdem:
Etwas verworren, zur Zeit.

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.