Forum: Mikrocontroller und Digitale Elektronik CTC Timer - immer 2s zuviel


von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Hallo zusammen!

ich wollte alle z.b. 5 Sekunden eine Messung auslösen, dazu hab ich 
einen 16 bit Timer gebraucht, welcher jedoch ständig ca. 2 Sekunden 
daneben liegt, dass heisst, statt den gewünschten 5 Sekunden von Messung 
zu Messung wird eine erneute Messung erst nach 7 Sekunden durchgeführt.

Übersehe ich etwas??
1
void timer_init (void) {
2
  // initialize Timer1
3
  cli();          // disable global interrupts
4
  TCCR3A = 0;     // set entire TCCR1A register to 0
5
  TCCR3B = 0;     // same for TCCR1B
6
  
7
  // set compare match register to desired timer count:
8
  OCR3A = 15624;
9
  // turn on CTC mode:
10
  TCCR3B |= (1 << WGM12);
11
  // Set CS10 and CS12 bits for 1024 prescaler:
12
  TCCR3B |= (1 << CS10);
13
  TCCR3B |= (1 << CS12);
14
  // enable timer compare interrupt:
15
  TIMSK3 |= (1 << OCIE3A);
16
  sei();          // enable global interrupts
17
}
18
19
20
ISR(TIMER3_COMPA_vect)
21
{
22
  sec++;
23
  if (sec == 10)
24
  {
25
    sec=0;
26
    if (pos_messen == 1) {
27
      messen();
28
      return;
29
    }
30
  }
31
}

Ich verwende einen externen 16MHz Quarz und den ATMega25601.

von Uwe (Gast)


Lesenswert?

>  wird eine erneute Messung erst nach 7 Sekunden durchgeführt.
> Übersehe ich etwas??
Ja es müßten eigentlich 10 Sekunden sein wegen :
 if (sec == 10)

von Karl H. (kbuchegg)


Lesenswert?

ABgesehen von der 10 versus 5 Diskrepanz
1
  ....
2
3
      messen();
4
  ....

und in messen() spielt es sich dann ab, inklusive Übrtragung auf LCD 
und/oder UART. Oder wie?

Der Teil gehört in die Hauptschleife und nicht in die ISR.
Und ja, das kann dafür verantwortlich sein, dass dein Timing nicht 
stimmt. Schliesslich sind die Interrupts deaktiviert und wenn du mehr 
als 1 verpasst, dann summiert sich das.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Uwe schrieb:
> Ja es müßten eigentlich 10 Sekunden sein wegen :
>  if (sec == 10)

Mein Fehler, habe es auch mit 10 Sekunden versuecht, Resultat: 12 
Sekuneden!

Karl Heinz Buchegger schrieb:
> und in messen() spielt es sich dann ab, inklusive Übrtragung auf LCD
> und/oder UART. Oder wie?

genau, da werden die Sensoren eingelesen und das Resultat dargestellt.

Karl Heinz Buchegger schrieb:
> Der Teil gehört in die Hauptschleife und nicht in die ISR.

Ich denke du meinst über ne Abfrage der Flags? Ist aber dann nicht der 
Intervall der Auslösung unregelmässig?
Abgesehen davon, sollte doch der Timer direkt nach auslösen wieder 
zurückgesetzt werden und von neuem beginnen zu zählen?!

von Oliver (Gast)


Lesenswert?

1 Sekunde ist aber eine Ewigkeit, da kann man auch schon mal eine 
(LCD-)Ausgabe aus einer ISR heraus machen, ohne daß da gleich Interrupts 
verloren gehen.

Wenn die Funktion messen allerdings länger als eine Sekunde benötigt 
(warum auch immer), dann ist eine Messung pro Sekunde halt nicht drin, 
egal, von wo aus die Funktion aufgerufen wird.

Oliver

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Oliver schrieb:
> 1 Sekunde ist aber eine Ewigkeit, da kann man auch schon mal eine
> (LCD-)Ausgabe aus einer ISR heraus machen, ohne daß da gleich Interrupts
> verloren gehen.
>
> Wenn die Funktion messen allerdings länger als eine Sekunde benötigt
> (warum auch immer), dann ist eine Messung pro Sekunde halt nicht drin,
> egal, von wo aus die Funktion aufgerufen wird.
>
> Oliver

