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
voidreceiveEvent(intx){
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
voidUnterprogramm(){
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
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.
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.
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.
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).
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
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
Eine eigene Frage?
Dieser Thread ist über 7 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.