CTC Timer - immer 2s zuviel

OP (Firma: FHNW) #3254619
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.
#3254634
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.
OP (Firma: FHNW) #3254643
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?!
Gast #3254658
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
OP (Firma: FHNW) #3254669
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
}
#3254711
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.
#3254726
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.
Moderator (Firma: Titel) Persönliche Seite #3254728
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?
OP (Firma: FHNW) #3254743
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
  }
#3254760
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.
OP (Firma: FHNW) #3254773
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
  }

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren