Forum: Compiler & IDEs Limit für Zeitmessung Abfrangen


von Hal S. (hal9000de)


Lesenswert?

Hallo,
ich komme einfach nicht weiter. Gerade Probiere ich mit dem ATmega128 
eine Zeitmessung. Über PC5 starte ich mit einer steigenden Flanke ein 
Ereignis (t0) in einer externen Schaltung. Zeitversetzt bekomme ich eine 
über PD2 (INT2) eine steigende Flanke zurück, welche meine 'Stopzeit' 
(t) sein soll. Allerdings möchte ich nicht ewig auf das Signal an PD2 
warten, sondern ein limit von 35ms setzen.

Versucht habe ich es so:

#define CNT_WAIT    0
#define CNT_MEASURED    1
#define CNT_OVERFLOW    2

volatile uint8_t cnt_state = CNT_WAIT;
volatile uint16_t cnt_value = 0x0;

ISR(TIMER1_COMPA_vect)
{
  if(cnt_state==CNT_WAIT)
    cnt_state = CNT_OVERFLOW;
}

ISR(INT2_vect)
{
  cnt_value = TCNT1;
  EIMSK &= ~(1<<INT2);    // INT2 disable

  if(cnt_state==CNT_WAIT)
    cnt_state = CNT_MEASURED;

}


int main(void)
{
        ...

        EICRA |= (1<<ISC21)|(1<<ISC20);  // INT2 rising edge

        ...


  // Timer1 initalisieren
  TCCR1A = 0;          // CTC Mode,
  TCCR1B = (1<<WGM12)|(1<<CS11);      // clk/8  542.535 ns
  OCR1A =  64511;          // CompareA 35ms
  TIMSK |= (1<<OCIE1A);        // Output CompareA Enable

  EIMSK |= (1<<INT2);               // INT2 enable

  cnt_state = CNT_WAIT;
  TCNT1 = 0;          // Counter1 reset
  PORTC |= (1<<PC5);
  while(cnt_state==CNT_WAIT);      // Auf 10%-Triggersignal oder 
CompareA warten

        ...


}


Der INT2_vect wird definitiv ausgelöst. Allerdings steht dann cnt_state 
bereits auf CNT_OVERFLOW. Also wird TIMER1_COMPA_vect bereits vorher 
ausgelöst obwohl INT2_vect innerhalb der 35ms erfolgt. Wo ist mein 
Gedankenfehler?

von Ralf (Gast)


Lesenswert?

Hal Smith schrieb:
> TIMSK |= (1<<OCIE1A);        // Output CompareA Enable

Hal Smith schrieb:
> cnt_state = CNT_WAIT;

Hal Smith schrieb:
> if(cnt_state==CNT_WAIT)
>     cnt_state = CNT_OVERFLOW;
= Reihenfolge der Abarbeitung noch vor while()

Hal Smith schrieb:
> Allerdings möchte ich nicht ewig auf das Signal an PD2
> warten, sondern ein limit von 35ms setzen.
Müsste diese Zeitmessung nicht erst in ISR_INT2 gestartet werden?

von Hal S. (hal9000de)


Lesenswert?

Ralf schrieb:
> Hal Smith schrieb:
>> TIMSK |= (1<<OCIE1A);        // Output CompareA Enable
>
> Hal Smith schrieb:
>> cnt_state = CNT_WAIT;
>
> Hal Smith schrieb:
>> if(cnt_state==CNT_WAIT)
>>     cnt_state = CNT_OVERFLOW;
> = Reihenfolge der Abarbeitung noch vor while()
>

Verstehe ich jetzt nicht. Ich nehme an, dass der TIMER1_COMPA_vect erst 
ausgelöst wird wenn TCNT1==OCR1A erreicht?


Ralf schrieb:
> Hal Smith schrieb:
>> Allerdings möchte ich nicht ewig auf das Signal an PD2
>> warten, sondern ein limit von 35ms setzen.
> Müsste diese Zeitmessung nicht erst in ISR_INT2 gestartet werden?

Nein. Die Messung soll mit PORTC |= (1<<PC5) starten und mit einer 
steigenden Flanke an PD2 enden.

von Ralf (Gast)


Lesenswert?

Hal Smith schrieb:
> Verstehe ich jetzt nicht. Ich nehme an, dass der TIMER1_COMPA_vect erst
> ausgelöst wird wenn TCNT1==OCR1A erreicht?

