Bitte löschen!
Beim Ersten Tastendruck startest du einen Timer (mit millis) der überwacht deine Zeit.
Und per Tastendruck zählt ein Zähler hoch, je Druck +1, bei 5 angekommen musst du die Zeit prüfen, ob es innerhalb deiner Vorgabe liegt.
Tastenentprellen nicht vergessen.
blackperil:
Wie kann ich denn das Programm dazu bewegen, dass es obwohl es mit dem ersten Tastendruck normal startet es dann nach den registrierten 5 mal tasten innerhalb von 2 Sekunden abbricht und das alternative Programm startet?
"Warten" im Sinne von "Programmausführung blockieren", kann ein Arduino-Programm mit Hilfe des "delay()" Befehls.
Aber sobald Dein Programm auch nur einmal delay() verwendet, hast Du ein Idiotenprogramm.
Willst Du ein Idiotenprogramm machen?
Wenn nein, dann mußt Du eine Programmlogik für ein "kooperatives Multitasking verwenden. Ein Programm, das viele Aufgaben quasi-gleichzeitig imerledigen kann, aufgeteilt in kleinste Funktionseinheiten, die jede für sich praktisch keine Ausführungszeit benötigt:
- Drucktaster abfagen
- Tastendrücke zählen mit Timeout
- ein oder mehrere Lichtprogramme ausführen
und das allesvollständig kooperativ und OHNE den Idiotenbefehl "delay() zu verwenden, der die Programmausführung für eine gewisse Zeit für alles blockiert.
Und das ohne die Unterstützung eines Betriebssystems mit "präemptivem Multitasking", sondern rein mit "kooperativem Multitasking mit eigener Programmlogik und ohne delay().
Kanst Du sowas überhaupt programmieren?
Oder ist "delay() vielleicht sogar einer Deiner Lieblingsbefehle, ohne den Du sequentielle Zeitabläufe gar nicht gesteuert bekommst?
Wie Jurs es schon geschrieben hat, die "delays" müssen alle raus, sonst kannst du es mit der "zeitgesteuerten" Tastenabfrage vergessen.
Alle delays blockieren deinen Sketch.
blackperil:
Wie kann ich die den alle raushauen? Die LEDs sollen halt ein nach dem anderen gesteuert werden.
Für jeden Ablauf eine Timersteuerung basteln?Ich habe mir theoretisch eine Zustandsmaschine überlegt bzw. auf Papier gebracht.
Bin mir nur nicht so sicher ob ich die ganzen Funktionen wie ich sie z.B. aus CodeSys kenne, anwenden kann.
Wer schreibt denn "raushauen", die müssen durch die Funktion "millis" ersetzt werden.
Und ja, eine Zustandsmaschine ist richtig, aber ohne delay.
Auch wenn du es schon weißt, sieh dir BlinkWithoutDelay an, da wird genau beschrieben, wie das ablaufen soll.
Das in diesem Beitrag von mir ursprünglich gepostete kleine Beispielprogramm "Hochdimmen und Runterdimmen einer LED nach der Programmlogik einer ("Finite-State-Machine ohne delay") anstelle der Programmlogik eines ("Idiotenprogramm mit delay") habe ich heute wieder gelöscht, weil das Programmbeispiel den Themenstarter offenbar nicht dazu animiert hat, hier in eine Diskussion darüber einzutreten, wie man längerlaufende Steuersequenzen und zeitlich zu steuernde Abläufe mit der Programmlogik einer Finite-State-Machine ohne delay realisieren kann, sondern dazu geführt hat, dass ich mit einer "privaten Mitteilung" über den Messagedienst des Forums angeschrieben werde, mit einem Angebot "Gegenwert einer Kiste Bier gegen die Programmierung eines Programmcodes frei von delay für die Lichtsteuerung aber mit zusätzlicher Drucktastensteuerung bis Freitag".
Kein Interesse. Null Bock.
Beispielprogramm und erläuternder Beitrag wieder gelöscht. Und ab dafür
BYE
For Schleife ist der falsche Ansatz, loop ist ja schon deine Schleife.
Und Programmieraufträge gegen Geld sind hier nicht gerne gesehen, auch nicht per PN. Hier gibt es hauptsächlich Hilfe zur Selbsthilfe
blackperil:
Geht das wirklich nicht ohne die DELAY Geschichte zu ersetzen?
Nein. delay macht immer Probleme, wenn man nicht genau weiss, was man tut.
Google mal nach den themen Nachtwächter Erklärung und Endlicher Automat hier im Forum.
Habe ich es richtig verstanden, dass man die Anweisungen direkt in die Zustände programmieren muss?
Wenn man wüsste oder zumindest ahnte, was du mit "die Anweisungen direkt in die Zustände programmieren" meinst ...
Im Forum habe ich Programme gesehen die ausserhalb des LOOP stehen.
Ganz vereinfacht: In C / C++ gibt es nur Funktionen. Die werden definiert und irgendwo aufgerufen.
Bei Arduino gibt es noch ein paar unsichtbare Funktionen:
void main() { // hier startet der Controller nach Reset / Spannungswiederkehr
init(); // diese Funktion ist auch unsichtbar und initialisiert alles nötige ... (egal erstmal)
setup(); // wird einmal aufgerufen
while (true) {
loop(); // dies wird immer wieder aufgerufen
}
// die Schleife wird nie verlassen
}
Du schreibst setup() und loop().
Dort kannst du auch andere Funktionen aufrufen. z.B. status= digitalRead(pin);
Solche Funktionen wie digitalRead kannst du auch selber definieren/schreiben (ausserhalb von setup oder loop) und dann beliebig ufrufen. Der Aufruf steht dann innerhalb von anderen Funktionen. Letztlich und evtl. indirekt in setup() oder in loop().
Klar ? Oder noch mehr verwirrt jetzt ?
Hallo,
Zeile 107: Semikolon falsch, dass hat eine komplett andere Auswirkung, immer daran denken
Und das durcheinander deiner Zustände gefällt mir auch nicht, vielleicht verlierst du dadurch den Überblick. Für sowas gibts enum.
typedef enum {
BEREIT, S_PROGRAMMSTART, ALLELEDSGRUEN, S_COUNTDOWNSTART, S_FLASH, S_TURBOMODUS_ALTERNATIV, S_FLASH_ALTERNATIV
} state; // Name vom neuen Datentyp
state Zustand = BEREIT; // Variable 'Zustand' vom Datentyp 'state' initialisiert mit Wert 'BEREIT'
// Zustandsmaschine
switch (Zustand)
{
und drück mal unter Werkzeuge auf autom. Formatierung.
Hallo,
du prüfst irgendeine Zeitdifferenz mit ts.
Nun suche mal nach ts im Sketch wo die definiert/initialisiert wird.
Was stellst du fest?
übrigens, den cast (unsigned long) kannste an der Stelle weglassen.
Hallo,
ich habe den Sketch aus #15 (für meine neun LEDs, siehe Avatar-Bild) etwas überarbeitet, damit ein Ablauf sichtbar wird:
#include <Adafruit_NeoPixel.h>
#include <Bounce2.h>
Bounce debouncer = Bounce();
#define PIN 6
#define NUM_PIXELS 9
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_RGB + NEO_KHZ800);
//32-Bit Variablen für Farben
const uint32_t red = strip.Color(255, 0, 0);
const uint32_t green = strip.Color(0, 255, 0);
const uint32_t white = strip.Color(255, 255, 255);
const uint32_t blue = strip.Color(0, 0, 255);
const uint32_t sw = strip.Color(0, 0, 0);
const byte S_ALLELEDSGRUEN = 1; //State 1: Alle LEDs grün warten auf Taster Aktion
const byte S_COUNTDOWNSTART = 2; //State 2: Taster wurde betätigt -> Alle LEDs nacheinander auf rot COUNTDOWN
const byte S_FLASH = 3; //State 3: Wenn bestimmte Zeit (COUNTDOWN) abgelaufen dann alle LEDs weiß für eine bestimmte Zeit dann zurück zu State 1
const byte S_TURBOMODUS_ALTERNATIV = 4; //State 4: Taster wurde 5 Mal in Zeit X betätigt -> Alle LEDs nacheinander auf rot und wieder von vorne > Wenn innerhalb X keine Taster Betätigung registriert wird dann wieder zu State 1
const byte S_FLASH_ALTERNATIV = 5; //State 5: Wenn Taster betätigt dann alle LEDs weiß für eine bestimmte Zeit dann zurück zu State 4
// Pin numbers
const int ausloeser = 2;
const int taster = 3;
void setup()
{
Serial.begin(9600);
Serial.println("Anfang");
strip.begin();
strip.setBrightness(20); // Helligkeit der LEDs
strip.show();
pinMode(ausloeser, OUTPUT);
pinMode(taster, INPUT_PULLUP);
debouncer.attach(taster);
debouncer.interval(30);
// Selbsttest
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, white);
}
strip.show();
delay(200);
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, red);
}
strip.show();
delay(200);
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, green);
}
strip.show();
delay(200);
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, blue);
}
strip.show();
delay(200);
}
void loop()
{
debouncer.update();
static int state = S_ALLELEDSGRUEN ;
static unsigned long ta, ts;
static byte zaehler = 0;
ta = millis();
switch (state) // Zustandsmaschine
{
case S_ALLELEDSGRUEN: // Alle LEDs auf grün umstellen und auf Taster reagieren wenn betätigt
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, green);
}
if ( debouncer.fell() ) { // Taste gedrückt
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, sw);
}
zaehler = 0;
state = S_COUNTDOWNSTART;
}
break;
case S_COUNTDOWNSTART: // Alle LEDs auf rot
// PROGRAMMIEREN ! Wenn der Taster 5x hintereinander gedrückt wird dann springe zu S_TURBOMODUS_ALTERNATIV
if ( debouncer.fell() ) { // Taste gedrückt
zaehler++;
}
if (ta - ts >= 300) { // Countdown
ts = ta;
if (colorWipe(red))
{
ts = ta;
if (zaehler >= 5) {
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, sw);
}
state = S_TURBOMODUS_ALTERNATIV;
} else {
state = S_FLASH;
}
}
}
break;
case S_FLASH: // If two seconds have passed, then move on to the next state.
if (!digitalRead(ausloeser)) {
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, white);
}
}
digitalWrite(ausloeser, HIGH);
if (ta - ts >= 2000) // "Flashzeit" in Millisekunden
{
digitalWrite(ausloeser, LOW);
state = S_ALLELEDSGRUEN;
}
break;
case S_TURBOMODUS_ALTERNATIV:
if (ta - ts >= 150) { // Countdown
ts = ta;
if (colorWipe(blue))
{
state = S_ALLELEDSGRUEN;
}
}
break;
case S_FLASH_ALTERNATIV:
for ( int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, white);
}
if (ta - ts >= 2000) // "Flashzeit" in Millisekunden
{
state = S_ALLELEDSGRUEN;
}
break;
} // end of switch
strip.show();
} // end of loop
bool colorWipe(uint32_t farbe) {
static uint16_t currentPixel = 0; // what pixel are we operating on
strip.setPixelColor(currentPixel, farbe);
currentPixel++;
if (currentPixel > NUM_PIXELS) {
currentPixel = 0;
return true;
}
return false;
}
EDIT: Variable zaehler initilisiert.
Die Version in #20 habe ich etwas ergänzt.
blackperil:
Bounce?War es das was gefehlt hat um die Probleme beim Zustand zu lösen?
Nicht alleine, aber sicher von zentraler Bedeutung. Du hast mittels taster_inaktiv sowas probiert. Das ist durchaus ein gangbarer Weg, allerdings steiniger als die Verwendung der Bibliothek, daher habe ich mich im Sinne einer schnellen Lösung dafür entschieden.
Viele andere Änderungen fallen in die Kategorie Kosmetik. Da hier aber ein paar mitlesen, möchte ich dann schon das gleich mit ändern.