2 Abläufe gleichzeitig machen lassen und delay ersetzen

Hallo,
ich habe mir einen Arduino zugelegt und möchte folgende Vorgänge gleichzeitig laufen lassen. Dafür muss ja das Delay ersetzt werden ...
Vorgang 1:

void setup()  { 
   // nothing happens in setup
    pinMode(4, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT); 
} 
void loop()
{
    digitalWrite(4, HIGH); 
    delay(10); 
    digitalWrite(4, LOW);
    delay(1000);
    digitalWrite(6, HIGH); 
    delay(10); 
    digitalWrite(6, LOW);
    delay(1000);
    digitalWrite(7, HIGH); 
    delay(10); 
    digitalWrite(7, LOW);
    delay(1000); 
}

Vorgang 2

const int ledPinOne = 3;    
const int ledPinTwo = 5;
void loop()  { 
  // fade in from min to max in increments of 5 points:
   for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
     // sets the value (range from 0 to 255):
     analogWrite(ledPinOne, fadeValue);
     analogWrite(ledPinTwo, fadeValue);  
     delay(3);                            
   } 
   // fade out from max to min in increments of 5 points:
   for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
     // sets the value (range from 0 to 255):
     analogWrite(ledPinOne, fadeValue);         
     analogWrite(ledPinTwo, fadeValue);         
         delay(3);                            
   } 
 delay(800);
}

Mir ist nicht ganz klar, wie ich millis() als Schrittzähler verwenden und es dann entsprechend verschachteln kann, dass es passt ... Kann mir jemand helfen? Danke!

Hier Mehrere Sensoren, Motoren usw. gleichzeitig betreiben. Nur wie? - Deutsch - Arduino Forum wird gerade das gleiche Problem erörtert.
Da findest du sicherlich die richtigen Stichwörter.

Eine for-Schleife ist auch nur ein verstecktes Delay das den restlichen Ablauf aufhält

Das hast mit loop() schon eine Schleife! Da läuft ein while(1) im Hintergrund. Ersetzte die for-Schleife durch eine if-Abfrage. Und frage zuerst ob genug millis() vergangen sind. Dann kannst du was machen und den Rest abfragen, wie den Wert der Zähl-Variablen.

z.B.:

const int INTERVAL = 500;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  static unsigned long previousMillis;
  static int counter;

  if (millis() - previousMillis > INTERVAL)
  {
    previousMillis = millis();

    Serial.println(counter);

    counter++;
    if (counter > 10)
      counter = 0;
  }
}

Das zählt einfach eine Variable von 0-10 auf Serial hoch. Lässt sich auch einfach in eine Funktion auslagern die man ständig in loop() aufruft. z.B.:

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  job1();
  job2();
}

void job1()
{
  const int INTERVAL = 500;
  static unsigned long previousMillis;
  static int counter;

  if (millis() - previousMillis > INTERVAL)
  {
    previousMillis = millis();

    Serial.print(F("Job 1: "));
    Serial.println(counter);

    counter++;
    if (counter > 10)
      counter = 0;
  }
}

void job2()
{
  const int INTERVAL = 1000;
  static unsigned long previousMillis;
  static int counter = 100;

  if (millis() - previousMillis > INTERVAL)
  {
    previousMillis = millis();

    Serial.print(F("Job 2: "));
    Serial.println(counter);

    counter++;
    if (counter > 105)
      counter = 100;
  }
}

Für Vorgang 1 kann man sich doch einen Sekundentimer einstellen

millis() ist ja im Prinzip schon ein Timer. Das wird von der Arduino Software schon im ms-Takt auf Timer0 hochgezählt. Da für sowas noch einen Hardware Timer zu belegen ist Overkill. Hat außerdem dass Problem dass man sich dadurch die PWM-Funktionalität auf den entsprechenden Pins zerstört.

Hallo,
ich konnte nun die statischen Sachen ohne delay machen:

int StrobeLight1 = 4;
int StrobeLight2 = 6;
int StrobeLight3 = 7;

unsigned long time;
int phase = 1;
unsigned long interval1 = 10; // Intervakk StrobeLight Blitz
unsigned long interval2 = 1000; // Intervall StrobleLight Pause
unsigned long previousMillis = 0;

