millis() in Interrupt (Arduino)

Gast #6025940
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
Gast #6025943
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.
Gast #6026059
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
Gast #6026845
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).
Gast #6027237
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

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