Hallo,
ich bin grad am programmieren meines Arduino Uno für eine Kameraschiene.
Jedoch bin ich grad auf das Problem gestoßen, dass ich die zeitlichen Abläufe nicht über die delay()-Funktion machen kann, da beispielsweise so keine Tasteneingaben mehr möglich sind.
Mein Ablauf schaut wie folgt aus:
- Taster schaltet die Funktion ein
- Ausgang A (Motor) wird für eine bestimmte Zeit 1 eingeschaltet
- Nach Ablauf dieser Zeit 1, wird eine Verzögerung Zeit 2 aktiviert
- Nach Ablauf von Zeit 2 wird Ausgang B (DSLR) für eine bestimmte Zeit 3 aktiviert
- Nach Ablauf von Zeit 3 folgt eine Verzögerung von Zeit 4 und das Programm wiederholt sich
Ich bin Arduino-Anfänger und habe zunächst die delay()-Funktion als Verzögerung eingesetzt. Da jedoch immer ein delay aktiviert ist, kann ich keine Eingaben über meine Taster machen.
Wie kann ich am einfachsten die o.g. Funktion realisieren? Ich hatte mir schon die BlinkWithoutDelay und ein paar timer-Libraries angeschaut. Jedoch zwar nichts dabei, was bei mehreren Timern einigermaßen übersichtig bzw. einfach aussau.
Am besten vergegenwärtigt man sich das Verhalten des Controllers mit einem Endlichen Zustandsautomaten (Endlicher Automat – Wikipedia). Bedingungen für Zustandswechsel sind dann nicht nur externe Ereignisse, sondern könnten dann auch abgelaufene Zeitperioden sein. Beispiel: Ausgangszustand sei A. Nach 5 Sekunden soll Zustand B eingenommen werden: Bei betreten von Zustand A berechnet man die neue Zielzeit aus der aktuellen Zeit plus 5 Sekunden. Wenn die Zielzeit erreicht ist, wird der Zustand auf B gewechselt.
Grüße,
Oliver
uwefed
3
Das BlinkWithoutDelay-Beispiel hatte ich mir schon angeschaut.
Ich als absoluter Programmier-Anfänger, weiß aber nicht, wie ich z.B. unterschiedliche Zeiten für das Ein/Aus einstellen kann. Das Beispiel schaltet ja die LED 1 Sekunde aus, und 1 Sekunde ein. Ich bräuchte aber beispielsweise 1 Sekunden ein und 5 Sekunden aus.
Außerdem verstehe ich nicht, wie ich mehrere dieser Timer aktiviere und benutze.
Für eine normales Ein/Aus mag das Beispiel zwar geeignet sein. Sobald aber mehrere Timer genutzt werden sollen, finde ich, dass das Beispiel viel zu wenig beschrieben ist.
system
5
Mach dir eine Time Mashine. Siehe hier, zweites Post von Oben von meiner wenigkeit.
http://arduino.cc/forum/index.php/topic,123929.0.html
uwefed
6
Das BlinkWithoutDelay-Beispiel funktioniert folgendermaßen.
Die Funktion millis() gibt die Millisekunden zurück, die vergangen sind seitdem Arduino eingeschaltet oder resetiert wurde.
Du speicherst die Startzeit ab un kontrolliest durch subtrahieren der Startzeit von der jetztzeit ob die Wartezeit schon vorbei ist.
Wenn Du mehrere solche Abläufe kontrollieren willst ( 2 LED unterschiedlich blinken) dann verwende mehrere variablen für die Startzeiten.
Zu Deinem Problem: Ich bräuchte aber beispielsweise 1 Sekunden ein und 5 Sekunden aus. Ändere das http://arduino.cc/en/Tutorial/BlinkWithoutDelay BEispiel folgendermaßen:
intervallon = 1000;
intervalloff = 5000;
...
void loop()
{
unsigned long currentMillis = millis();
if(ledState == HIGH && currentMillis - previousMillis > intervalon ) {
previousMillis = currentMillis;
ledState = LOW;
digitalWrite(ledPin, ledState);
}
if(ledState == LOW && currentMillis - previousMillis > intervaloff) {
previousMillis = currentMillis;
ledState = HIGH;
digitalWrite(ledPin, ledState);
}
}
Grüße Uwe
... und außerdem brauchst du wohl eine Variable, die dir sagt in welchem Schritt du grade bist.
int Schritt;
unsigned long Dauer;
unsigned long previousMillis;
...
void loop ()
{
unsigned long currentMillis = millis();
...
if ( currentMillis - previousMillis > Dauer )
{
Schritt++; // nächster Schritt
switch (Schritt)
{
case 1:
// Motor Ein
Dauer = 5000; // sec warten
break;
case 2:
// Motor aus
Dauer = 1000; // Pause zeit 2
break;
// .... Beliebig weitere Schritte definieren
default:
Schritt = 0;
Dauer = 1; // Schrittfolge wieder von vorn
}
previousMillis = currentMillis; // "Delay" neu starten
}
// hier evtl. Tasterabfragen, um die Schrittfolge zu ändern oder Wartezeiten abzubrechen o.ä.
}
Edit: hoppla, Code Tag vergessen ; )
uwefed
8
michael_x:
... und außerdem brauchst du wohl eine Variable, die dir sagt in welchem Schritt du grade bist.
Die hatte ich ja:
ledState
Grüße Uwe
Die hatte ich ja:
ledState
Schon richtig, aber das Problem mit "Blink without Delay" ist, dass die Leute sagen: prima, aber an/aus Blinken reicht mir nicht...
Und eine "State-Machine" ist auch richtig, aber abschreckend ...
@Michael: Vielen Dank, dein Code ist genau das was ich gesucht habe, funktioniert genauso wie ich es wollte.
Jedoch habe ich da noch eine Frage:
Die Funktion soll nur dann ablaufen, wenn der Einschalter auf 1 steht und der Endlageschalter auf 0. Sobald sich einer dieser Werte ändert, soll der Ablauf gestoppt werden.
Mein Ansatz mit der if-Bedingung:
if (endlageValue == 0 && einaus == 1)
{
...
}
Wenn ich den Endschalter betätigt (=1) und Einschalter(einaus=1), passiert nichts. Wenn ich den Endschalter loslasse, startet die Funktion. Also genau so wie ich es will. Wenn jedoch die Funktion abläuft und ich den Endschalter oder Einschalter betätige, dann läuft die Funktion immer noch weiter bzw. wird am momentanen Schritt gestoppt und der Schritt läuft im Dauermodus.
Was muss ich ändern, damit die Funktion beim Ändern der Bedingungen sich resettet bzw. stoppt?
uwefed
11
Hofdiener, bringe er mir die Kristallkugel.

