Forum: Mikrocontroller und Digitale Elektronik millis() in Interrupt (Arduino)


von Seb (Gast)


Lesenswert?

Hallo,

ich habe hier schon des Öfteren still mitgelesen und hoffe, dass ihr mir 
helfen könnt.

Ich habe zwei Arduinos über I²C gekoppelt. Der Slave bekommt vom Master 
eine Zahl übermittelt und soll das entsprechende Unterprogramm ausführen 
und seine Ergenisse an den Master übermitteln.

Das Problem: Sobald ich über den Interrupt, also
1
void receiveEvent(int x) {
2
//Code
3
Unterprogramm();
4
//Code
5
}
in das Unterprogramm gehe, bleiben meine Millis stehen, also die Zahl 
erhöht sich innerhalb des Unterprogrammes nicht weiter. Dass Delays 
nicht funtkionieren ist klar, aber millis() und micros()?
1
void Unterprogramm(){
2
x = millis();
3
//Code
4
y = millis();
5
WieLangHatsGedauert = y-x;
6
//x und y haben den gleichen Wert, egal welche Zeit dazwischen liegt
Gibt es irgendeinen Workaround, eine Zeitmessung dort durchzuführen?

Vielen Dank!

Sebastian

von MaWin (Gast)


Lesenswert?

Seb schrieb:
> in das Unterprogramm gehe, bleiben meine Millis stehen, also die Zahl
> erhöht sich innerhalb des Unterprogrammes nicht weiter. Dass Delays
> nicht funtkionieren ist klar, aber millis() und micros()?

Natürlich nicht, die millis zählt ein Timer1 Overflow Interrupt,
und innerhalb einer Interrupt-Routine sind Interupts gesperrt.

Man kann sei() machen um sie wieder zu erlauben, aber ob man dann 
nochmal dran kommt, und wann dann der stack voll ist, ist unklar, hängt 
also von deinem Programmierkenntnissen ab, die wohl eher gering sind.

Eine Interrupt Bearbeitung sollte nie 1ms r länger dauern, sondern in 
Mikrosekunden abgeschlossne sein, damit der uC nicht steht.

Wenn man was längeres machen muss, sollte die Interrupt-Routine nur en 
volatile flag setzen, und die Programm Hauptschleife fragt das dann ab 
und macht weniheger zeitkritische Restbearbeitung.

Z.B. Interrupt legt nur das nächste Zeichen von seriellem Interface in 
Buffer ab damit der Empfangsbuffer nicht überläuft, die 
Programm-Hauptschleife bearbeitet dann das gesendete Kommando wenn es 
vollständig ist.

von Seb (Gast)


Lesenswert?

Okay, da hätte man drauf kommen können.

Danke!

von sid (Gast)


Lesenswert?

Aber was mit ICR1...?

Müsste nicht
1
volatile long x, y;
2
void Unterprogramm(){
3
y = ICR1;
4
}
5
x = y;
6
Unterprogramm();
7
WieLangHatsGedauert = y-x;
funktionieren?
und ja mit nem first/second flag kann man das auch im Unterprogramm 
selber machen, aber so ist leichter zu verstehen denke ich

von Stefan F. (Gast)


Lesenswert?

Die Funktion delayMicroseconds() vertrödelt Zeit, ohne Timer und 
Interrupts zu benutzen.

von S. R. (svenska)


Lesenswert?

Bedenke, dass auf den meisten Arduinos (allen mit AVR drin) ein 
"volatile long" nicht atomisch ist. Da muss um den Zugriff ein 
ATOMIC_BLOCK oder cli/sei rum.

von Peter D. (peda)


Lesenswert?

Seb schrieb:
> in das Unterprogramm gehe, bleiben meine Millis stehen, also die Zahl
> erhöht sich innerhalb des Unterprogrammes nicht weiter.

Das sollte auch so sein, denn ein Interrupt, der länger als 1ms dauert, 
ist ein schlechter Interrupt.
Ändere den Programmablauf so, daß im Interrupt nicht gewartet wird.

von MaWin (Gast)


Lesenswert?

sid schrieb:
> Aber was mit ICR1...?

Erst heisst er seb nun fragt sid, wer weiss wer nun wer ist.

Man kann einfach einen Hardwaretimer (z.B. 16 bit) passend 
initialisieren und dauernd laufen lassen, dann fragt man zu Beginn einer 
Routine den Timerstand ab, und zieht den ab vom Timerstand am Ende der 
Routine.

Ist halt nicht mehr Arduino-Dummenprogrammierung, die eignet sich eh 
nicht für zeitkritisches (schon weil die Millisekundeninterrupts von 
Timer0 ständig reinhauen).

von sid (Gast)


Lesenswert?

MaWin schrieb:
> Erst heisst er seb nun fragt sid, wer weiss wer nun wer ist.

ich sid..

ICR1 der Hinweis AN Seb (TO),
dass ich glaube es müsste so funzen
Gewährlos

von Georg (Gast)


Lesenswert?

Seb schrieb:
> Gibt es irgendeinen Workaround, eine Zeitmessung dort durchzuführen?

Nein, schon das Konzept ist falsch. Wie schon erwähnt, eine 
Interrupt-Routine darf nicht länger laufen als unbedingt notwendig, eine 
Zeitmessung ist daher wenig hilfreich - wenn die Laufzeit zu lang ist 
liegt das Kind schon ersoffen im Brunnen.

Grundsätzlich sind Verzögerungsschleifen in der ISR verboten, ausser es 
handelt sich um wenige µs, z.B. zur Einhaltung von Setup- oder 
Hold-Zeiten. Das kommt aber eh nur infrage bei Assembler-Programmierung.

Georg

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.