Forum: Mikrocontroller und Digitale Elektronik interrupt und timer / catch richtig verstanden?


von int (Gast)


Lesenswert?

Hallo, was ich vorhabe: der Abstand zweier H/L-Flanken soll möglichst 
genau gemessen werden mit einem ATmega8. Ich hab mir das so 
zusammengelesen und frage ob es so korrekt ist:

1) ich verwende ICP1 (PinB.0) und schließe dort das zu messende Signal 
an.

2) ich lasse den Timer1 laufen, so schnell er kann (den passenden mode 
muss ich noch raussuchen) und erlaube interrupts allgemein so wie den 
input capture und den overflow-interupt

3) wenn Overflow auslöst, zähle ich eine ov-variable hoch, damit ich 
auch Signallängen messen kann, die länger als 65535 Takte sind.

4) wenn der Capture-Interrupt auslöst, lese ich den Zählerstand bei 
Auslösung und setze danach den Zähler und die ov-variable auf 0

Ist das so richtig? Und was passiert, wenn das Signal innerhalb der 
Overflow-ISR auftritt? verliere ich das dann? Oder bekomme ich einen 
verzögerten Wert?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

int schrieb:
> Und was passiert, wenn das Signal innerhalb der
> Overflow-ISR auftritt? verliere ich das dann? Oder bekomme ich einen
> verzögerten Wert?

Weder noch, denn die ICP Hardware läuft ja ohne Programmunterstützung in 
Hardware ab. Für mich klingt deine Vorgehensweise völlig richtig.

von int (Gast)


Lesenswert?

danke - ok also weil Hardware, werde ich keinen verzögerten Wert 
bekommen - das sit schonmal gut.

Aber wird die Capture-ISR auch ausgelöst werden, direkt nachdem die 
Overflow-ISR gelaufen ist (also falls der capture während der 
Overflow-isr passiert)? Oder muss ich per Programm nachschauen, ob das 
Capture-Interrupt-Flag gesetzt ist?

von Adam P. (adamap)


Lesenswert?

Hey,

der Atmega8 hat keine Verschachtelten Interrupts.
Erst wird der eine ausgeführt und nach dem Rücksprung der nächste, falls 
anstehend - siehe:

https://www.mikrocontroller.net/articles/Interrupt#Verschachtelte_Interrupts

von Peter D. (peda)


Lesenswert?

int schrieb:
> 4) wenn der Capture-Interrupt auslöst, lese ich den Zählerstand bei
> Auslösung und setze danach den Zähler und die ov-variable auf 0

Damit geht die Interruptlatenz mit ein, laß den Timer durchlaufen und 
bilde die Differenz.

Das Auslesen eines Timers mit Bereichserweiterung per Interrupt ist 
etwas tricky:
Beitrag "AVR Timer mit 32 Bit"

von int (Gast)


Lesenswert?

ist ja wirklich etwas tricky.. aber danke für's Beispiel, ich glaube bei 
mir wird es nicht ganz so kompliziert, insbesondere muss ich mir ja das 
overflow-bit nicht merken, wie in Deinem Beispiel, oder?

Also abgewandelte Vorgehensweise:

1) und 2) wie oben

3) wenn capture auslöst, lese ich die Variable "periode" (s.u.) und 
verwende sie als Messwert (außer beim ersten Mal). Dann lese + merke ich 
mir den Timer-Wert, ziehe vorigen Timer-Wert davon ab und speichere das 
Ergebnis in eine Variable "periode"

4) wenn Overflow auslöst, addiere ich 65536 zur Variable "periode"

Müsste doch klappen, oder?

von Jonas B. (jibi)


Lesenswert?

4) wenn Overflow auslöst, addiere ich 65536 zur Variable "periode"

shifte lieber, wenn der Compiler es nicht eh optimiert :D

von Lurchi (Gast)


Lesenswert?

Um das Problem mit dem fast gleichzeitig auftretendem Überlauf beim 
Timer und ICP event kommt man auch bei nur einer Periode nicht herum. 
Man muss also schon in der ISR zum ICP daraus achten ob das overflow 
interupt Flag gesetzt ist, und dann nach dem ICP wert unterscheiden ob 
der Overflow kurz vor ICP oder kurz danach kam. Nur wenn der Overflow 
kurz davor kam muss man den noch berücksichtigen.

