Erste Frage
Ich habe eine allgemeine Frage zum Umgang mit Interrupts in Mikrocontrollern. Ich verwende den MSP430, aber ich denke, die Frage kann auf andere uCs ausgedehnt werden. Ich möchte wissen, ob es eine gute Praxis ist, Interrupts häufig entlang des Codes zu aktivieren / deaktivieren. Ich meine, wenn ich einen Teil des Codes habe, der nicht empfindlich auf Interrupts reagiert (oder noch schlimmer, aus irgendeinem Grund nicht auf Interrupts hören darf), ist es besser:
- Deaktivieren Sie die Interrupts vor und aktivieren Sie sie nach dem kritischen Abschnitt wieder.
- Setzen Sie ein Flag in den jeweiligen ISR und setzen Sie (anstatt den Interrupt zu deaktivieren) das Flag vor dem kritischen Abschnitt auf false und setzen Sie es unmittelbar danach auf true zurück. Um zu verhindern, dass der Code des ISR ausgeführt wird.
- Keiner der beiden, daher sind Vorschläge willkommen!
Update: Interrupts und Zustandsdiagramme
Ich werde eine bestimmte Situation zur Verfügung stellen. Nehmen wir an, wir möchten ein Zustandsdiagramm implementieren, das aus 4 Blöcken besteht:
- Übergänge / Wirkung.
- Ausgangsbedingungen.
- Einstiegsaktivität.
- Aktivität ausführen.
Das hat uns ein Professor an der Universität beigebracht. Wahrscheinlich ist es nicht die beste Möglichkeit, dieses Schema zu befolgen:
while(true) {
/* Transitions/Effects */
//----------------------------------------------------------------------
next_state = current_state;
switch (current_state)
{
case STATE_A:
if(EVENT1) {next_state = STATE_C}
if(d == THRESHOLD) {next_state = STATE_D; a++}
break;
case STATE_B:
// transitions and effects
break;
(...)
}
/* Exit activity -> only performed if I leave the state for a new one */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(current_state)
{
case STATE_A:
// Exit activity of STATE_A
break;
case STATE_B:
// Exit activity of STATE_B
break;
(...)
}
}
/* Entry activity -> only performed the 1st time I enter a state */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(next_state)
{
case STATE_A:
// Entry activity of STATE_A
break;
case STATE_B:
// Entry activity of STATE_B
break;
(...)
}
}
current_state = next_state;
/* Do activity */
//----------------------------------------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
}
Nehmen wir auch an, dass STATE_A
ich beispielsweise empfindlich auf einen Interrupt reagieren möchte, der von einer Reihe von Tasten ausgeht (mit Debouce-System usw. usw.). Wenn jemand eine dieser Tasten drückt, wird ein Interrupt generiert und das Flag für den Eingangsport in eine Variable kopiert buttonPressed
. Wenn die Entprellung auf irgendeine Weise auf 200 ms eingestellt ist (Watchdog-Timer, Timer, Zähler, ...), können wir sicher buttonPressed
nicht vor 200 ms mit einem neuen Wert aktualisiert werden. Das frage ich dich (und mich selbst :) natürlich)
Muss ich die Unterbrechung der DO-Aktivität aktivieren STATE_A
und deaktivieren, bevor ich gehe?
/* Do activity */
//-------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
Enable_ButtonsInterrupt(); // and clear flags before it
// Do fancy stuff and ...
// ... wait until a button is pressed (e.g. LPM3 of the MSP430)
// Here I have my buttonPressed flag ready!
Disable_ButtonsInterrupt();
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
Auf eine Weise, dass ich sicher bin, dass ich beim nächsten Ausführen von Block 1 (Übergang / Effekte) bei der nächsten Iteration sicher bin, dass die entlang der Übergänge überprüften Bedingungen nicht von einem nachfolgenden Interrupt stammen, der den vorherigen Wert buttonPressed
dieses I überschrieben hat brauchen (obwohl es unmöglich ist, dass dies passiert, weil 250 ms vergehen müssen).