Tasten über Interrupt und "Drückdauer"

Ja, auf einem Steckbrett. Habe die Schalter einfach mal getauscht (PIN am Board), es ändert sich nichts.

Ich habe nun mal "Meldungen" und Zähler in die Routinen eingebaut. Wenn loop einmal läuft, dann läuft die Routine "handleBlinkState" 2x. Und beim ersten Durchgang nach reset gibt der Monitor mir die Meldung "l" (.. soll der linke Blinker an sein ...) aus, dann nicht mehr.
Beim Start - mit einem delay 3000 - extrem verzögert, sind auch zunächst beide Leds an. Die linke geht dann nach dem ersten loop aus, die Rechte nicht. Jetzt werde ich mir mal die Werte in der Routune ausgeben lassen (wenn die Frau das Essen noch nicht fertig hat :slight_smile:

Durch diverse delays() und printeln() kann ich nun folgendes Verhalten beschreiben:

Beim Start des Sketch sind beide LEDs High.
Dann werden die Routinen "blinkTask()", "setCurrentKeystate()", "handleStateChange" durchlaufen. Bis hier leuchten
immer noch beide LEDs. Dann gehts in die Routine "handleBlinkState". Hier schaltet sich die Linke LED ab, die Rechte leuchtet weiter. Der Zähler in dieser Routine erhöht sich immer um 2, in den anderen Routinen um 1.
Morgen dann mehr ...

odiug:
Beim Start des Sketch sind beide LEDs High.

Schaltest Du die LEDs über Relais, die auf "ative LOW" schalten (z.B, mechanische Relais mit Optokopplern)?

In dem Fall sollte aber eigentlich auch nur die Blinklogik vertauscht sein, d.h. zu Anfang wären dann beide Blinker auf Dauerlicht an. Beim Einschalten blinkt es und beim Ausschalten wären wieder beide Blinker auf Dauerlicht an. Aber das ist es ja auch nicht.

Ich kann das von Dir beschriebene Verhalten hier nicht nachvollziehen und müßte mir bei Gelegenheit mal die Bauteile in der Grabbelkiste zusammensuchen und so zusammenstecken wie Du den Aufbau hast, mit PullDown-Widerständen an den Buttons.

Nachtrag vom 13.10.: Auch nachdem ich die Schaltung mit Tastern und PullDown-Widerständen auf Steckbrett aufgebaut habe, kommt nichts anderes dabei heraus als vorher: Das gepostete Programm funktioniert völlig einwandfrei. Einzige notwendige Änderung ist der INPUTTYPE auf "INPUT" statt auf "INPUT_PULLUP", wenn man PullDown-Widerstände an den Buttons verwendet statt PullUp-Widerstände.

Deshalb bleibt es bei meinem oben geposteten Ratschlag:
Prüfe mal den PullDown-Widerstand (Widerstandswert, Anschluss, Spannungspegel) am rechten Taster!
Der rechte Taster ist bestimmt nicht sauber auf LOW, wenn der gleich am Start als HIGH ausgewertet wird!
Schaltung überprüfen! Eventuell mal den Pulldown-Widerstand genau ausmessen oder den Button austauschen.
Oder testen, ob der rechte Button einen Wackelkontakt hat. Wenn man den "keystate" mal durchlaufen läßt, bei unbetätigter Taste und auch mal längere Zeit bei gedrückter Taste, dann sollte man "Ausreißer" im keystate eigentlich im seriellen Monitor leicht identifizieren können.

Sorry, aber ich widerspreche Dir. Der Grund muss ein anderer sein ....

Ich habe heute deinen Sketch mit weiteren Ausgaben und delays versehen.
Mit Start des Programmes leuchten beide LEDs. Das Programm kommt dann zur Routine "handleBlinkState". Bis zum if-Aufruf "Soll der linke Blinker gerade an sein?" leuchten beide LEDs. Nach Abarbeitung dieses If's geht die linke LED aus, es wird am Bildschirm ein " l" ausgegeben und der zweite Durchlauf beginnt. Dann wird keine Meldung mehr ausgegeben. Ich kann gerne eine Video bei YouTube posten ...

Ich habe heute dann meinen Interrupt-Sketch geladen, da werden alle Taster erkannt ohne dass der rechte Taster irgendwie anders als die anderen reagiert. Auch die LEDs gehen nicht beide direkt an.

Sorry, aber es muss was anderes sein.

Verwendest Du ein Due-Board?

odiug:
Sorry, aber es muss was anderes sein.

Verwendest Du ein Due-Board?

Ich habe noch nie einen DUE gehabt, zum Testen habe ich einen UNO und einen MEGA.

Lasse bei Dir mal folgenden Test-Sketch laufen:

#define LAMPELINKS 22
#define LAMPERECHTS 23

void setup() {
  Serial.begin(9600);
  pinMode(LAMPELINKS,OUTPUT);  
  pinMode(LAMPERECHTS,OUTPUT);  
  Serial.println("Sketch gestartet.");
  delay(10000);
  Serial.println("Nach 10 Sekunden:");
  digitalWrite(LAMPELINKS,HIGH);  
  digitalWrite(LAMPERECHTS,HIGH);  
}

void loop() {
}

Pin-Nummern für die beiden LEDs ggf. anpassen.

Nachdem die Meldung "Sketch gestartet" im seriellen Monitor angezeigt wird: Sind Deine LEDs dann an oder aus?

Und 10 Sekunden danach: Sind Deine LEDs dann an oder aus?

Die LEDs sind die ganze Zeit AN.
Direkt mit Start AN und nach 10 Sekunden auch noch AN.
Also scheint es so, dass die LEDs mit der Initalisierung direkt ein HIGH bekommen. Ich habe Deinen Test-Sketch geändert und aus dem HIGH ein LOW gemacht. Folge: Nach10 Sekunden schalten sich die LEDs auch AUS.

Ich habe jetzt im BLINKER Sketch diese beiden Zeilen im void setup() eingefügt:
digitalWrite( BLINKPINLEFT, LOW);
digitalWrite( BLINKPINRIGHT, LOW);
Nun bleiben beide LEDs beim Start aus. Die linke LED funktioniert mit der Linken-, der Warn- und der Stopp-Taste wie gewünscht.
Drücke ich die rechte Taste oder die Warn-Taste, dann geht die rechte LED an, aber blinkt nicht und geht auch nicht mehr aus. Egal welche Taste (Stopp, Warn etc.) ich dann drücke, ein Dauerlicht halt ... bis zu einem Reset.

odiug:
Die LEDs sind die ganze Zeit AN.
Direkt mit Start AN und nach 10 Sekunden auch noch AN.
Also scheint es so, dass die LEDs mit der Initalisierung direkt ein HIGH bekommen.

OK, also macht der DUE einiges anders, denn alle übrigen Arduinos sind nach dem Starten LOW an den Pins.

odiug:
Ich habe Deinen Test-Sketch geändert und aus dem HIGH ein LOW gemacht. Folge: Nach10 Sekunden schalten sich die LEDs auch AUS.

Ich habe jetzt im BLINKER Sketch diese beiden Zeilen im void setup() eingefügt:
digitalWrite( BLINKPINLEFT, LOW);
digitalWrite( BLINKPINRIGHT, LOW);
Nun bleiben beide LEDs beim Start aus. Die linke LED funktioniert mit der Linken-, der Warn- und der Stopp-Taste wie gewünscht.

Das hört sich schon mal besser an als vorher.

Da die Betaversion der Arduino-Softare für den DUE immer noch einige Bugs enthält (und gerade deshalb noch "BETA" ist), mußt Du bei Verwendung des DUE offenbar einige Bugs umschiffen. Ein Bug der DUE-BETA-Version betrifft auch den von mir geposteten Sketch und ist hier mit Workaround beschrieben:
http://forum.arduino.cc/index.php?topic=185291.0

Man kann offenbar den Status von als OUTPUT gesetzten Pins beim DUE nur dann zuverlässig auslesen, wenn der Pin vorher einmal als INPUT gesetzt war.

Mein Vorschlag wäre also, den im Link genannten Workaround zu verwenden, in der setup-Funktion die Ausgänge erstmal auf INPUT und danach erst auf OUTPUT und dann am Ende nochmal LOW, damit die Ausgänge LOW und die LEDs bei Programmstart aus sind:

void setup() 
{
#ifdef DEBUG  
  Serial.begin(9600);
#endif
  pinMode(BUTTONLEFT, INPUTTYPE);
  pinMode(BUTTONRIGHT, INPUTTYPE);
  pinMode(BUTTONSTOP, INPUTTYPE);
  pinMode(BUTTONWARN, INPUTTYPE);
  // Die beiden LED-Pins auf digitalen Output schalten
  pinMode(BLINKPINLEFT, INPUT);
  pinMode(BLINKPINLEFT, OUTPUT);
  digitalWrite(BLINKPINLEFT, LOW);
  pinMode(BLINKPINRIGHT, INPUT);
  pinMode(BLINKPINRIGHT, OUTPUT);
  digitalWrite(BLINKPINRIGHT, LOW);
}

Irgendwelche Änderungen im Ablauf?

TREFFER UND VERSENKT :smiley:

Jau, das war es .... Nun funz't es ....
Ich denke, Du hast schon an mir gezweifelt - vielen Dank für Deinen unermüdlichen Einsatz.
Der Hinweis mit dem DUE-Board war dann ja doch nicht so ganz verkehrt.

Jetzt werde ich mich noch etwas mit dem "&variable" (Pointer) beschäftigen, damit dann alles sitzt.
Da ich ja auch die Byte-Schieberei bislang vermieden habe :roll_eyes: muss ich noch einmal fragen:
Wenn ich einByte abfrage, dann wird mir immer ein "0b" mitgeliefert?

Dann werde ich mich nun mal an den Gyrosensor und das Display machen .... 8)