von int (Gast)


Lesenswert?

Lurchi schrieb:
> Man muss also schon in der ISR zum ICP daraus achten ob das overflow
> interupt Flag gesetzt ist

Muss man das wirklich? Nehmen wir mal 3 Fälle an:

a) Overflow kommt einen Takt vor dem Signal
b) Overflow kommt mit dem Signal (gleichzeitig)
c) Overflow kommt einen Takt nach dem Signal

bei a) ist alles gut - es wird zuerst 65535 addiert und der gelesene 
Wert ist relativ klein.

bei c) habe ich in den capture-registern noch den Wert vor dem Overflow, 
relativ groß nahe am Überlauf - stimmt auch

bei b) kommt es darauf an, welcher Interrupt zuerst drankommt
b1) ICP zuerst = wie c), oder?
b2) OVL zuerst = wie a), oder?

Ich fürchte ich hab was übersehen..

von Peter D. (peda)


Lesenswert?

int schrieb:
> bei a) ist alles gut - es wird zuerst 65535 addiert und der gelesene
> Wert ist relativ klein.

Nö, nicht jeder Befehl ist einen Takt lang, z.B. RET = 4.
Ist nach Befehlsende ICP und OVF gesetzt, hat ICP Vorrang.

von int (Gast)


Lesenswert?

Peter D. schrieb:
> Das Auslesen eines Timers mit Bereichserweiterung per Interrupt ist
> etwas tricky:
> Beitrag "AVR Timer mit 32 Bit"

Ich habe jetzt Dein Beispiel gedanklich durchgearbeitet und auch ganz 
verstanden. Es ist aber anders als mein Anwendungsfall: Erstens will ich 
den Timerwert in der ISR lesen, zusätzliche Interrupts sind in dem 
Moment also ohnehin nicht möglich. UNd zweitens will ich nicht direkt 
den Timer lesen, sondern das ICR (Input Capture Register), das den 
Timer-wert zum Zeitpunkt der Auslösung beinhaltet (unabhängig von der 
ZEit für den Einsprung in den Interrupt..

ganz schöne Kopfnuss.. :-)

von c-hater (Gast)


Lesenswert?

int schrieb:

> Ich habe jetzt Dein Beispiel gedanklich durchgearbeitet und auch ganz
> verstanden.

Nein, das hast du nicht.

> Es ist aber anders als mein Anwendungsfall

Ja, aber das Problem besteht analog für deinen Anwendungsfall. Es sei 
denn, es ist gewährleistet, das zwei zu messende Flanken niemals 
weiter als den Timer-Zählumfang -1 auseinander liegen. Dann (und nur 
dann!) kann man auf das Gehampele mit dem Overflow komplett verzichten.

von c-hater (Gast)


Lesenswert?

c-hater schrieb:

> Ja, aber das Problem besteht analog für deinen Anwendungsfall. Es sei
> denn, es ist gewährleistet, das zwei zu messende Flanken *niemals*
> weiter als den Timer-Zählumfang -1 auseinander liegen.

Mist, da fehlt ein Wort. Es muß heissen: "den halben Timer-Zähl..."

von Axel S. (a-za-z0-9)


Lesenswert?

int schrieb:
> Peter D. schrieb:

>> Beitrag "AVR Timer mit 32 Bit"
>
> Ich habe jetzt Dein Beispiel gedanklich durchgearbeitet und auch ganz
> verstanden. Es ist aber anders als mein Anwendungsfall: Erstens will ich
> den Timerwert in der ISR lesen, zusätzliche Interrupts sind in dem
> Moment also ohnehin nicht möglich.

Falsch. Interrupts sind sehr wohl möglich. Im Sinne daß die Hardware die 
Bedingungen für einen Interrupt weiterhin prüft und im Fall des Falles 
das entsprechende Flag setzt. Was stimmt: die zugehörige ISR wird nicht 
sofort angesprungen. Diese Aktion wird so lange verzögert bis du aus der 
gerade abgearbeiteten ISR zurückkehrst.

