loop abschnitt umgehen

Hi, ich habe mir einen code geschrieben bei dem gleichzeitig die Temperatur gemessen wird und der sich aller 24 Stunden dreht . Aber jetzt habe ich das Problem das nur einmal die Temperatur gemessen wird, und dann wartet der Arduino erst die 24 Stunden ab und misst dannach erst wierder die Temperatur. Wie muss man den code umschreiben dass die Temperatur aller 3 sekunden gemessen wird, und der Servo aller 24 Stunden sich einmal dreht. (Die Temperatur wird auf einem 2x16 LCD Display ausgegeben.

Hier der Code:

#include <LiquidCrystal.h>

#include <Servo.h> 

 Servo servoblau;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);



/* Temperatur Berechnung */
int sensorAnalogPin = A0;  // A0
int iSensorWert = 0;
float fVoltage = 0.0;
float fTemperature = 0.0;

void setup() {
  // set up the LCD's number of columns and rows: 

 
  servoblau.attach(8);

  
  lcd.begin(16, 2);
    
  Serial.begin(9600);  

}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):

        
  iSensorWert = analogRead(sensorAnalogPin); // A0
 
  /* Voltage */
  fVoltage = (iSensorWert / 1024.0) * 5.0;
 
  
  /* Temperatur */
  fTemperature = (fVoltage - 0.5) * 100;
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("Luft: ");
  lcd.print(fTemperature); 
  lcd.print("C");
  lcd.setCursor(0, 1);
  lcd.print("Futter 18:00 Uhr");
   

  Serial.print("Temp. C=");
  Serial.println(fTemperature);    

  delay(2000);  

    servoblau.write(0);
    delay(1000);
    servoblau.write(180);
    delay(86400000);
    servoblau.write(0);
    delay(0.10);

}

Das delay() muss weg.
Siehe dazu: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Suche mal hier im Forum nach "endlicher Automat". Solche Ablaufsteuerungen werden hier gerade recht häufig behandelt.

Aber wenn ich das delay() weglasse dreht sich der servo sich ja nicht mehr aller 24 h.

Tomuino:
Aber wenn ich das delay() weglasse dreht sich der servo ja nach 24 h nicht mehr

Warum sollte er das nicht tun?

Im Gegenteil:
Ich bin mir sicher, dass das geht.

BlinkWithoutDelay zeigt dir, wie eine LED ohne Delay blinkt.
Dein Servo ist auch so was, wie ein Blinker.
Nur langsamer

Wenn du das wirklich dauerhaft willst, ist das sowieso Quark. Der Arduino Takt ist nicht so genau. Der driftet dir irgendwann weg.

Der Code war dafür gedacht einmal 24 Stunden zu warten und dann einen Reset durchzuführen. Wenn du das ständig ausführst brauchst du eigentlich eine Real Time Clock damit du die Zeit zuverlässig hast.

schau mal nach (Task) Scheduler z:b. TimeAlarm der arbeitet mit einer RTC

Mir wäre ein Sketch (den von mir verwendeten, am besten umschreiben) ganz lieb, weil ich mich mit den "Task" Sachen noch nicht so gut auskenne.

Schau Dir mal den Beispielsketch BlinkWithoutDelay https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay angeschaut?
Grüße Uwe

Eine wirklich ganz einfache und nicht “saubere” Lösung, da es passieren kann dass eine Funktion/ ein Zustand mehrfach ausgeführt wird, oder er gar ganz übergangen wird. Auch wird es nach einigen Tagen Laufzeit problematisch, da dann die Funktion millis() an ihre max. Zahlengöße stößt und wieder bei o anfängt. Aber vielleicht erst mal eine kleine Hilfe für Dich auf die schnelle :wink:

#include <LiquidCrystal.h>

#include <Servo.h>

 Servo servoblau;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);



/* Temperatur Berechnung */
int sensorAnalogPin = A0;  // A0
int iSensorWert = 0;
float fVoltage = 0.0;
float fTemperature = 0.0;

const unsigned long DELAY_1 = 2000;     // Pause bzw. Periode 1 (2sec)
const unsigned long DELAY_2 = 86400000; // Pause bzw. Periode 2 (24h)
const unsigned long DELAY_3 = 60000;    // Pause bzw. Periode 3 (1min)

void setup() {
  // set up the LCD's number of columns and rows:

 
  servoblau.attach(8);

  
  lcd.begin(16, 2);
    
  Serial.begin(9600);  

}