odiug:
Jau, das war es .... Nun funz't es ....

Na bravo!

odiug:
Ich denke, Du hast schon an mir gezweifelt - vielen Dank für Deinen unermüdlichen Einsatz.
Der Hinweis mit dem DUE-Board war dann ja doch nicht so ganz verkehrt.

Ja, zeitweise schon. Aber dass der DUE doch so große Unterschiede zu den Standard-Arduinos aufweist, wenn man "nur" die Befehle der Arduino-Software verwendet, war mir vollkommen neu. Z.B. dass Pins nach dem Setzen auf OUTPUT im setup() HIGH statt LOW sind, oder dass man den Zustand von als OUTPUT gesetzten Pins nur dann sicher abfragen kann, wenn der Ausgang vorher einmal explizit als INPUT gesetzt war. Na ja, hinterher ist man schlauer.

odiug:
Jetzt werde ich mich noch etwas mit dem "&variable" (Pointer) beschäftigen, damit dann alles sitzt.

Du meinst mit dem &-Adressoperator bei den Parametern in den Funktionsdeklarationen?

Der Unterschied ist der:
Wenn die Variablen "normal" deklariert sind, sind sie "call-by-value", die Funktion erhält eine Kopie der originalen Variablen übergeben. Die Funktion kann innerhalb der Funktion diese Variablen ändern, aber an der Stelle wo die Funktion aufgerufen wurde, wird das Original des Parameters NICHT geändert. Es wird ja in der Funktion tatsächlich mit einer Kopie des Parameters gearbeitet und nicht mit dem Original-Parameter.

