Guten Tag miteinander,

ich bin neu im Forum und auch bei Arduino. Ich habe die vergangenen Stunden versucht folgendes Problem für mich zu lösen:

Ich habe einen Sensor, dieser soll, wenn er den Gegenstand erkennt, einen Pneumatikzylinder zum ausfahren bewegen, ist er wieder unbelegt, soll dieser einfahren, soweit so einfach. Nun möchte ich aber gerne, dass dies zeitverzögert stattfindet:

Sensor erkennt Gegenstand -> Zeit vergeht (500-1000 ms/ variabel) -> Ventil an/ Zylinder fährt aus und bleibt ausgefahren

Wenn der Gegenstand entfernt wird, geht der Sensor aus -> Zeit vergeht (500-1000 ms/ variabel) -> Ventil aus/ Zylinder fährt ein

Mit delay ist das ganze kein Problem, leider will ich parallel noch weitere Signale auswerten, weshalb ich es mir nicht "leisten" kann, dass das Programm unterbrochen wird.

Im Forum bin ich bereits beim Blink without delay Tutorial gelandet, habe mir einige Varianten hier im Forum angesehen, ist allerdings alles nicht so ganz was ich will. Außerdem kann ich die Gleichung nicht nachvollziehen. Ich möchte besser verstehen, wie genau das mit millis funktioniert:

Aus folgendem Thread: Wie zeitliche Abläufe ohne delay() einfach gestalten? - Deutsch - Arduino Forum

