"blinkerSchalterZustand" klingt erstmal nach einem gute gewählten Namen.
Aber was die Werte 0 1 und 2 bedeuten, kann ich nicht schnell erkennen.
Benutze dafür Enumerations oder Konstanten.
Vorschlag:
#define GEDRUECKT 1
#define LOSGELASSEN 0
#define GEDRUECKT_ZUM_EINSCHALTEN 0
#define LOSGELASSEN_NACH_EINSCHALTEN 1
#define GEDRUECKTE_ZUM_AUSSCHALTEN 2
#define LOSGELASSEN_ZUM_AUSSSCHALTEN 3
"blinkerZustandMerker" gefällt mir gar nicht. Der Name sagt mir zwar,
dass da irgendwas vermerkt wird, aber nicht genau genug. Hier schlage
ich vor: "vorherigerBlinkerZustand".
Dein Lösungsansatz mit dem Zustandsautomat gefällt mir im Prinzip,
allerdings könntest du den Code deutlich übersichtlicher und besser
erweiterbar gestalten, wenn du folgende Punkte berücksichtigst:
- Jeder Zustandsautomat hat genau eine Zustandsvariable, die Auskunft
darüber gibt, auf welches Ereignis der Automat wartet (nicht, welche
Signale gerade anliegen!).
- Bei jedem Zustand wartet der Automat auf ein oder mehrere Ereignisse
und löst ggf. die gewünschte Aktion aus.
1 | void Task_LedSteuerung()
|
2 | {
|
3 | static uint8_t zustand;
|
4 | uint8_t taster=digitalRead(...);
|
5 | switch (zustand)
|
6 | {
|
7 | case 0: // Warte auf Einschalten
|
8 | if (taster==1)
|
9 | {
|
10 | digitalWrite(...,HIGH);
|
11 | zustand=1;
|
12 | }
|
13 | break;
|
14 |
|
15 | case 1: // Warte auf Loslassen
|
16 | if (taster==0)
|
17 | {
|
18 | zustand=2;
|
19 | }
|
20 | break;
|
21 |
|
22 | case 2: // Warte auf Ausschalten
|
23 | if (taster==1)
|
24 | {
|
25 | digitalWrite(...,LOW);
|
26 | zustand=3;
|
27 | }
|
28 | break;
|
29 |
|
30 | case 3: // Warte auf Loslassen
|
31 | if (taster==0)
|
32 | {
|
33 | zustand=0;
|
34 | }
|
35 | break;
|
36 | }
|
37 | }
|
38 |
|
39 | void loop()
|
40 | {
|
41 | Task_LedSteuerung();
|
42 | delay(10);
|
43 | }
|
Auch hier wäre wieder eine Enumeration oder Konstanten für die Stati
sinnvoll. Ich zeige das im nächsten Beispiel.
Du verwendest delay um den Taster zu entprellen. Während der µC wartet,
kann er nichts anderes tun. Häufig istb es allerdings nötig, ständig
etwas zu tun. Zum Beispiel andere Taster abfragen. Oder etwas auf einem
LED-Matrix Display darstellen.
Daher benutze besser einen Systemtimer. Um den Code jetzt nicht
unübersichtlich zu machen, schlage ich vor, die Entprellung des Tasters
in einen separaten Task zu packen. Etwa so:
1 | uint8_t ereignis_taster_gedrueckt;
|
2 |
|
3 | // Setzt die Variable taster_gedrueckt=1 wenn der Taster gedrückt wurde.
|
4 | // Beim Loslassen des Tasters bleibt die Variable unverändert!
|
5 | void Task_Entprellen()
|
6 | {
|
7 | static enum {WARTE_DRUCK, ENTPRELLEN1, WARTE_LOSLASSEN, ENTPRELLEN2} zustand=WARTE_DRUCK;
|
8 | static long warteSeit;
|
9 |
|
10 | uint8_t taster=digitalRead(...);
|
11 | switch (zustand)
|
12 | {
|
13 | case WARTE_DRUCK:
|
14 | if (taster==1)
|
15 | {
|
16 | taster_gedrueckt=1;
|
17 | status=ENTPRELLEN1;
|
18 | warteSeit=millis();
|
19 | }
|
20 | break;
|
21 |
|
22 | case ENTPRELLEN1:
|
23 | if (millis()-warteSeit>50)
|
24 | {
|
25 | status=WARTE_LOSLASSEN;
|
26 | }
|
27 | break;
|
28 |
|
29 | case WARTE_LOSLASSEN:
|
30 | if (taster==0)
|
31 | {
|
32 | // Absichtlich auskommentiert: taster_gedrueckt=0;
|
33 | status=ENTPRELLEN2;
|
34 | warteSeit=millis();
|
35 | }
|
36 | break;
|
37 |
|
38 | case ENTPRELLEN2:
|
39 | if (millis()-warteSeit>50)
|
40 | {
|
41 | status=WARTE_DRUCK;
|
42 | }
|
43 | break;
|
44 | }
|
45 | }
|
46 |
|
47 | void Task_LedSteuerung()
|
48 | {
|
49 | static enum {WARTE_EINSCHALTEN, WARTE_AUSSCHALTEN} zustand=WARTE_EINSCHALTEN;
|
50 | switch (zustand)
|
51 | {
|
52 | case WARTE_EINSCHALTEN:
|
53 | if (ereignis_taster_gedrueckt)
|
54 | {
|
55 | digitalWrite(...,HIGH);
|
56 | // Ereignis als "erledigt" kennzeichnen
|
57 | ereignis_taster_gedrueckt=0;
|
58 | zustand=WARTE_AUSSCHALTEN;
|
59 | }
|
60 | break;
|
61 |
|
62 | case WARTE_AUSSCHALTEN:
|
63 | if (ereignis_taster_gedrueckt)
|
64 | {
|
65 | digitalWrite(...,LOW);
|
66 | // Ereignis als "erledigt" kennzeichnen
|
67 | ereignis_taster_gedrueckt=0;
|
68 | zustand=WARTE_EINSCHALTEN;
|
69 | }
|
70 | break;
|
71 | }
|
72 | }
|
73 |
|
74 | void loop()
|
75 | {
|
76 | Task_Entprellen();
|
77 | Task_LedSteuerung();
|
78 | }
|
Der Aufruf von delay() entfällt, weil der Task_Entprellen() bereits nach
erkanntem Tastendruck (bzw. Loslassen) eine Weile wartet. Allerdings
wartet er nicht mit delay, sondern indem er immer wieder bei jedem
loop() prüft, ob schon mehr als 50 Millisekunden verstrichen sind.