void setup()
{
  Serial.begin(9600);
    pinMode(StrobeLight1, OUTPUT);
    pinMode(StrobeLight2, OUTPUT);
    pinMode(StrobeLight3, OUTPUT); 
}

void loop()
{
  if ((phase == 1) and (millis() - previousMillis > interval1)) {  
    previousMillis = millis();                                    
    phase = 2 ; 
  }
  if ((phase == 2) and (millis() - previousMillis > interval2)) {
    previousMillis = millis(); 
    phase = 3 ; 
  }
  if ((phase == 3) and (millis() - previousMillis > interval1)) {
    previousMillis = millis(); 
    phase = 4 ; 
  }
    if ((phase == 4) and (millis() - previousMillis > interval2)) {
    previousMillis = millis(); 
    phase = 5 ; 
  }
      if ((phase == 5) and (millis() - previousMillis > interval1)) {
    previousMillis = millis(); 
    phase = 6 ; 
  }
    if ((phase == 6) and (millis() - previousMillis > interval2)) {
    previousMillis = millis(); 
    phase = 1 ; 
  }
if (phase == 1) {
  digitalWrite(StrobeLight1, HIGH);
  digitalWrite(StrobeLight2, LOW);
  digitalWrite(StrobeLight3, LOW);
}
if (phase == 2) {
    digitalWrite(StrobeLight1, LOW);
  digitalWrite(StrobeLight2, LOW);
  digitalWrite(StrobeLight3, LOW);
  }
if (phase == 3) {
    digitalWrite(StrobeLight1, LOW);
  digitalWrite(StrobeLight2, HIGH);
  digitalWrite(StrobeLight3, LOW);
  }
if (phase == 4) {
    digitalWrite(StrobeLight1, LOW);
  digitalWrite(StrobeLight2, LOW);
  digitalWrite(StrobeLight3, LOW);
  }
if (phase == 5) {
    digitalWrite(StrobeLight1, LOW);
  digitalWrite(StrobeLight2, LOW);
  digitalWrite(StrobeLight3, HIGH);
  }
if (phase == 6) {
    digitalWrite(StrobeLight1, LOW);
  digitalWrite(StrobeLight2, LOW);
  digitalWrite(StrobeLight3, LOW);
  }  
}

für die Sache mit der for-Schleife fehlt mir irgendwie der Durchblick ... In diesem Code wird fadeValue ja vom Arduino berechnet. Wenn ich das richtig interpretiere, mach dir for-Schleife also folgendes:

const int ledPinOne = 3;   
const int ledPinTwo = 5;
void loop()  {
  // fade in from min to max in increments of 5 points:
   for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {
     // sets the value (range from 0 to 255):
     analogWrite(ledPinOne, fadeValue);
     analogWrite(ledPinTwo, fadeValue); 
     delay(3);                           
   }
   // fade out from max to min in increments of 5 points:
   for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {
     // sets the value (range from 0 to 255):
     analogWrite(ledPinOne, fadeValue);         
     analogWrite(ledPinTwo, fadeValue);         
         delay(3);                           
   }
 delay(800);
}

Wenn ich das richtig interpretiere, mach dir for-Schleife also folgendes: Ich fange mit Wert 0 an und rechne nun mit +/-5 hoch bzw. runter, bis der Wert 0 bzw. 255 erreicht ist. Dazu hat die Schleife 3 ms Zeit. Wie geht das nun in einer if? kann mir da jemand was zu sagen? Vielleicht auch an einem Beispiel?

kann mir da jemand was zu sagen? Vielleicht auch an einem Beispiel?

Ja.

combie:
Ja.

geht es auch konkreter?? :slight_smile:

utz676:
geht es auch konkreter?? :slight_smile:

Ja.

combie:
Ja.

würdest du das auch "eben" machen, bevor wir uns hier mit Fragen und Ja's im Kreise drehen?? :slight_smile:

Darauf ein klares: Nein!

Falls du ein Problem bei der eigenen Programmierung hast, will ich dir gerne mit Rat und Tat zur Seite stehen.

Aber irgendein Interesse daran, deine Arbeit zu erledigen, habe ich nicht.