Wenn die Variable in der Parameterliste mit dem &-Adressoperator deklariert ist, ist es "call-by-reference". Die Funktion bekommt dann keine Kopie des Parameters übergeben, sondern einen Referenz-Verweis auf den originalen Parameter. Wenn dieser Parameter innerhalb der Funktion verändert wird, wird der tatsächliche originale Parameter gleichzeitig an der Stelle geändert, von wo aus der Funktionsaufruf mit diesem Parameter erfolgte. Das benutzt man für Parameter "die innerhalb einer Funktion von der Funktion änderbar" sein sollen.

odiug:
Da ich ja auch die Byte-Schieberei bislang vermieden habe :roll_eyes: muss ich noch einmal fragen:
Wenn ich einByte abfrage, dann wird mir immer ein "0b" mitgeliefert?

Nein, es wird nichts "geliefert". Eine Zahl ist eine Zahl und kann auf verschiedene Arten dargestellt werden. Man kann z.B. eine Zahl als normale Dezimalzahl schreiben:
byte zahl=255;
Oder dieselbe Zahl als Hexedezimalzahl:
byte zahl=0xFF;
Oder dieselbe Zahl als Binärzahl:
byte zahl=0b11111111;

Das "0b" ist ein Präfix (quasi "Vorsilbe") und bedeutet, dass die nachfolgende Zahl als Binärzahl interpretiert werden soll.
Also genau so wie das Präfix "0x" bedeutet, dass die nachfolgende Zahl als Hexadezimalzahl interpretiert werden soll.

Es handelt sich als nur um einen Hinweis für den Compiler: Steht eine Zahl ohne Präfix da, soll er sie als Dezimalzahl behandeln, mit Präfix "0x" vor der Zahl als Hexadezimalzahl und mit Präfix "0b" als Binärzahl.

Die Darstellung als Binärzahl im Quelltext habe ich nur gewählt, weil man bei dieser Darstellung sehr gut die gesetzten und nicht gesetzten Bits in der Zahl erkennen kann.

Was ich durch dieses Projekt schon von Dir lernen konnte .... einfach genial und vielen, vielen Dank für Deine geduldigen Erklärungen.
Wenn Du mal Langweile haben solltest, kannst Du ja mal 2 Tasten programmieren, die eine blinkende LED durch Interrupt erzeugen bzw. unterbrechen. Wenn DU das machst, bin ich mir sicher es auch hinterher zu verstehen.

@Jurs
Ich bin gerade über Deinen Sketch gestolpert - und der erfüllt genau das, was ich suche. Ich habe in in die Arduino Ide kopiert beim kompilieren kommt die Fehlermeldung, dass blinkPhase nicht definiert ist. Da ich die Funktion Garagentor nicht benötige, habe ich die ausgeklammert ohne dass es etwas gebracht hätte. Kann es an der Verwendung der neuesten IDE liegen?

Danke und Grüße aus Hamburg

Jörg