void loop() {
  
  
  if(millis() % DELAY_1 == 0){              // wird alle 2 sec ausgeführt
    /* Temperatur */
    iSensorWert = analogRead(sensorAnalogPin); // A0
    /* Voltage */
    fVoltage = (iSensorWert / 1024.0) * 5.0;
    
    fTemperature = (fVoltage - 0.5) * 100;
    lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print("Luft: ");
    lcd.print(fTemperature);
    lcd.print("C");
    lcd.setCursor(0, 1);
    lcd.print("Futter 18:00 Uhr");
    

    Serial.print("Temp. C=");
    Serial.println(fTemperature);
    delay(1);                           // hilfs-Delay um mehrfach-Auslösung zu verhindern
  }  

  if(millis() % DELAY_2 == 0){            // wird alle 24h ausgeführt

    servoblau.write(0);
    delay(1000);
    servoblau.write(180);
  }

  if(millis() % DELAY_3 == 0){

    // Code hier wird alle 1 Minute ausgefürt...
    delay(1);                           // hilfs-Delay um mehrfach-Auslösung zu verhindern
  }


}
const unsigned long DELAY_1 = 2000; 

if(millis() % DELAY_1 == 0){       
      // wird alle 2 sec ausgeführt
    delay(1);  // hilfs-Delay um mehrfach-Auslösung zu verhindern

}

Der Überlauf von millis() macht überhaupt nichts aus, das delay aber schon.
Ist zwar richtig mit der mehrfach-Auslösung, stört aber die anderen if (millis() ... ) Abfragen.

Richtig wäre pro Zyklus eine unsigned long Variable, in der die letzte "Auslösung" gemerkt wird.
Dann kann loop() sowohl ofters als auch weniger als ein mal je ms drankommen.

Ich habe mal ein Video zu meinen Problem gemacht :wink:

Mach erst einmal sämtliche delays raus. Die Aufgabenbewältigung kann dann wie folgt aussehen:

#define INTERVAL_TASK0 2000UL
#define INTERVAL_TASK1 86400000UL
#define INTERVAL_TASK2 60000UL

void loop(){
static unsigned long lastMillis_task0;
static unsigned long lastMillis_task1;
static unsigned long lastMillis_task2;


if(millis() - lastMillis_task0 >= INTERVAL_TASK0) {
lastMillis_task0 = millis(); 

// do something
}


if(millis() - lastMillis_task1 >= INTERVAL_TASK1) {
lastMillis_task1 = millis(); 

// do something
}


if(millis() - lastMillis_task2 >= INTERVAL_TASK2) {
lastMillis_task2 = millis(); 

// do something
}

}

Bei ">=" bedarf es dann auch kein "Hilf"delay mehr. Entweder ist die Zeit gleich oder größer. Trifft der Fall einmal zu, wird lastMillis wieder auf millis() abgeglichen und bei der nächsten Überprüfung ist dieser zwangsläufig kleiner und somit unwahr.

Hallo,

Edit: manchmal überschneidet man sich ... :slight_smile: jetzt sollte er es verstehen können ...

um sowas mit den übelsten delays zu umgehen

delay(2000);  

    servoblau.write(0);
    delay(1000);
    servoblau.write(180);
    delay(86400000);
    servoblau.write(0);
    delay(0.10);

mußte Dich wirklich nochmal mit millis genauer beschäftigen. Wenn Du das verstanden hast, kannste alles was du willst zu jeder Zeit schalten für so lange wie du möchtest ohne dabei die loop zu blockieren.

Ein Bsp. gebe ich Dir mit. Das läßt eine LED blinken. Wie gesagt, wenn du die Funktionsweise verstanden hast, ist es vollkommen egal was Du damit machst. Ob eine LED blinkt oder Motoren ein- und ausgeschalten werden oder sonst was anders.

// globale Variablen
unsigned long lastTime;
unsigned long on_time = xx;   // ein Zeit
unsigned long off_time = xx;  // aus Zeit
const byte pin_LED = xx;   // Pin Nummer
boolean state_LED = LOW;
---------------------------------------------------
void LedBlinker()
  {
    if (state_LED == LOW && millis() - lastTime > off_time )  
    {
      digitalWrite(pin_LED, HIGH);       // LED einschalten für x ms
      lastTime = millis();             
      state_LED = HIGH;
    }
    if (state_LED == HIGH && millis() - lastTime > on_time ) 
    {
      digitalWrite(pin_LED, LOW);         // LED ausschalten für x ms
      lastTime = millis();  
      state_LED = LOW;
    }
  }

Tomuino:
- YouTube

Ich habe mal ein Video zu meinen Problem gemacht :wink:

Auch wenn es dich verblüfft, wir haben vermutlich schon recht genau verstanden, wo dein Problem steckt.

Also nicht Videos machen....
Sondern versuchen zu verstehen, was die Jungs/Mädels dir beibiegen möchten.
Das lernen können wir dir leider nicht abnehmen.

sschultewolter:

#define INTERVAL_TASK0 2000UL

#define INTERVAL_TASK1 86400000UL
#define INTERVAL_TASK2 60000UL

void loop(){
static unsigned long lastMillis_task0;
static unsigned long lastMillis_task1;
static unsigned long lastMillis_task2;

if(millis() - lastMillis_task0 >= INTERVAL_TASK0) {
lastMillis_task0 = millis();

// do something
}

if(millis() - lastMillis_task1 >= INTERVAL_TASK1) {
lastMillis_task1 = millis();

// do something
}

if(millis() - lastMillis_task2 >= INTERVAL_TASK2) {
lastMillis_task2 = millis();

// do something
}

}

Das ist doch ein sehr übersichtlicher und gut zu verstehender Code als Beispiel für einen "Anfänger" zum Thema zeit- gesteuerter/periodischer Ablauf. Top!

Wenn man das Beispiel noch ergänzt um eine "Toggle-Funktion" (wie weiter oben schon im Beispiel der Blinkenden LED) ist doch alles wichtige in einem Code-BSP dabei. Darüber hätte (tu' ich immer noch) ich mich als Anfänger sehr gefreut. :wink: Das sollte irgendwo als Tutorial gepostet werden, wenn's nicht schon der Fall ist.

PS: Frage: Warum static variablen? die sind doch innerhalb der gesamten loop() sichtbar in diesem BSP, oder? als static könnte man sie direkt in den jeweiligen "Task"-Abschnitt schreiben (dann ist der Code compakter/ bzw. das was zusammengehört steht zusammen) Oder bin ich auf dem Holzweg? ::slight_smile: ::slight_smile:

Tutorials schreib ich nicht, würde aber behaupten, dass das so auch in blinkwithoutdelay einleuchtend erklärt wird. https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Das mit static ist Geschmackssache. Wenn man lastMillis bereits vor dem Eintritt in die loop initialisieren möchte (wenn die setup eine Weile dauert, zB bis ein Signal eingetroffen ist zum ersten Mal), dann macht es vielleicht Sinn, static wegzulassen und die Variable global zu defnieren.

Da aber die Variable nur innerhalb einer Funktion benötigt wird, und die nicht mit Referenzen oä. übergeben wird, halt ich das nicht für nötig.

...
void loop() {
static byte stateLed;
static unsigned long lastMillis_led;

if(millis() - lastMillis_led >= 1000) { // jede Sekunde
lastMillis_led = millis();
stateLed ^= 1;
digitalWrite(LED, stateLed);
}
}

Das Problem mit dem static, in diesem Fall ist, dass die Variablen nicht initialisiert werden.

Das mag, hier, in lopp() nicht auffallen, weil millis() auch mit Null startet.

Aber verwendet man das so in anderen Funktionen, welche später mal aufgerufen werden, kann/wird das zu schwer zu findenden und schwer behebbaren Fehlern führen.

Ich halte es für besser die Kapselung weiter zu führen!
Entweder die Daten in Strukturen stopfen, oder sofort mit Klassen und Objekten arbeiten.

Hallo combie, static Variablen werden automatisch mit 0 initialisiert. Deshalb auch geschrieben, dass wenn die setup länger als geplant dauert, dass man die als global nimmt.

Ich selbst würde es so nicht nutzen sondern mit call-by-reference einsetzen

int8_t blink(uint32_t *lastMillis, uint32_t *interval)
{
if(millis() - *lastMillis >= *interval) 
{
*lastMillis = millis();
return 1;
}
else return 0;
}

...

Okay, ich habe mich jetzt schon ein bisschen belesen was millis(). Aber ich finde irgendwie keine guten und vor allen dingen keine für mein Problem zutreffende Tutorials. Kann mir jemand ein gutes Tutorial empfehlen?

Dann hast du deinen Thread nicht aufmerksam zu Ende gelesen. Die Lösung steht hier, wenn auch nicht als zusammengefügten Sketch. Das werde ich für dich nicht übernehmen.

Wenn das nicht geht, solltest du dich erst einmal ernsthaft mit der Programmierung insbesondere bezogen auf µC beschäftigen. Es gibt diverse gute Bücher mit ausreichend Informationen. Erik Bartmann, O'Reileys Kochbuch, ...