blink without delay ist ja schon oft hilfreich gewesen, bei meinem aktuellen Problem hänge ich aber dennoch.
Ein Temperatursensor liefert mir die Temperatur eines Wärmeschrankes und wenn diese zwischen 25 und 40°C ist soll die Heizspirale für 1 Minute an und dann für 3 Minuten aus sein.
Die restlichen Aktionen des Sketches (Thingspeak-Upload und Temperaturmessung) sollen ganz normal weiterlaufen, daher möchte ich nicht für die 3 Minuten in der Schleife “festhängen”, sondern mittels Abfrage einfach nur Prüfen, ob die Heizspirale schon 3 Minuten aus ist, wie realisiere ich das am Besten?
Irgendwie habe ich einen Knoten im Hirn und kriege es nicht hin die notwendigen Variablen und Abfragen dieser richtig hintereinander zu biegen.
Bislang sieht der relevante Teil meines Sketches leider nur so aus (PIN 6 steuert das Relais der Heizleitung):
if (celsius < 20) { //bei Temperaturen <20°C soll Dauerheizung möglich sein
digitalWrite(6, HIGH);
}
if (celsius >20) { //ab 20°C Heizung für 1 Minute an und 3 Minuten aus
if (celsius < 40) {
//hier so der Code zum Einschalten des Relais für 1 Minuten und Ausschalten für 3 Minuten hin
}
if (celsius > 40) {
digitalWrite(6, LOW);
}
}
sondern mittels Abfrage einfach nur Prüfen, ob die Heizspirale schon 3 Minuten aus ist, wie realisiere ich das am Besten?
Beim Abschalten den aktuellen millis() Wert abspeichern und evtl. eine Zustandsvariable (ob an oder aus). Dann kannst du einfach abfragen ob die Zeit schon abgelaufen ist
Das ist doch genau das Probel, Welches mit 'Blink without delay' umgangen wird.
Deshalb befürchte ich, daß Dir der Grundgedanke dahinter doch noch nicht so ganz klar geworden ist.
Wie meine Vorschreiber schon äußerten, Du prüfst IMMER nur, ob ein Zeitpunkt erreicht wurde, wenn, arbeitest Du diesen Schritt ab und merkst Dir erneut, daß Du 'gearbeitet hast' - also den aktuellen millis()-Wert wieder aufschreiben.
Beim nächsten Loop-Durchlauf wird wieder genau die gleiche Prüfung durchgeführt, dieses Mal ist aber erst eine Millisekunde vergangen, weshalb die Abarbeitung hier erst wieder greift, wenn die Zeit um ist.
On Du Dir jetzt millis() nur merkst, wenn Du die Heizung einschaltest oder auch beim Umschalten, ist Dir überlassen - ändert dann aber die Abfragen nach der vergangenen Zeit,
Wenn Da Probleme auftauchen, können wir uns Das aber ebenfalls gerne Mal anschauen.
warum nimmst du keinen PID-Regler mit Relais-Steuerung. Damit kannst du die Temperatur genau auf einen festen Wert einstellen und musst nicht mit Intervallen arbeiten.
Das habe ich zuerst auch gemacht (unter 40° heizen, sonst abschalten). Das hatte aber zur Folge, dass die Heizung insgesamt so lange lief, dass die Luft im Wärmeschrank auf ca. 50°C erhitzt wird und durch die verzögerte Reaktion des Temperatursensors die Werte dann zwischen 37° und ca 50°C schwanken. Durch die rel. kurze Einschaltzeit von 1 Minute soll die Wärme im Schrank langsamer ansteigen und dann konstanter bei ca. 40° gehalten werden. Das genaue Verhältnis zwischen Ein- und Ausschaltzeit werden ich dann in längeren Versuchsreihen ausprobieren.
Neben dem Blinken mit millis() brauchst Du noch eine Schrittkette (endlicher Automat, finite state machine). Ich mag die mit switch/case. Ist das was für Dich?
const byte pinEingang = A0;
const byte pinAusgang = 6;
const uint32_t einIntervall = 3000, ausIntervall = 5000, blinkIntervall = 200;
uint32_t aktMillis, schaltMillis, blinkMillis;
enum {WARTEN, EIN, AUS};
byte celsius, schritt = WARTEN;
bool einmal;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pinAusgang, OUTPUT);
}
void loop() {
aktMillis = millis();
switch (schritt)
{
case WARTEN:
celsius = analogRead(A0) / 10;
if (celsius < 20) { //bei Temperaturen <20°C soll Dauerheizung möglich sein
digitalWrite(pinAusgang, HIGH);
}
else if (celsius > 40) {
digitalWrite(pinAusgang, LOW);
}
else if (celsius > 20) { //ab 20°C Heizung für 1 Minute an und 3 Minuten aus
einmal = true;
schritt = EIN;
}
break;
case EIN:
if (einmal)
{
einmal = false;
digitalWrite(pinAusgang, HIGH);
schaltMillis = aktMillis;
}
if (aktMillis - schaltMillis >= einIntervall)
{
einmal = true;
schritt = AUS;
}
break;
case AUS:
if (einmal)
{
einmal = false;
digitalWrite(pinAusgang, LOW);
schaltMillis = aktMillis;
}
if (aktMillis - schaltMillis >= ausIntervall)
{
einmal = true;
schritt = WARTEN;
}
break;
}
if (aktMillis - blinkMillis >= blinkIntervall) // Herzschlag als Beweis für blockadearmes Programmieren
{
blinkMillis = aktMillis;
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
}