void loop()
{
unsigned long currentMillis = millis();

if(ledState == HIGH && currentMillis - previousMillis > intervalon ) {
previousMillis = currentMillis;
ledState = LOW;
digitalWrite(ledPin, ledState);
}

da steht doch (angenommen current millis ist 10000 und intervalon 1000) 10000-0>1000 dadurch wäre das doch sofort erfüllt und der timmer sinnfrei? Wenn man immer nur hin und her blinken will mag das ja gehen, ab ich will ja das eine Funktion zeitverzögert einschalten, bzw ausschalten, wie muss ich den code ändern damit das geht? Müsste ich previousMillis dann davor schon = currentMillis setzen?

Für den Fall das meine Fragen dumm eirscheinen, ich hab irgendwie nen Knoten im Hirn, komme eigentlich aus der SPS Richtung und habe gerade erst mit C/C++ angefangen und bei ner SPS is dat mit der Zeit, zumindest mal für mich, auf den ersten Blick einfacher gelöst :slight_smile: Kann sein das ich dadurch aber auch vorprogrammiert bin und mir das umschalten schwer fällt.

Vielen Dank im vorraus für eure Hilfe :slight_smile:

da steht doch (angenommen current millis ist 10000 und intervalon 1000) 10000-0>1000 dadurch wäre das doch sofort erfüllt und der timmer sinnfrei?

Millis startet nicht mit 10000, sondern mit 0.

Wenn dir die SPS Sicht einfacher erscheint, dann baue dir solche Funktionen. Ist kein Hexenwerk.
Ein Start dahin: iec Timer

Ansonsten:

Ablaufsteuerung
Meine Standardantwort zu Ablaufsteuerungen:
Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay,

Blink Without Delay
Der Wachmann

Multitasking Macros
Intervall Macros

Servus.
Das ist ein Code den ich auch in verwendung habe

Der Code mit der IF abfrage läuft ja permanent durch.
Da der interval bei 1er sekunden ist, trifft die IF abfrage auch nur zu jeder vollen Sekunde zu.
Und so kann man dann zu jeder vollen sekunde eine Funktion ausführen lassen.
Du kannst dann innerhalb dieser IF abfrage auch weitere IF Abfragen gestallten.

Das ganze ist aus meiner Anfänger Sicht einfach eine art Trigger der in diesem Fall alle 1000millis zutrifft.

ich denke mal das man den Code soweit erweitern und anpassen kann wie du es brauchst.

unsigned long previousMillis = 0;                                                                 
const long interval = 1000;


void setup()
{

}



void loop() {
unsigned long currentMillis = millis();                                                           

if (currentMillis - previousMillis >= interval)                                                  
{                                                                                                 
previousMillis = currentMillis;                                                                   
           
}


}

hier wäre mein denkansatz

void loop() {
unsigned long currentMillis = millis();  

if (item == 1)
{
                                                         
if (currentMillis - previousMillis >= interval)   
  {
  previousMillis = currentMillis; 
  digitalWrite(ventil, HIGH);
                                                   
  }
                                                                                                 
     
}

if (item == 0)
{
                                                         
if (currentMillis - previousMillis >= interval)   
  {
  previousMillis = currentMillis; 
  digitalWrite(ventil, LOW);
                                                   
  }
                                                                                                    
}
  
}

Aber vorsicht der Code ist nicht getest und ist nur als Gedanke gedacht mit dem man vll. was Anfangen könnte.

Hallo,

du kannst auch sagen, wenn das Ereignis eintritt,
dann merke ich mir den Zeitpunkt wenn der Zylinder seine Position erreicht hat > time_detect
und warte bis
time_detect + 5000 > currentmillis wahr wird
und mache dann ...
Wobei dann sicherlich noch eine zusätzliche Statusvariable rein muß, sonst wird das ab dem Zeitpunkt
ständig ausgeführt. Ist dann von der Sache her das was combie angesprochen hat. Sieht nur anders aus.

time_detect + 5000 > currentmillis

Ich befürchte, dass, wenn time_detect kurz vor seinem 49 Tage Überlauf steht, der Vergleich nie wieder true liefern wird.

time_detect ist hier ein etwas passenderer Name als previousmillis, aber die Regel dass man besser
if (currentmillis - timedetect >= wartezeit) schreibt alstimedetect+wartezeit, gilt natürlich auch hier, um beim Überlauf keine Probleme zu kriegen.

Was noch fehlt: Erkennen, dass überhaupt was passiert ist:

  • Sensor und Zylinder passen nicht zueinander.
  • Im vorigen Durchlauf war das noch nicht so. Jetzt muss also timedetect gesetzt werden.

Alternativ kann man (statt einem extra Merker) immer, wenn alles ok ist (Sensorwert == Ventilstellung), timedetect=currentmillis mitziehen und so verhindern, dass die Wartezeit losläuft. Wenn dann der Sensor sich ändert, ist timedetect schon gesetzt und die Wartezeit läuft.

Basierend auf #2 würde ich noch die Flankenerkennung und zwei verschiedene Intervalle ergänzen. Also wenn Flanke erkannt, dann setze previousMillis, damit die Zeit losläuft:

const byte sensorPin = 2, ventilPin = 13;
const uint16_t intervall0 = 500, intervall1 = 1000;
uint32_t currentMillis, previousMillis;
bool altSensor, aktSensor;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(sensorPin, INPUT_PULLUP);
  pinMode(ventilPin, OUTPUT);
  aktSensor = !digitalRead(sensorPin);
  altSensor = aktSensor;
}


void loop() {
  currentMillis = millis();
  altSensor = aktSensor;
  aktSensor = !digitalRead(sensorPin);
  if (aktSensor) {
    if (!altSensor && aktSensor) {
      previousMillis = currentMillis;
      delay(30);    // wenn nötig, zum Entprellen, um eine definierte Zeit zu haben
    }
    if (currentMillis - previousMillis >= intervall1) {
      digitalWrite(ventilPin, HIGH);
    }
  } else {
    if (altSensor && !aktSensor) {
      previousMillis = currentMillis;
      delay(30);    // wenn nötig, zum Entprellen, um eine definierte Zeit zu haben
    }
    if (currentMillis - previousMillis >= intervall0) {
      digitalWrite(ventilPin, LOW);
    }
  }
}

Hallo,

ja stimmt, die Überlaufproblematik hatte ich außer acht gelassen. Sorry.