Die folgenden Ausschnitte stammen aus dem Quellcode der TimerOne-Bibliothek :
// TimerOne.h:
void (*isrCallback)();
// TimerOne.cpp:
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
Timer1.isrCallback();
}
// TimerOne.cpp:
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
resume();
}
Die Frage: Wenn der Timer bereits läuft und das Hauptprogramm aufruft attachInterrupt()
, kann der Timer-Interrupt dort während der Funktionszeigerzuweisung auftreten isrCallback = isr;
? Dann Timer1.isrCallback();
würde der Funktionszeiger mit etwas Glück teilweise aus der alten und teilweise aus der neuen Adresse bestehen, was dazu führen würde, dass der ISR zu einem falschen Ort springt?
Ich nehme an, dass dies der Fall sein könnte, da Funktionszeiger sicherlich breiter als 1 Byte sind und der Zugriff auf Daten mit> 1 Byte nicht atomar ist. Mögliche Problemumgehungen könnten sein:
- Immer anrufen
detachInterrupt()
an, um sicherzustellen, dass der Timer nicht läuft, bevor Sie anrufenattachInterrupt()
, dh klären Sie die Timer1-Dokumente. - Oder ändern Sie Timer1, indem Sie die Timer-Überlauf-Interrupts kurz zuvor vorübergehend deaktivieren
isrCallback = isr;
Ist dies sinnvoll oder gibt es etwas in Timer1
Quellen oder Funktionszeigerzuweisungen, das ich verpasst habe?
Es sieht so aus, als hätten Sie einen Punkt. Es ist logisch, Interrupts so zu deaktivieren, dass Sie sie nicht wieder aktivieren, wenn sie überhaupt deaktiviert wurden. Beispielsweise:
Damit möchten Sie Code wie folgt schreiben lassen:
Ohne diese Bestimmung könnten Sie eine Unterbrechung zwischen diesen beiden Leitungen bekommen und somit auf unbestimmte Zeit schlafen (weil die Unterbrechung, die Sie wecken würde, aufgetreten ist, bevor Sie geschlafen haben). Die Bestimmung im Prozessor, dass der nächste Befehl, nachdem Interrupts aktiviert wurden, wenn sie vorher nicht aktiviert wurden, immer ausgeführt wird, schützt dagegen.
quelle
TIMSK1=0; TIFR1=_BV(TOV1); isrCallback=isr; TIMSK1=_BV(TOIE1);
? Es schont ein CPU-Register und trägt nicht zur Interrupt-Latenz bei.