Forum: Mikrocontroller und Digitale Elektronik Timer mal wieder - Hilfesuchend bei Überlaufberechnung


von Peter S. (petershaw)


Lesenswert?

Hi,

ich habe auf einem ATTiny2313 Board ein 20Mhz Tackt. Nun möchte ich eine 
exakte Sekunde mit Timer0 berechnen.

Nehme ich die Formel aus dem Tutorial, ergeben sich für

    sec = ((2 ^8) * 64) / 20000000;

Überläufe in der Sekunde. Will ich nun wissen wie viele das in der 
Sekunde sind, dann teile ich 1(sec) / die Überläufe.

So komme ich auf: 31250

Soweit so gut?

Nun stelle ich meinen Timer ein:

     // INIT TIMER
     // -----------------------------------------
     TCCR0A |= 1<<WGM01;
     // Timer 0, Prescaller /64; OVF-Interrupt
     TCCR0B |=  (0<<CS02) | (1<<CS01) | (1<<CS00);
     // Overflow Interrupt erlauben
     TIMSK |= (1<<OCIE0A);
     // Set MAX
     OCR0A |= 255;

und fange den interrupt:

ISR (TIMER0_COMPA_vect){
  tick++;
  if(tick == 31250){
      ++sekunde;
      tick = 0;
  }

  if(sekunde == 60){
    minute++;
    sekunde = 0;
  }
  if(minute == 60){
    stunde++;
    minute = 0;
  }
  if(stunde == 24){
    stunde = 0;
  }
}

Leider kommt es nicht zu einem Sekündlichen hochzählen. Meine 
Kontrolllampe bleibt an, sie sollte sekündlich blinken.

Kann mir jemand helfen?

: Verschoben durch Moderator
von A. S. (Gast)


Lesenswert?

Ich kenne Deinen µC nicht. Aber bei Vorteiler 64 und Zähler bis 256 
erwarte ich bei 20Mhz etwa 20.000.000/(256*64)=1220 Überläufe pro 
Sekunde. Je nach Architektur ggf. davon noch die Hälft oder ein Viertel.

Wenn es 31.000 pro Sekunde wären (30µs pro Interrupt), solltest Du dich 
fragen, ob es nicht viel zu viele Interrupts wären.

Zudem kannst Du probehalber einfach mal kleinere Werte nehmen (binäre 
oder logarithmische Suche. Also statt 31.000: 1000, danach 100 (10, 1) 
wenn immer noch statisch an, sonst halt mehr.

Viel Erfolg

von Wolfgang (Gast)


Lesenswert?

Peter S. schrieb:
> Meine Kontrolllampe bleibt an, sie sollte sekündlich blinken.

Deine Kontrolllampe wird auch nirgends im gezeigten Programm 
angesprochen. Warum sollte sie also ihren Zustand verändert - und wie 
soll dir hier jemand einen Tip geben, wenn keiner weiss, wie deine 
Kontrolllampe hard- und softwaremäßig mit deinem Programm zusammen 
hängt. Bist du dir sicher, dass dein µC überhaupt in die ISR rein 
springt?

von Peter (Gast)


Lesenswert?

Hi,
Ja, mit anderen (Phantasie-)werten aus einem anderen Projekt klappt es, 
nur brauche ich hier exakte Sekunden.

von Peter S. (petershaw)


Lesenswert?

Also dieser Code lässt so halbwegs im Sekunden-Takt an und ab schalten:


    TCCR0A |= 1<<WGM01;
    // Timer 0, Prescaller /1024; OVF-Interrupt
    TCCR0B |=  (1<<CS02) | (0<<CS01) | (1<<CS00);
    // Overflow Interrupt erlauben
    TIMSK |= (1<<OCIE0A);
    // Set MAX
    OCR0A |= 19 -1;

mit dem ISR:

ISR (TIMER0_COMPA_vect){
  millisekunden++;
  if(millisekunden == 1000)
  {
    sekunde++;
    millisekunden = 0;
    if(sekunde == 60)
    {
      minute++;
      sekunde = 0;
    }
    if(minute == 60)
    {
      stunde++;
      minute = 0;
    }
    if(stunde == 24)
    {
      stunde = 0;
    }
  }
}


aber wie ist denn die Formel, damit ich den so optimieren kann, dass ich 
genau auf einer Sekunde bin?

: Bearbeitet durch User
von Peter S. (petershaw)


Lesenswert?

Ok, mit dem script kann ich mich nähern


    #!/usr/bin/perl

    $freq = 20000000;        # 20mhz
    $prescaler = 256;

    $countto = 255;          # overflow ISR
    for($i=$countto;$i>0;$i--){
  $ov = $freq / $prescaler;
  $every = ($ov / $i) / 1000;
  print "$every x/sec, $i\n";
    }

jetzt muss ich da nur noch die nächste 1 finden.
Aber irgendwie muss ich das doch auch ausrechnen können, oder? bzw 
jemand hier wird wissen, was die beste Einstellung ist ;)

Danke,
ps

von gfxjbv (Gast)


Lesenswert?

Die genaue Sekunde von P.Danneger, sozusagen DAS Standardwerk zum Thema:

Beitrag "Die genaue Sekunde / RTC"

gfxjbv

von Uwe S. (de0508)


Lesenswert?

Hallo Peter,

ich würde es etwas anders machen:
F_CPU = 20 *10^6
T0_MODE = 2 ' CTC Mode
T0_PRESCALER = 64
T0_PRELOAD = 250

T0_FREQUENCY = F_CPU /T0_PRESCALER /T0_PRELOAD
T0_FREQUENCY = = 20 *10^6 /64 /250 = 1250Hz

D.h. in Deiner ISR musst Du nun nur noch bis 1250 Zählen, um 1Hz zu 
erhalten.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Uwe S. schrieb:
> Hallo Peter,
>
> ich würde es etwas anders machen:
> F_CPU = 20 *10^6
> T0_MODE = 2 ' CTC Mode
> T0_PRESCALER = 64
> T0_PRELOAD = 250
>
> T0_FREQUENCY = F_CPU /T0_PRESCALER /T0_PRELOAD
> T0_FREQUENCY = = 20 *10^6 /64 /250 = 1250Hz
>
> D.h. in Deiner ISR musst Du nun nur noch bis 1250 Zählen, um 1Hz zu
> erhalten.

Es ginge auch Prescaler 256 und Preload 125, dann müsste man bloss noch 
bis 625 zählen und die Interrupts würden nur halb so häufig auftreten.


Um mal darzustellen, wie man zu solchen Lösungen kommt: Das Zauberwort 
ist Primfaktorzerlegung.

20.000.000 = 2^8 * 5^7

Es spielen für die konkrete Aufgabe also nur Zahlen eine Rolle, die sich 
entweder als Potenz von 2 oder als Potenz von 5 oder als Produkt solcher 
Potenzen darstellen lassen. Die ganze Denkleistung besteht nun nur noch 
darin, diese Zahlen möglichst geschickt über die Teilerstufen zu 
verteilen und dabei deren jeweiligen Limitierungen einzuhalten. Deine 
Lösung wäre also:

(2^6) * (2^1 * 5^3) * (2^1 * 5^4)

und meine

(2^8) * (5^3) * (5^4)

In beiden Fällen finden sich alle Primfaktoren der ursprünglichen 
Zerlegung in genau der richtigen Menge wieder und es tauchen keine 
anderen auf. -> eine exakte Lösung für das Teilerproblem ist gefunden.

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.