utz676:
Wenn ich das richtig interpretiere, mach dir for-Schleife also folgendes: Ich fange mit Wert 0 an und rechne nun mit +/-5 hoch bzw. runter, bis der Wert 0 bzw. 255 erreicht ist. Dazu hat die Schleife 3 ms Zeit. Wie geht das nun in einer if? kann mir da jemand was zu sagen? Vielleicht auch an einem Beispiel?

Es sind pro Schritt 3ms. Die Gesamtzeit ergibt sich aus Zeit pro Schritt * Anzahl der Schritte

Wie man das machen kann habe ich in Reply #2 gezeigt. for durch if ersetzten und die Schleifen-Bedingung per Hand nachbilden. In dem ersten Beispiel geht ein Zähler alle 500ms von 0 bis 10. Im zweiten Beispiel geht zusätzlich einer alle 1s von 100 bis 105

Damit das Faden nicht fade wird, so geht's ohne delay():

void loop()  {
  if (millis() > fadeMillis) {
    analogWrite(ledPinOne, fadeValue);
    analogWrite(ledPinTwo, fadeValue);
    if (fadeValue == 255 || fadeValue == 0) {
      delta = -1 * delta;
      fadeMillis = millis() + grossePause;
    } else {
      fadeMillis = millis() + pause;
    }
    fadeValue += delta;
  }
}

Womit ich weiß, mein Mega kann es auch :slight_smile:

ich habe nun eine Lösung gefunden, die fast funktioniert:

int led1 = 3;
int led2 = 5;

//Einstellungen Fader
int brightness = 0;    // how bright the LED is
int fadeAmount = 1;    // how many points to fade the LED by
int faderDuration = 5;
unsigned long currentTime;
unsigned long loopTime;
void setup()
{
  Serial.begin(9600);
    pinMode(led1, OUTPUT);
    pinMode(led2, OUTPUT);
    currentTime = millis();
      loopTime = currentTime; 
}
loop(){
currentTime = millis();
  if(currentTime >= (loopTime + faderDuration)){     
    analogWrite(led1, brightness);    
    analogWrite(led2, brightness);
    brightness = brightness + fadeAmount;

    if (brightness == 255) {
      fadeAmount = -fadeAmount ; 
      }
      if ( brightness == 0 ) {
        if (currentTime >= (loopTime + faderDuration + 2000)){ // wenn brightness = 0, sollen 2 Sekunden lang brightness bei 0 bleiben und dann wieder ansteigen.
          fadeAmount = 0;
          }
      fadeAmount = -fadeAmount ; 
      }
       loopTime = currentTime;  // Updates loopTime
  }
}

Wie bekomme ich die längere Pause hin, wenn brightness der LEDs = 0 ist? Ich hab jetzt mehreres probiert und nichts funktioniert, egal wo ich die if-Abfrage einfüge ...

Das Setzen der neuen Zeit loopTime = currentTime; muß eine Ebene höher.

Die Bedingung if (currentTime >= (loopTime + faderDuration + 2000)) braucht nur eine Zuweisung zu sein.

analogWrite() muß zwischen brightness = brightness + fadeAmount; und if (brightness == ), da sonst die LEDs bei brightness == 5 warten.

 currentTime = millis();
  if (currentTime >= (loopTime + faderDuration)) {
    brightness = brightness + fadeAmount;
    loopTime = currentTime;  // Updates loopTime
    analogWrite(led1, brightness);
    analogWrite(led2, brightness);

    if (brightness == 255) {
      fadeAmount = -fadeAmount;
    }
    if ( brightness == 0 ) {
      loopTime = currentTime + 2000; { // wenn brightness = 0, sollen 2 Sekunden lang brightness bei 0 bleiben und dann wieder ansteigen.
        fadeAmount = -fadeAmount;
      }
    }
  }

agmue:
Das Setzen der neuen Zeit loopTime = currentTime; muß eine Ebene höher.

Die Bedingung if (currentTime >= (loopTime + faderDuration + 2000)) braucht nur eine Zuweisung zu sein.

analogWrite() muß zwischen brightness = brightness + fadeAmount; und if (brightness == ), da sonst die LEDs bei brightness == 5 warten.

 currentTime = millis();