Alles klar! Es war wirklich der Messprozess (da über mehrere Messungen 
nacheinander gemittelt wird) habe nun eifach ein Flag gesetzt und in der 
Hauptschleife abgefragt und alles ist so wie es sein soll, danke euch 
allen!

hier noch der Code:
1
void timer_init (void) {
2
  // initialize Timer1
3
  cli();          // disable global interrupts
4
  TCCR3A = 0;     // set entire TCCR1A register to 0
5
  TCCR3B = 0;     // same for TCCR1B
6
  // set compare match register to desired timer count:
7
  OCR3A = 15624;
8
  // turn on CTC mode:
9
  TCCR3B |= (1 << WGM12);
10
  // Set CS10 and CS12 bits for 1024 prescaler:
11
  TCCR3B |= (1 << CS10);
12
  TCCR3B |= (1 << CS12);
13
  // enable timer compare interrupt:
14
  TIMSK3 |= (1 << OCIE3A);
15
  sei();          // enable global interrupts
16
}
17
18
19
ISR(TIMER3_COMPA_vect)
20
{
21
  sec++;
22
  if (sec == 10)
23
  {
24
    sec=0;
25
    pos_messen=1;
26
  }
27
}

von Oliver (Gast)


Lesenswert?

Rico H. schrieb:
Es war wirklich der Messprozess (da über mehrere Messungen
> nacheinander gemittelt wird)

Hm. In einer Sekunde auf einem 16MHz AVR lassen sich aber sehr viele 
Daten mitteln. Da sürfte dann noch einiges im argen liegen...

Oliver

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Oliver schrieb:
> Hm. In einer Sekunde auf einem 16MHz AVR lassen sich aber sehr viele
> Daten mitteln. Da sürfte dann noch einiges im argen liegen...

Es sind 13 Sensoren, welche je 16 Messungen durchführen, mitteln und 
ausgeben;)

von Falk B. (falk)


Lesenswert?

@ Rico H. (Firma: FHNW) (2she)

>Es sind 13 Sensoren, welche je 16 Messungen durchführen, mitteln und
>ausgeben;)

Was bislang auch mal länger als 1s dauern kann, wenn man den Ansatz so 
sieht. Das kann man prüfen, im Programm.

http://www.mikrocontroller.net/articles/Multitasking#Verbesserter_Ansatz_mit_Timer

Siehe auch Interrupt. Dennoch bleibt die Grundaussage. Solche Sachen 
gehören nicht in die ISR, einen 1s Timer wird man in den meisten Fällen 
so nicht machen, sondern eher einen 10ms Timer und dort eine Variable 
bis 100 hochzählen. Denn die meisten Programme brauchen einen deutlich 
schnelleren Grundtakt als 1s.

von Falk B. (falk)


Lesenswert?

Und in den Messungen sind garantiert viele lustige Delays und andere 
Sachen drin.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Falk Brunner schrieb:
> Solche Sachen
> gehören nicht in die ISR

welche Sachen? ich erhöhe ja jetzt nur noch die Variable sec um 1 und 
setze pos_messen auf 1?!

von Falk B. (falk)


Lesenswert?

@ Rico H. (Firma: FHNW) (2she)

>> Solche Sachen
>> gehören nicht in die ISR

>welche Sachen? ich erhöhe ja jetzt nur noch die Variable sec um 1 und
>setze pos_messen auf 1?!

Ich war zu langsam, ich meinte die Messung in der ISR. Deine jetztige 
Lösung ist OK.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Rico H. schrieb:
> Oliver schrieb:
>> Hm. In einer Sekunde auf einem 16MHz AVR lassen sich aber sehr viele
>> Daten mitteln.
> Es sind 13 Sensoren, welche je 16 Messungen durchführen, mitteln und
> ausgeben;)
[ironie]
Werden die jeweils 16 Messwerte dann pro Sensor wenigstens auch 
schnellstmöglich nacheinander gemacht, um einen Ausreisser nicht 
herauszumitteln?
[/ironie]

>> Da sürfte dann noch einiges im argen liegen...
Das mit den 16 Messungen pro Sensor deutet in der Tat darauf hin. W
@Oliver:
Warum musst du da 16 mal messen? Was bringt das?

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Lothar Miller schrieb:
> Warum musst du da 16 mal messen? Was bringt das?