BlueGene bitte den gesamten modifizierten Sketch.
Grüße Uwe
Das Posten der Definition der Variablen und des setup kann ich verzichten, oder ist das auch von Bedeutung?
void loop()
{
unsigned long currentMillis = millis();
if (modus == 1 && einaus == 1)
{
if (endlageValue==0)
{
if (currentMillis - previousMillis > Dauer )
{
Schritt++; // nächster Schritt
switch (Schritt)
{
case 1:
analogWrite(motoreinaus, 255);// Motor - Leistung 100%
digitalWrite(rechtslauf, LOW);// Motor - Rechtslauf aus
digitalWrite(linkslauf, HIGH);// Motor - Linkslauf ein
digitalWrite(led4, LOW);
Dauer = 1000; // sec warten
break;
case 2:
analogWrite(motoreinaus, 127);// Motor - Leistung 50%
digitalWrite(led2, HIGH);
Dauer =1000; // Pause zeit 2
break;
case 3:
digitalWrite(led2, LOW);
digitalWrite(led3, HIGH);
analogWrite(ein, 255); // Motor - Leistung 100%
Dauer = 1000;
break;
case 4:
digitalWrite(led3, LOW);
digitalWrite(linkslauf, LOW);// Motor - Linkslauf aus
digitalWrite(motoreinaus, LOW);// Motor Aus
digitalWrite(led4, HIGH);
Dauer=1000;
break;
default:
Schritt = 0;
Dauer = 1; // Schrittfolge wieder von vorn
}
previousMillis = currentMillis; // "Delay" neu starten
} // if (currentMillis - previousMillis > Dauer )
} // if (endlageValue==0)
} // if (modus == 1)
} // loop-Ende
Wenn ... ich den Endschalter ... betätige, dann läuft die Funktion immer noch weiter
ja klar, das hast du so programmiert:
...
if (endlageValue==0)
{
....
} // if (endlageValue==0)
} // if (modus == 1)
} // loop-Ende
-- Was soll er machen, wenn der Endlage-Schalter erreicht ist ?
-- Und wo würdest du das einbauen ?
2 Fragen, die du selbst beantworten musst, bzw. können solltest .
Falls es dir zur 2. Frage hilft:
if (bedingung) { ... } gibt es auch als if (bedingng) { ... } else { ... }
Danke nochmal, jetzt funktioniert endgültig wie es soll (hoff ich mal^^)