> UNd zweitens will ich nicht direkt
> den Timer lesen, sondern das ICR (Input Capture Register), das den
> Timer-wert zum Zeitpunkt der Auslösung beinhaltet (unabhängig von der
> ZEit für den Einsprung in den Interrupt..

Das hast du nicht richtig überlegt. Natürlich liest du das ICR und nicht 
den Timer direkt. Aber es geht um die Variable, die die Überläufe zählt. 
Wenn der Überlauf und das Capture-Event gleichzeitig[1] auftreten, dann 
kann es passieren daß du einen Überlauf verpaßt. Dein Meßwert wäre 
dann um 65536 zu klein. Und deswegen mußt du in der Capture-ISR 
zusätzlich noch nach dem Überlauf-Interruptflag schauen und entscheiden 
ob dieser Fall vorliegt oder nicht.

[1] wie PeDa schon richtig sagte, muß das nicht exakt gleichzeitig sein. 
Ein AVR kann immer nur dann in eine ISR springen, wenn er gerade eine 
Instruktion fertig abgearbeitet hat. Instruktionen die länger als einen 
Takt brauchen erzeugen also ein Zeitfenster. Alle Interrupts die 
innerhalb dieses Zeitfensters passieren, sind für den µC zeitlich nicht 
mehr unterscheidbar.

von int (Gast)


Lesenswert?

ok ich sehe es ein. Ich werde also meine 2 ISR so aufbauen:

t1overflow:
  overflow-zähler erhöhen

t1Capture:
  ?ov-Flag gesetzt ?
      wenn ja - ist der gelesene ICR - Wert klein (höchstes Bit =0) ?
          wenn ja - overflow-Zähler erhöhen, overflow flag löschen
  Periodendauer = icr_neu - icr_alt plus (overflow-zähler * 10000hex)
  icr_alt = icr_neu
  overflow-zähler = 0

Bin gespannt :-)

von Wolfgang K. (donkracho)


Lesenswert?

Der Ansatz ist vollkommen richtig. Wirklich exakte Messungen kann man 
nur mit freilaufendem Timer machen.

Anzahl der Timer1 Takte zwischen 2 Input Captures mir 32 Bit Zähler 
messen. Bei 16 MHz Timer1 Takt reicht es also für ca. 268 Sekunden 
Intervalle. Wenn es in C sein darf kann es z. B. so aussehen:

wobei _BV(x) ist nichts anderes ist als altes Atmel define ein für 
(1<<x)

static int ovfl_cnt = 0;

// timer overflow interrupt vector
ISR(TIMER1_OVF_vect)
{
  ovfl_cnt++;
}

// input capture interrupt vector
ISR(TIMER1_CAPT_vect)
{
  static unsigned int last_icr = 0;

  // Capture is an external asynchronous event. Overflow and Capture may 
occur at the
  // same time, but we are already entering this ISR. Check for missed 
overflow first.
  if (ICR1H < 16 && (TIFR1 & _BV(TOV1)))
  {
    ovfl_cnt++;               // do what ISR(TIMER1_OVF_vect) should 
have done ;)
    TIFR1 = _BV(TOV1);        // clear overflow flag, because already 
handled here
  }

  // calculate total tick difference using overflows and last value
  unsigned long t = ((unsigned long) ovfl_cnt << 16) + ICR1 - last_icr;
  last_icr = ICR1;
  ovfl_cnt = 0;

  // ISR code ....
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Adam P. schrieb:
> der Atmega8 hat keine Verschachtelten Interrupts.

Das ist so nicht ganz richtig. Der AVR ist durchaus in der Lage, eine 
ISR zu unterbrechen, eine zweite zu bearbeiten und dann wieder in die 
erste ISR zurückzukehren.
Dazu ist es lediglich notwendig, in der unterbrechbaren ISR globale 
Interupts wieder zu erlauben durch löschen des I-Bits, welches 
normalerweise beim Eintritt in jede ISR gesetzt wird. Siehe dazu auch 
AppNote AVR1200.

In avr-gcc und avrlibc kann man das durch das Attribut 'ISR_NOBLOCK' für 
eine ISR ermöglichen.

Ob es sinnvoll ist, ist dabei eine andere Frage. ISR_NOBLOCK bietet sich 
für untergeordnete ISR an, die durch hochpriorisierte ISR unterbrochen 
werden müssen, sowas wie Soft PWM, software-serielle ISR oder USB Komms.

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.