wie man sieht wird die Led mit "On" eingeschaltet, mit "Off" aus und mit "Blink soll sie blinken, mein Problem ist jetzt wie kann ich die Subroutine wieder beenden?
s-fr:
...
wie man sieht wird die Led mit "On" eingeschaltet, mit "Off" aus und mit "Blink soll sie blinken, mein Problem ist jetzt wie kann ich die Subroutine wieder beenden?
Du könntest beim Aufruf der blink-Funktion übergeben, wie oft oder wie lange geblinkt werden soll. In der Funktion prüfst Du dann, ob oft oder lange genug geblinkt wurde und kehrst mit return; zum aufrufenden Programm zurück.
Oder Du programmierst eine Schleife, anstatt goto zu verwenden. Dann wird entsprechend oft geblinkt und wenn die Schleife beendet ist, wird im Hauptprogramm weitergemacht. Goto ist eh verpönt.
Die Subroutine, wie du sie nennst, heißt "Funktion" und wird, wenn keine blockierende Schleife oder was ähnliches eingebaut ist, automatisch verlassen.
Das "goto Start" kannst du dir sparen.
Die Funktion sollte endlos ausgeführt werden, bis man sie eben beendet.
Dieses Vorgehen solltest du dir gar nicht erst angewöhnen. Du hast in loop() schon eine Schleife. In der kannst du eine Funktion ständig aufrufen und wenn nichts zu tun ist wird sie sofort beendet und kehrt nach loop() zurück. So kann man dort noch andere Dinge tun. Wenn das schnell geschieht (also keine Verzögerungen in der Funktion sind) kann so mehrere Dinge quasi-gleichzeitig erledigen.
In deinem Fall willst du wie so oft einen Zustandsautomaten. Du fragst also die serielle Schnittelle ab und je nach Eingabe wird eine Zustandsvariable gesetzt. Die sagt dir was in diesem loop() Durchlauf zu tun ist, z.B. Blinken. Und je nach dem wird eine andere Funktion aufgerufen.
So kannst du dann neben dem Blinken noch die serielle Schnittstelle ständig abfragen. Wenn du das nicht tust bist du in der Funktion gefangen und kannst den Zustand nicht mehr ändern
Gibt es keine einfache Methode eine Funktion zu schließen?
ElEspanol:
Das ist aber immer noch nicht, was der TO will.
Er hat eigentlich die falsche Frage gestellt.
Ja, das sehe ich jetzt genauso.
In dieser einfachen Form wurde ich die "Blink-Funktion" immer aus der Loop aufrufen und den Aufruf über eine if-Abfrage einer Status Variable steuern.
Und wenn der TO dann noch die delays durch eine Funktion mit millis ersetzt (Beispiel "BlinkWithoutDelay"), dann wird auch der Sketch nicht blockiert.
Aber ich kann nur die gestellte Frage beantworten.
Je ungestellter die Frage, desto wahrscheinlicher, dass ich mit der Antwort daneben liege.
Leider ist meine Kristallkugel gerade in Urlaub.
(hat sie auch dringend nötig)
OK, ich kann vermuten....
Dann:
s-fr möchte eine, auf kooperativem Multitasking beruhende, Ablaufsteuerung bauen.
Tipp:
Return ist dabei sehr hilfreich!
Egal ob implizit, oder explizit.
Genau genommen will er ja über Serial steuern, ob die LED den Zustand On, OFF, oder Blinken haben soll. Die LED soll also wohl solange blinken, bis ain anderes Kommando eintrifft.
Somit braucht er BlinkWithoutDelay und dabei jeden Blink-Zyklus von der Loop aus aufgerufen.
ElEspanol:
Das ist aber immer noch nicht, was der TO will.
Ja, aber was er will ist Murks. Das mag vielleicht funktionieren wenn man die richtige Syntax verwendet ist aber vom Design her keine vernünftige Lösung.
Außerdem blinkt es dann vielleicht, aber die Abfrage der seriellen Schnittstelle geht nicht flüssig
Wenn die Funktion Blink() wenig Zeit braucht, wird es ganz einfach.
(Wenn Blink gar keine Zeit braucht, wäre es noch eleganter, aber das lassen wir vorerst mal weg).
Wenn das Kommando über Serial einfacher ist, wird es noch einfacher.
Ich schlage mal vor, der Sketch reagiert auf die Zeichen { '0' , '1' , 'B' } und ignoriert alles andere.
const int INTERVALL = 500; // Blinkfrequenz
byte ledStatus; // 0 = aus, 1 = an, 2 = blinkend an, 3 = blinkend aus
void loop() {
while (Serial.available()) {
int c = Serial.read();
switch (c) {
case '0': ledStatus = 0; break;
case '1': ledStatus = 1; break;
case 'B':
case 'b': ledStatus = 2; break;
default: break; // alles andere auch ignorieren
}
}
if (ledStaus > 1) blink();
else digitalWrite(13, ledStatus); // AN oder AUS Dauerlicht
}
void blink() {
// Primitiv-Version: kehrt erst nach Ablauf einer Blink-Phase zurück
// Experten verstehen BlinkWithoutDelay
if ( ledStatus == 2) {
digitalWrite(13, HIGH);
ledStatus = 3;
} else {
digitalWrite(13, LOW);
ledStatus = 2;
}
delay (INTERVALL);
}
@s-fr: Du hattest wohl noch eine falsche Vorstellung des Begriffs "Programm".
Das Programm eines Controllers läuft nach dem Start "ewig".
Und wofür die Funktion loop() gedacht ist. (loop() ist nicht main() und sollte nicht ewig laufen, sondern optimalerweise gar keine Zeit brauchen)
Bzw. wie andere eigene Funktionen dabei mitspielen.
Die auch wenig (bis optimalerweise gar keine) Zeit brauchen.
Hi s-fr,
der code von michael_x funktioniert hervorragend.
Ich habe Dir hier noch den Code, den Du an Anfang gepostet hast angepasst und ergänzt. Dieser basiert
weiterhin auf den Befehlen 'On', 'Off' und 'Blink'. Ausserdem hab ich das void Blink() ohne delay gemacht,
wodurch das Programm schneller auf Befehlsänderung während dem Blinken reagiert. Ist wichtig bei langem Interval = niedrigen Blinkfrequenz.
#define LEDpin 13 // Pin andem die LED angeschlossen ist
unsigned long interval = 500; // interval gibt an, wie lange LED 'on' bzw. 'off' ist beim Blinken
unsigned long intervalStart = 0; // IntervalStart merkt sich den Start des Intervals für Test ob Intervalzeit abgelaufen ist
bool blinken = false; // Merker ob für Blinken aus/ein (false = kein Blinken)
bool ledStatus = 0; // Status der LED beim Binken (0 = LED ist aus)
String input; // Nimmt das Komanndo über die Serial auf.
void setup() {
// put your setup code here, to run once:
pinMode(LEDpin, OUTPUT); // LEDPin als Ausgang definieren
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
input = "";
while (Serial.available() > 0) {
input += (char) Serial.read();
delay(5);
if (input == "On") {
digitalWrite(LEDpin, HIGH); // LEDpin ist oben als Pin 13 definiert
blinken = false; // kein Blinken
}
if (input == "Off") {
blinken = false; // kein Blinken
digitalWrite(LEDpin, LOW); // LEDpin ist oben als Pin 13 definiert
}
if (input == "Blink") {
blinken = true; // Blinken einschalten
}
}
if (blinken == true) { // Blinken ist aktiv
if (millis() - intervalStart > interval) Blink(); // Wenn das Interval abgelaufen ist, gehe Blinken
}
}
void Blink() {
ledStatus = !ledStatus; // Wenn led vorher aus, dann led ein, wenn led vorher ein, dann led aus
digitalWrite(LEDpin, ledStatus); // LED ein- oder ausschalten
intervalStart = millis(); // Startzeit für nächstes Interval merken
}
Ist sicher nicht die aller eleganteste Lösung, ich wollte aber bewusst bei dem bleiben, was in Deinem Sketch bereits funktioniert hat. Lediglich die Definition des Pin's an dem die LED hängt, hab ich flexibler gestaltet.