Hallo ich habe mir einen Code "zusammengebastelt" der soweit super
funktioniert. Ziel ist es wenn man am Gartentor einen Taster betätigt
gehen alle Gehweglampen nacheinander im Fading an. Mein Problem ist nur,
wie kann ich nun einen Taster einbinden der das Program startet und beim
nächsten mal drücken wieder ausschaltet aber die Lampen wierder
Rückwärts aus dimmt?
Mir wäre es ersteinmal wichtig das man den Tater einbinden kann,der
Funktioniert bei mir nicht.
hier mein Code.
Braucht noch ein paar kleinere Funktionen und Variablen/Definitionen
drumherum, aber so als Denkanstoß sollte es funktionieren.
Kannst ja erst einmal eine bistabile Schaltung in Code bauen. Also
komplett ohne dimmen erstmal Tastendruck LED an, Tastendruck LED aus,...
Dann LED an und aus durch entsprechende Dimm-Funktionen ersetzen
Sebastian R. schrieb:> Kannst ja erst einmal eine bistabile Schaltung in Code bauen. Also> komplett ohne dimmen erstmal Tastendruck LED an, Tastendruck LED aus,...
ok danke also lass ich ersteinmal den versuch mit dem bool?
Markus R. schrieb:> ok danke also lass ich ersteinmal den versuch mit dem bool?
Naja. Die Entscheidung, ob die Lampen nun bei Tastendruck ein- oder
ausgeschaltet werden müssen, hängt nicht davon ab, welchen Zustand der
Taster vorher hatte, sondern welchen Zustand die Lampen vorher hatten.
Deshalb: Überleg dir (vielleicht auch basierend auf meinem Pseudocode),
wie man erst einmal mit Tastendruck die Lampen (oder die LED aufm Board)
einschaltet und mit dem nächsten Tastendruck wieder ausschaltet. Du
musst dir merken, welchen Zustand der Ausgang hat (wieder auslesen
und/oder xor 1 ginge, aber das führt dann später zu Problemen) und
entscheidest dann, wenn die Taste gedrückt wurde, ob du nun ein- oder
ausschalten musst.
ok danke ich tüftel heute mal noch ein paar Stunden bis ichs satt
habe:)hier nocheinmal etwas konkreter ich möchte den Taster einmal
drücken die Lampen gehen der Reihe nach an, bleiben 60s an und gehen
danach wieder (Programm läuft rückwärts) aus wenn der Taster bis dahin
nicht erneut gedrückt wurde.
Ich habe wie du schon gesagt hast mit dem Beispielcode aus der IDE jetzt
eine Led ein und aus schalten können. Wie aber sage ich dem Program das
es anhalten soll und erst dann weiter machen wenn die Bedingung "Taster
ein" gegeben ist?? denn den Befehlt ledPin den ich in der IDE habe gibt
es im obigen Programm nicht.Ich muss doch die Abfrage so gestallten das
zuerst der Taster abgefragt wird Tru False wenn Tru dann gehe im Program
weiter wen false dann warten bis true oder?
Markus R. schrieb:> wenn man am Gartentor einen Taster betätigt gehen alle Gehweglampen> nacheinander im Fading anMarkus R. schrieb:> wierder Rückwärts aus dimmt
Welchen Sinn hat das ? Klingt wieder wie eine Informatikerlösung,
prsktischer Unsinn. Man steht am Gartentor und die Lichterkette geht zum
Haus hin an.
Nun geht man doch entlang des Gartenwegs zum Haus.
Soll man danach zum Gartentor zurück laufen, um den Taster zum
Ausschalten zu drücken, und während die Lampe am Haus zuerst aus geht
schnell wieder zum Haus in die Dunkelheit hinein rennen?
Man braucht doch zumindest einen zweiten Taster am Haus. Und wenn man
den drückt, hat man den Weg hinter sich, die Lampen könnten schlagartig
aus gehen.
Und wenn man tatsächlich am Gartentor bleibt weil man es sich anders
überlegt hat, muss man dann wirklich warten bis die ganze Lichterkette
an ist, bevor man sie wieder ausschalten kann ?
Markus R. schrieb:> Wie aber sage ich dem Program das> es anhalten soll und erst dann weiter machen wenn die Bedingung "Taster> ein" gegeben ist?? denn den Befehlt ledPin den ich in der IDE habe gibt> es im obigen Programm nicht.Ich muss doch die Abfrage so gestallten das> zuerst der Taster abgefragt wird Tru False wenn Tru dann gehe im Program> weiter wen false dann warten bis true oder?
In meinem Pseudocode ist ein Hinweis darauf versteckt.
Nicht die eleganteste Lösung, aber es geht ja darum, was zu lernen.
solange(Taster nicht gedrückt){ tu nichts }
An MaWin
1. bitte richtig lesen da steht was von 60sec...
2. Sin oder Unsinn mag jeder für sich selbst entscheiden, ich finde es
schöner wenn es sanft anläuft
Sorry ich habe heute den ganzen Nachmittag verbraten und mir stehts bis
oben mit dem Prog. Ich komme immer wieder zum selben Fehler der da
wäre,das ich nicht die Ausgänge mittels Taster abschalten will sondern
das ich bei Taster abfrage die Stelle ausklammern mus in dem der Code
zum Andimmen steht. mit dem Vorschlag von Sebastian geht es nicht weil
hier ein bestimmter Ausgang definiert wird (LED) ich habe aber mehrere
Ausgänge die ich Formelbedingt nicht ausschalten kann.Somit muss das
Programm nach Tasterabfrage ja/nein entweder übersprungen werden oder
durchlaufen. Ich bitte nocheinmal um Hilfe. Es soll nur per Tastendruck
angedimmt werden 60sec. an bleiben und danach wieder ausdimmen (ende des
Programs)bis zur nächsten betätigung des Tasters. Kann ich das durch
eine If else funktion machen und für die 60sec.ein delay? ich befürchte
wenn ich das delay verwende stoppt der Programmablauf für 60sec. da
benötige ich doch auch noch einen Zähler oder??
hier nochmal mein Angefangener Code:
Markus R. schrieb:> Keiner eine Idee wie ich den Taster einbinden kann?
Du brauchst noch mindestens eine weitere Variable, die sich merkt, ob
ein Fading läuft oder nicht.
Die Variable könnte sich auch gleichzeitig dir Richtung merken: +1, 0,
-1
0: Kein Fading
+1: Einschalt-Fading
-1: Ausscahlt-Fading
jetzt habe ich es hinbekommen den Taster einzubinden. nun möchte ich 60
sekunden lang die Leds eingeschaltet lassen und danach wieder ausdimmen.
beim nächsten Tastenstart soll alles wieder von vorn beginnen.Hier
nocheinmal der funktionierende Code. Wenn ich es mit (mills) versuche
erwartet das Programm ja immer auch eine Aktion was es danach machen
soll.Wie kann ich es so Schreiben das es 60sek.wartet und dann die
nächsten Programmzeilen weiter ab arbeitet? Also das wäre dan das
Abdimmen.Formel Kopieren und Werte negieren ??
1
intbuttonPin=8;
2
boollastbuttonPin=true;// der Zustand des Buttons beim letzten Schle
Peter meint, dass du eine State-Maschine realisieren sollst.
Im switch/case hast du dann alle deine States und schreibst dazu den
Code, der im jeweiligen State ausgeführt werden soll.
Ansonsten ließ mal wie du am besten einen Taster verwenden solltest:
https://www.arduino.cc/en/tutorial/debounce
(Hier gibt es von Peter D. eine wunderschöne Lib, aber die ist denke ich
für den Anfang zu schwierig nachzuvollziehen.)
Und wie du Zeitintervalle festlegen kannst:
https://www.arduino.cc/en/tutorial/BlinkWithoutDelay
Ok, aber möchte das alles nicht zu komplex gestalten daher dachte ich es
wäre einfacher wenn man nach dem hoch faden hochzählt bis 60sek. Und
danach das abdimm Programm Schreibt was im Anschluss abläuft.
Markus R. schrieb:> Ok, aber möchte das alles nicht zu komplex gestalten daher dachte> ich es> wäre einfacher wenn man nach dem hoch faden hochzählt bis 60sek. Und> danach das abdimm Programm Schreibt was im Anschluss abläuft.
Das kannst du gerne so machen. Die Erfahrung zeigt, dass es immer
weniger Komplex wird, wenn man es richtig macht.
Dein nach dem Faden hochzählen kannst du ja mit delay() erledigen, oder
falls es retriggerbar sein soll mit Hilfe aus dem letzten Link.
Ja, Zustandsmaschinen, für jedes Teilproblem eine:
1. Taster. Das sieht ja schon gut aus: aktuellen Eingangswert mit dem
vorigen vergleichen, Aktivität nur bei Änderung, und nur wenn der Taster
gedrückt wurde, wird der Sollwert für das Licht geändert: von "aus" nach
"ein" oder umgekehrt. Entprellen ist wahrscheinlich nicht nötig, da ja
schon 10 (oder jetzt 20) ms delay in der Hauptschleife steht.
2. Licht. Je nach Sollwert (ein oder aus) einen anderen Algorithmus
nutzen. Den für "ein" hast du ja schon. Der sieht übrigens gut aus,
durch das min() ist er robust gegen unsinnige Werte in den Variablen,
wie sie vielleicht entstehen könnten, wenn jemand mitten beim Ausfaden
wieder einschaltet.
3. Timer. Der muß gestartet werden, sobald der Sollwert auf "ein" geht,
und wenn er abläuft, stellt er den Sollwert auf "aus". Timerstart heißt:
aktuelle millis() merken. Solange der Sollwert "ein" ist, muß man eben
bei jedem Schleifenduchlauf prüfen, ob der Start zu lange her ist, also
millis() - Startzeit zu groß.
Die drei Maschinen laufen praktisch unabhängig voneinander und sind nur
durch wenige globale Variablen (Sollwert und Timer-Startzeitpunkt)
miteinander verbunden. Bedingung dafür ist natürlich, daß der
Programmablauf nirgendwo durch irgendwelche delay()-Orgien oder
sonstiges Abwarten aufgehalten wird.
Markus R. schrieb:> Ok, aber möchte das alles nicht zu komplex gestalten
Im Gegenteil, jetzt ist es komplex und völlig unerweiterbar.
Eine Statemaschine macht alles wesentlich einfacher.
Z.B. der Tastendruck wechselt von STOP zu FADE_A. Ist FADE_A fertig
wechselst Du zu FADE_B usw.
Du mußt also nicht ständig alles machen, sondern nur das für die Aktion
nötige.
1
switch(state)
2
{
3
caseSTOP:if(get_key())
4
state=FADE_A;
5
break;
6
caseFADE_A:if(++a>=FADE_MAX)
7
state=FADE_B;
8
break;
9
caseFADE_B:if(++b>=FADE_MAX)
10
state=FADE_C;
11
break;
12
// ...
13
caseDIMM_F:if(--f==0)
14
state=DIMM_E;
15
break;
16
// usw.
17
}
Dann fällt es auch leicht, weitere States hinzuzufügen.
Die States definiert man vorzugweise mit einem enum.
Danke aber bei deinem Vorschlag Faden die LEDs nacheinander bei mir
gehen die ineinander über ab 20% geht die nächste los unsw. Ich kann da
auch nicht sehen das es eine Minute wartet?
man kann es auch in 4 States aufteilen: stateIDLE (wartend),
stateFadeUp, stateDelay, stateFadeDown. Die malt man sich als 4 Kreise
auf ein Blatt und dann Pfeile vom einen Zustand zum anderen. An die
Pfeile schreibt man wann diese Zustandsänderung passiert.
Das ist für diese Sequenz noch sehr einfach, aber so bekommt man auch
Erweiterungen übersichtlich hin. Z.B. einen Bewegungsmelder der nur
einschaltet, oder Taste lang drücken um Helligkeit fest dauerhauft
einzuschalten, Doppelklick zum Ausschalten.
Und FadeUp/Down in ein Unterprogramm packen, dann bleibt switch/case
übersichtlicher.
Was man versthen muss ist das kein Teil lange blockieren darf. Die loop
mit Eingänge auswerten und switch/case rennt immer schnell im Kreis. Nur
bei Zustandsänderung wird über die switch Variable auf eine andere
Funktion umgeschaltet.
Peter D. schrieb:> Ich würds mit Statemaschine (switch/case) machen.
Die Verwendung weiterer Arrays würde die Übersicht und
Modularisierbarkeit erhöhnen.
so als Vorlage:
- button an Pin2 startet state machine
- Meldungen über serielle werden ausgegeben, eine LED dimmt rauf/runter
Das fade() muss dann noch die Logik für die vielen LED bekommen.
Für sowas einfaches mit Kanonen mit auf Spatzen, aber dafür
Erweiterbar...
Das delay ist global, daher ist ein stateDelay hier nicht drin.
Vielen Dank für deine Mühe aber ich sehe da nicht mehr durch, ich muss
da noch sehr viel lernen. Ich versuch mich heute Abend nach der Arbeit
mal daran.
dafür sind die Ausgaben auf die serielle Schnittstelle drin,
Werkzeuge/Serieller Monitor ist hoffentlich bekannt?
Der Ablauf in loop() ist:
1
checkInputs()
2
Entprellzeit 20 ms abwarten
3
Taster einlesen
4
bei Änderung über startSequence() die Schrittkette anstossen
5
6
processDelay()
7
wenn die (globale) Verzögerungszeit >0 ist,
8
dann warten, sonst Wartezeit löschen
9
10
processStateMachine()
11
wenn wartezeit aktiv, dann nix machen
12
Meldung ausgeben wenn state sich geändert hat
13
Aktion abhängig vom State ausführen
state ist zunächst nix tun, bis der über die Taste auf FadeUp gesetzt
wird. Dann landet processStateMachine immer wieder in fade(). Bis es
fertig meldet, dann wird eine Pause gesetzt (als Demo 3s) und der
nächste Schritt auf fadeDown gesetzt. Weil die Verzögerung jetzt >0 ist,
wird fadeDown aber erst nach Ablauf der Verzögerungszeit erreicht. Wenn
fade() jetzt fertig meldet wird wieder auf warten geschaltet.
fade() kann machen was es will, es darf nur nicht blockieren. Das loop()
führt dann immer wieder die 3 Funktionen aus und kann damit jederzeit
auf die Taste (oder auch andere Eingänge) reagieren. Wenn man in einem
stat ungleich idle ist, könnte man mit der Taste auch ein stop auslösen
(LED aus, state auf idle setzen).
Hoffe es war einigermassen verständlich.
Super ! das funktioniert Danke bis dahin ist auch super erklärt! aber in
welchen Teil deines Sketches kann ich jetzt meine Routine einbinden? in
der "VOID Loop" wie vorher geht das jetzt bestimmt nicht mehr so einfach
oder? Ich muss jetzt meine Variablen ändern da er ja nicht mehr über
vals hoch zählt (0-255) sondern über deine Formel trotzdem muss ich
jetzt sagen das er die erste LED bis 20% andimmen soll und weiter bis
255 aber gleichzeitig bei ereichen von 21% die zweite Led anfangen soll
unsw. damit es einen weichen Übergang untereinander gibt.
[c]
// Zählervariablen berechnen
a = min(a++, numVal-1); // Zähler 1. LED wird hochgezählt bis 31
if (vals[a] > schwelle){
b = min(b++, numVal-1); // Zähler 2. LED wird hochgezählt bis
31, wenn Wert 1. LED > Schwelle,
}
if (vals[b] > schwelle){
c = min(c++, numVal-1); // Zähler 3. LED wird hochgezählt bis
31, wenn Wert 2. LED > Schwelle,
}
if (vals[c] > schwelle){
d = min(d++, numVal-1); // Zähler 4. LED wird hochgezählt bis 31,
wenn Wert 2. LED > Schwelle,
}
if (vals[d] > schwelle){
e = min(e++, numVal-1); // Zähler 5. LED wird hochgezählt bis 31,
wenn Wert 2. LED > Schwelle,
}
if (vals[e] > schwelle){
f = min(f++, numVal-1); // Zähler 6. LED wird hochgezählt bis 31,
wenn Wert 2. LED > Schwelle,
}
analogWrite(3, vals[a]);
analogWrite(5, vals[b]);
analogWrite(6, vals[c]);
analogWrite(9, vals[d]);
analogWrite(10, vals[e]);
analogWrite(11, vals[f]);
delay(20);
[c/]
Das gehört in die fade() Funktion, das jetzige LED rauf/runter war nur
ein Beispiel für den Test. Ein Argument für die Richtung ist ja schon
drin, damit kann beides in eine Funktion. Fade() wird auch zyklisch
aufgerufen, wie vorher in loop(). Mit dem Unterschied das es jetzt nur
gestartet wird wenn es im Ablauf dran ist.
Und das delay(20) wird jetzt praktisch am Anfang gemacht und muss weg,
sonst würde es ja die ganze Ausführung für 20 ms blockieren.
Johannes S. schrieb:> Das gehört in die fade() Funktion
Man kann dafür auch eine 2. Statemaschine implementieren.
Je feiner man Code unterteilt, umso übersichtlicher wird er.
ja, richtig. Nur sind in vielen Arduino Programmen schon Unterprogramme
Luxus und für einen Anfänger vielleicht eher unübersichtlich :)
Nur wenn Code wächst und dann in eine 1 m lange loop ausartet ist es
meist zu spät. Wenn die eine Schrittkette verstanden wurde kommt der TO
hoffentlich auch weiter.
Die fade() Funktion kann man auch mit einem Schieberegister bauen: ein
Array mit Wert für jede Led, nach jedem 200 ms Schritt alle Werte um
eine Position weiterschieben und den nächsten Helligkeitswert aus der
Tabelle an Anfang (oder Ende für runterdimmen) setzen.
Aber dann wäre ja garnix mehr vom original Code übrig.