Na klar, aber der fängt doch sofort an zu zählen. Und ~35ms nach dem 
Einschalten des µC ist der Stand erreicht. Ja okay, ein paar 
while-Schleifen macht er noch.

Hal Smith schrieb:
> Die Messung soll mit PORTC = (1<<PC5) starten und mit einer
> steigenden Flanke an PD2 enden.
... außer das ganze dauert länger als 35ms (wenn ich's richtig 
verstanden habe).

von Stefan E. (sternst)


Lesenswert?

Hal Smith schrieb:
> Wo ist mein Gedankenfehler?

Vermutlich in diesen drei Zeilen:
1
  TCCR1B = (1<<WGM12)|(1<<CS11);      // clk/8  542.535 ns
2
  OCR1A =  64511;          // CompareA 35ms
3
  TIMSK |= (1<<OCIE1A);        // Output CompareA Enable
Der Timer wird gestartet während OCR1A 0 ist, also gibt es sofort ein 
Compare-Event (vermutlich, bin mir nicht 100%ig sicher). Der 
entsprechende Interrupt ist zwar noch nicht eingeschaltet, aber das 
verhindert ja nicht, dass das entsprechende Flag gesetzt wird. Wenn die 
Interrupts dann eingeschaltet werden, lößt der Compare-Interrupt sofort 
aus (wegen des gesetzten Flags).

von Hal S. (hal9000de)


Lesenswert?

Stefan Ernst schrieb:
[/c]Der Timer wird gestartet während OCR1A 0 ist, also gibt es sofort
> ein Compare-Event (vermutlich, bin mir nicht 100%ig sicher).

Sollte doch eigentlich nichts ausmachen. Mit TCNT1 = 0 wird auch 
cnt_state auf CNT_WAIT gesetzt. Falls davor ein TIMER1_COMPA_vect 
aufgerufen sein sollte ist das damit unerheblich!?

  cnt_state = CNT_WAIT;
  TCNT1 = 0;
  IO_PORT |= (1<<IR_ENABLE);
  while(cnt_state==CNT_WAIT);

von Ralf (Gast)


Lesenswert?

Hal Smith schrieb:
> Sollte doch eigentlich nichts ausmachen. Mit TCNT1 = 0 wird auch
> cnt_state auf CNT_WAIT gesetzt. Falls davor ein TIMER1_COMPA_vect
> aufgerufen sein sollte ist das damit unerheblich!?
Beginnt die Zeitmessung über Interrupt nach dem Start des µC innerhalb 
von 35ms? Ich hoffe, ich habe keinen Denkfehler. So wie ich das sehe, 
gibts alle 35ms einen TIMER1_COMPA-Interrupt.

von Hal S. (hal9000de)


Lesenswert?

Hal Smith schrieb:
> Die Messung soll mit PORTC |= (1<<PC5) starten und mit einer
> steigenden Flanke an PD2 enden.

ok ... vielleicht ist es so verständlicher:
Die Messung soll mit dem Schalten von PC5 von Low auf High starten 
(PORTC |= (1<<PC5);) und bei einer steigenden Flanke an PD2 (INT2) 
enden. Die Messung soll aber nach 35ms beendet werden falls keine 
steigende Flanke an PD2 anliegt.

Ich weiß, dass das setzen des Counters auf 0 und das Schalten von PC5 
auf HIGH-Pegel nicht synchron erfolgen kann. Aber wenn dies nacheinander 
geschieht, sollte der Zeitversatz konstant sein und kann daher in der 
Auswertung berücksichtigt werden.

von Ralf (Gast)


Lesenswert?

Ah, jetzt hab' ich verstanden wie das alles gemeint war. Was sagt denn 
der Simulator? Wann wird der Timer1_IR ausgeführt?

von Hal S. (hal9000de)


Lesenswert?

Wie kann ich so etwas Zeitkritisches mit dem Simulator testen?

von Ralf (Gast)


Lesenswert?

Hal Smith schrieb:
> Wie kann ich so etwas Zeitkritisches mit dem Simulator testen?
Einfach mal starten. Und sehen, wo der Timer zulangt.

von Hal S. (hal9000de)


Lesenswert?

Danke für den Tip mit dem Interrupt Flag. Allerdings liegt es nicht am 
Timer sondern am INTF2 im EIFR Register.
Also vor dem das INT2-Bit in EIMSK auf 1 gesetz wird das INTF2-Bit im 
EIFR Register auf 0 setzen.

Danke! Wieder was gelernt ;-)

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.