Es handelt sich um Temperaturmessungen, welche sehr genau sein sollen.

neues Problem, eher ein einfaches aber im Moment Blick ich nicht mehr 
durch.

Ich möchte auf einen Tastendruck eine Messung starten und den Timer 
starten, sodass die 2ten Messungen 10 sec danach starten. Die Funktion 
wird mit dem Tastendruck ausgeführt was auch soweit funktioniert.

Resp. wie kann ich den CTC Timer reseten?!
1
void Sensoren ()
2
{
3
  timer_init();    //selbe Initialisierung wie oben
4
  pos_messen=0;
5
  messen();    //Erste Messung sofort starten
6
  timer_init();
7
  //TCNT3 = 0;    //Timer zurücksetzen???=> funktioniert nicht
8
  while (site == 1100)
9
  {
10
    //hier werden die Timerinterrupts die Messungen starten
11
    //Abfrage Flags
12
    flags();
13
  }

von Falk B. (falk)


Lesenswert?

@ Rico H. (Firma: FHNW) (2she)

>  //TCNT3 = 0;    //Timer zurücksetzen???=> funktioniert nicht

Doch.

von Karl H. (kbuchegg)


Lesenswert?

Rico H. schrieb:

> Ich möchte auf einen Tastendruck eine Messung starten und den Timer
> starten, sodass die 2ten Messungen 10 sec danach starten.

Also nicht mehr regelmässig, so wie bisher?


Ich mach das immer so:
Countdowntimer
1
volatile int8_t countdown = -1;
2
3
ISR(TIMER3_COMPA_vect)
4
{
5
  sec++;
6
  if (sec == 10)
7
  {
8
    sec=0;
9
    pos_messen=1;
10
  }
11
12
  if (countdown > 0)
13
    countdown--;
14
}
15
16
....
17
18
  while( 1 )
19
  {
20
21
    ....
22
23
    if( Tastendruck )
24
    {
25
      countdown = 10;
26
      messen();
27
    }
28
29
    if (countdown == 0)
30
    {
31
      messen();
32
      countdown = -1;
33
    }
34
35
    ....
36
  }
37
}


Vergiss den Quatsch
1
void Sensoren ()
2
{
3
  timer_init();    //selbe Initialisierung wie oben
4
  pos_messen=0;
5
  messen();    //Erste Messung sofort starten
6
  timer_init();

Dein Timer läuft durch. Immer! Der startet mit dem Einschalten der 
Stromversorgung und ab da läuft der. Dauernd. Ständig.
Arbeite mit den ISR Aufrufen und entsprechenden Zählvariablen, aber lass 
den Timer in Ruhe!
Du stellst ja deine Armbanduhr auch nicht dauernd ab bzw. den 
Sekundezeiger auf 0, nur weil du irgendwelche Zeiten abmessen willst.

Genau deshalb ist weiter oben auch gesagt worden, dass die meisten 
Programme einen Basistakt haben, der meistens etwas schneller als 1 
Sekunde ist. Irgendwas im Millisekundenbereich. Man setzt sich einen 
Timer auf, so dass zb jede 1 Millisekunde eine ISR aufgerufen wird. Und 
den Rest leitet man dann mit entsprechenden Zählern und Jobflags von 
diesen 1 Millisekunden her. Aber der Timer tickt durch. Ständig. Der 
Zeitfehler ist dann nicht größer als diese 1 Millisekunden, was 
angesichts diverser Ausgaben völlig ausreichend ist.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Rico H. schrieb:
> // turn on CTC mode:
>   TCCR3B |= (1 << WGM12);
>   // Set CS10 and CS12 bits for 1024 prescaler:
>   TCCR3B |= (1 << CS10);
>   TCCR3B |= (1 << CS12);

Ich Pfosten hab zwar die richtigen Register beschrieben, aber die 
falschen Bits gesetzt....

so funzt es jetzt! THX an alle!!
1
  timer_init();
2
  pos_messen=0;
3
  messen();
4
  TCNT3 = 0;    //Timer zurücksetzen
5
  while (site == 1100)
6
  {
7
    //Abfrage Flags
8
    flags();
9
  }

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.