if (currentTime >= (loopTime + faderDuration)) {
    brightness = brightness + fadeAmount;
    loopTime = currentTime;  // Updates loopTime
    analogWrite(led1, brightness);
    analogWrite(led2, brightness);

if (brightness == 255) {
      fadeAmount = -fadeAmount;
    }
    if ( brightness == 0 ) {
      loopTime = currentTime + 2000; { // wenn brightness = 0, sollen 2 Sekunden lang brightness bei 0 bleiben und dann wieder ansteigen.
        fadeAmount = -fadeAmount;
      }
    }
  }

Vielen Dank,
da habe ich vorhin wohl zu viele if-Abfragen gesehen :). was passiert eigentlich nach den 50 Tagen,
wenn die millis "überlaufen". Hängt dann alles oder muss das durch eine if-Abfrage am Anfang resettet werden?

Wenn du statt

 if (currentTime >= (loopTime + faderDuration)) {

besser

 if ( currentTime - loopTime >= faderDuration ) {

schreibst, wird auch bei Überlauf immer richtig gerechnet. ( Und danach sowieso wieder...

Brauchst du gar nichts machen

utz676:
was passiert eigentlich nach den 50 Tagen, wenn die millis "überlaufen". Hängt dann alles oder muss das durch eine if-Abfrage am Anfang resettet werden?

Nach der höchst möglichen Zahl (4.294.967.295) geht es dann wieder bei Null los, wenn es sich um eine vorzeichenlose Variable (unsigned long) handelt. Mit currentTime = millis() + 4294960000UL; kannst Du das testen.

agmue:
Nach der höchst möglichen Zahl (4.294.967.295) geht es dann wieder bei Null los, wenn es sich um eine vorzeichenlose Variable (unsigned long) handelt. Mit currentTime = millis() + 4294960000UL; kannst Du das testen.

das führt dann nach 2 Seknden zu einem einmaligen Doppelaufflackern ... damit lässt sich leben, wenn das alle 50 Tage passiert.

bei diesem hier führt es allerdings dazu, dass Phase 1 immer viel zu dunkel wieder gegeben wird. Da stimmt etwas nicht.

int Led1 = 4;
int Led2 = 6;
int Led3 = 7;
unsigned long time;
int phase = 1;
unsigned long interval1 = 10; // Intervall Led Blitz
unsigned long interval2 = 1000; // Intervall Led Pause
unsigned long previousMillis = 0;

void setup()
{
  Serial.begin(9600);
    pinMode(Led1, OUTPUT);
    pinMode(Led2, OUTPUT);
    pinMode(Led3, OUTPUT); 
}

unsigned long cur = millis() + 4294960000UL;
  if ((phase == 1) and (cur - previousMillis > interval1)) {  
    previousMillis = millis();                                    
    phase = 2 ; 
  }
  if ((phase == 2) and (millis() - previousMillis > interval2)) {
    previousMillis = millis(); 
    phase = 3 ; 
  }
  if ((phase == 3) and (millis() - previousMillis > interval1)) {
    previousMillis = millis(); 
    phase = 4 ; 
  }
    if ((phase == 4) and (millis() - previousMillis > interval2)) {
    previousMillis = millis(); 
    phase = 5 ; 
  }
      if ((phase == 5) and (millis() - previousMillis > interval1)) {
    previousMillis = millis(); 
    phase = 6 ; 
  }
    if ((phase == 6) and (millis() - previousMillis > interval2)) {
    previousMillis = millis(); 
    phase = 1 ; 
  }
if (phase == 1) {
  digitalWrite(Led1, HIGH);
  digitalWrite(Led2, LOW);
  digitalWrite(Led3, LOW);
}
if (phase == 2) {
    digitalWrite(Led1, LOW);
  digitalWrite(Led2, LOW);
  digitalWrite(Led3, LOW);
  }
if (phase == 3) {
    digitalWrite(Led1, LOW);
  digitalWrite(Led2, HIGH);
  digitalWrite(Led3, LOW);
  }
if (phase == 4) {
    digitalWrite(Led1, LOW);
  digitalWrite(Led2, LOW);
  digitalWrite(Led3, LOW);
  }
if (phase == 5) {
    digitalWrite(Led1, LOW);
  digitalWrite(Led2, LOW);
  digitalWrite(Led3, HIGH);
  }
if (phase == 6) {
    digitalWrite(Led1, LOW);
  digitalWrite(Led2, LOW);
  digitalWrite(Led3, LOW);
  }

Was ist denn cur ?