supersonix:
Wo ist mein Denkfehler?
Dein Denkfehler liegt darin, dass Du davon ausgehst, dass Du innerhalb von Interrupt-Behandlungsroutinen jede Art von Code ausführen darfst. Das ist eine völlig falsche Annahme.
Tatsächlich ist es so: Innerhalb von Interrupt-Behandlungsroutinen darf nur ganz bestimmter Code ausgeführt werden, und zwar nur solcher Code, der für die Ausführung keinerlei Interrupts benötigt und der auch keine laufenden Timer braucht.
Daher kannst Du z.B. innerhalb einer ISR-Routine keine Ausgaben auf Deinem LCD-Display machen, da die entsprechenden Library-Aufrufe die Buchstaben auf das LCD selbst interruptgesteuert oder timergesteuert (weiß ich selbst nicht so genau) raustickern. Und "Interrupt im Interrupt" ausführen geht nicht, genausowenig wie Timing mit millis() und micros(). Also crasht an der Stelle Dein Programm, wenn Du es trotzdem versuchst.
Du bist also innerhalb von Interrupt-Behandlungsroutinen extrem beschränkt, welcher Code überhaupt ausgeführt werden kann und verwendet werden darf.
Also: Innerhalb einer Interrupt-Routine keine Library-Funktionen aufrufen, von denen Du nicht sicher weißt, dass zu deren Ausführung keinerlei Interrupts benötigt werden und die auch nicht Verzögerungen mit delay(), millis() und micros() realisieren wollen!
Wenn Du das, was Du vorhast, tatsächlich mit Interrupt-Programmierung machen möchtest, müssen alle Ausgaben auf dem LCD außerhalb der Interrupt-Routine stattfinden. Du könntest es beispielsweise so machen, dass innerhalb der ISR nur ein Status-Flag zurückgesetzt wird:
volatile int textNum=-1;
void resetLCD()
{
textNum=-1;
}
Das Setzen einer Variablen in der ISR ist "interruptsicher", weil keine Library-Funktion dazu aufgerufen werden muß. Und vor der Variablen-Deklaration siehst Du ein "volatile", das ist Pflicht für Variablen, auf die sowohl aus "normalem Code" als auch von "Interrupt Code" aus zugegriffen werden sollen.
Die Ausgaberoutine, die nur von normalem Code aus aufgerufen werden darf, kann dann abhängig vom übergebenen Parameter die Ausgabe vornehmen:
void zeigeText(int nr)
{
lcd.clear();
lcd.setCursor(0,0);
if (textNum>=0)
lcd.print(menu[nr]);
else
lcd.print(normalText);
}
Und die loop macht folgendes:
- Wenn eine Taste gedrückt wird, wird die Nummer des anzuzeigenden Textes geändert und der Interrupt-Timer gestartet.
- Wenn sich die Nummer des anzuzeigenden Textes geändert hat, wird der passende Text angezeigt
int letzteTextNum;
void loop()
{
if (digitalRead(11))
{
textNum=0;
MsTimer2::start();
}
if (textNum!=letzteTextNum)
{
zeigeText(textNum);
letzteTextNum=textNum;
}
}
Solche Anzeigenänderungen macht man normalerweise aber nicht mit Timer-Interrupts.
Viel zu kompliziert und fehlerträchtig.