Parallel schalten und AI

Hallo Zusammen,
bisher habe ich nur ganz simple sachen mit delay gesteuert, aber ich will eigentlich dass ich zyklen mit eigenen zeiten unabhängig voneinander laufen lassen kann. Ich habs mal mit chat gpt versucht aber das was der mit gibt, haut nicht hin, obwohl es sich erstmal logisch liest. Was ist denn falsch daran? Wäre dankbar für eine einfache und schnelle lösung für eine eigentlich einfache aufgabe.
(alternativ habe ich halt immer recht lange dinger mit delays geschrieben, wobei ich halt immer die einzelnen schaltkreise zerstückelt habe und zwischenrein wieder den anderen geschalten habe, aber das ist so umständlich. (Also zb. 1ein, 2ein 1aus, 3ein, 4ein, 2aus, 1ein, 3aus, 1aus, 4aus, 1ein, 2ein....))

// Pin-Definitionen
int relais1Pin = 9;
int relais2Pin = 8;

// Schaltzeiten für Relais 1
const int relais1EinZeit = 1000;   // Zeit in ms, während das Relais eingeschaltet ist
const int relais1AusZeit = 1000;  // Zeit in ms, während das Relais ausgeschaltet bleibt

// Schaltzeiten für Relais 2
const int relais2EinZeit = 1000;  // Zeit in ms, während das Relais eingeschaltet ist
const int relais2AusZeit = 2000;  // Zeit in ms, während das Relais ausgeschaltet bleibt

// Variablen zur Speicherung der Zeiten
unsigned long relais1EinStartzeit = 0;
unsigned long relais1AusStartzeit = 0;
unsigned long relais2EinStartzeit = 0;
unsigned long relais2AusStartzeit = 0;

void setup() {
  // Pin-Modi setzen
  pinMode(relais1Pin, OUTPUT);
  pinMode(relais2Pin, OUTPUT);
}

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


  if (jetzt - relais1AusStartzeit >= relais1AusZeit) {
    digitalWrite(relais1Pin, HIGH);  // Relais einschalten
    relais1EinStartzeit = jetzt;     // Startzeit für Einschaltzeitpunkt setzen
  }
    // Schaltzyklus für Relais 1
  if (jetzt - relais1EinStartzeit >= relais1EinZeit) {
    digitalWrite(relais1Pin, LOW);  // Relais ausschalten
    relais1AusStartzeit = jetzt;   // Startzeit für Ausschaltzeitpunkt setzen
  }

  // Schaltzyklus für Relais 2
  if (jetzt - relais2EinStartzeit >= relais2EinZeit) {
    digitalWrite(relais2Pin, LOW);  // Relais ausschalten
    relais2AusStartzeit = jetzt;   // Startzeit für Ausschaltzeitpunkt setzen
  }
  if (jetzt - relais2AusStartzeit >= relais2AusZeit) {
    digitalWrite(relais2Pin, HIGH);  // Relais einschalten
    relais2EinStartzeit = jetzt;     // Startzeit für Einschaltzeitpunkt setzen
  }
}

Hallo kallio

Nimm eine Suchmaschine deiner Wahl und befrage das WWW mit 'Ampelsteuerung +arduino'.

Viel Erfolg.

Ich wünsche einen geschmeidigen Tag und viel Spass beim Programmieren in C++.

auf den seriellen Monitor ausgeben lassen was das Programm macht

Du hast jeweils zwei if-bedingungen.
Die jeweils erste ist die ganze Zeit true
Du verwendest zuviel Variablen
nur eine Timervariable verwenden und dann ändert man nur die Zeitdifferenz relais1Zeit abwechselnd von 1000 auf 2000

if (jetzt - relais1Startzeit >= relais1Zeit) {

Wenn die ein/auszeit gleich lang ist braucht man sie gar nicht ändern sondern schaltet nur den Ausgang ein/aus

Die Werte für die unterschiedlichen An- und Aus-Zeiten sollte man schon in Variablen/Konstanten an einer zentralen Stelle im Code halten. Es spart also keine Variablen.
Alternativ könnte man auch die einzelnen If’s auf den Pinzustand sperren.

…
  // Schaltzyklus für Relais 2
  if ((jetzt - relais2Startzeit >= relais2EinZeit) && digitalRead(relais2Pin)) {
    digitalWrite(relais2Pin, LOW);  // Relais ausschalten
    relais2Startzeit = jetzt;   // Zeit merken
  }
  if ((jetzt - relais2Startzeit >= relais2AusZeit) && !digitalRead(relais2Pin))  {
    digitalWrite(relais2Pin, HIGH);  // Relais einschalten
    relais2Startzeit = jetzt;     // Zeit merken
  }
…
// code editiert -> pinzuweisung und erste Schaltzeit für rel 2
struct ACTOR
{
  byte outPin;
  unsigned long onTime;
  unsigned long offTime;
  unsigned long switchTime;
};

ACTOR relOne;
ACTOR relTwo;
ACTOR actors[] = {relOne, relTwo};
const byte numActors = sizeof(actors) / sizeof(actors[0]);

const bool off = HIGH;  // Relaisbausteine sind oftmals LOW - aktiv...

void setup()
{
  Serial.begin(9600);                                             //
  Serial.println(F("\r\nStart..."));
  relOne.onTime = 1000;
  relOne.offTime = 2000;
  relOne.outPin = 9;
  relTwo.onTime = 3000;
  relTwo.offTime = 4000;
  relTwo.outPin = 8;
  for (byte b = 0; b < numActors; b++)                           // durchzählen
  {
    pinMode(actors[b].outPin, OUTPUT);                           // initialisieren
    digitalWrite(actors[b].outPin, off);                         // setzen
  }
  relOne.switchTime = millis() + 2000;                           // erste Auslösezeit festlegen
  relTwo.switchTime = millis() + 3000;
}

void loop()
{
  uint32_t myTime = millis();                                    // aktuelle Zeit merken
  for (byte b = 0; b < numActors; b++)                           // Durchzählen
  {
    if (digitalRead(actors[b].outPin) == off)                    // Der PIN zustand ist gesetzt
    {
      if (myTime - actors[b].switchTime > actors[b].offTime)     // und die Zeit abgeaufen?
      {
        digitalWrite(actors[b].outPin, !off);                    // Pin neu setzen
        actors[b].switchTime = myTime;                           // Zeit merken
      }
    }
    else                                                         // PIN zustand ist nicht gesetzt
    {
      if (myTime - actors[b].switchTime > actors[b].onTime)      // und Zeit abgelaufen
      {
        digitalWrite(actors[b].outPin, off);                     //
        actors[b].switchTime = myTime;                           //
      }
    }
  }
}

?

Man kann es auch so sehen, dass du zuviele Zyklen verwendest (4 statt 2)

// Schaltzeiten für Relais 1
const int relais1EinZeit = 1000;   // Zeit in ms, während das Relais eingeschaltet ist
const int relais1AusZeit = 1000;  // Zeit in ms, während das Relais ausgeschaltet bleibt
const int Relais1Zyklus = relais1EinZeit+relais1AusZeit;

// Schaltzeiten für Relais 2
const int relais2EinZeit = 1000;  // Zeit in ms, während das Relais eingeschaltet ist
const int relais2AusZeit = 2000;  // Zeit in ms, während das Relais ausgeschaltet bleibt
const int Relais2Zyklus = relais2EinZeit+relais2AusZeit;

unsigned long relais1Zeit = 0;
unsigned long relais2Zeit = 0;

void loop() {
  unsigned long jetzt = millis();
  // Relais 1 Zyklus
  if (jetzt - relais1Zeit >= Relais1Zyklus) {
    relais1Zeit = jetzt;     // neuer Zyklus
  }
  if (jetzt - relais1Zeit < relais1EinZeit) 
       digitalWrite(relais1Pin, HIGH);  // Relais einschalten (am Zyklusanfang)
  else
      digitalWrite(relais1Pin, LOW);  // Relais ausschalten (für den Rest der ZyklusZeit)

 // Relais 2  genauso ...
  if (jetzt - relais2Zeit >= Relais2Zyklus) {
    relais2Zeit = jetzt;     // neuer Zyklus
  }
  // alternative Schreibweise: 
  digitalWrite(relais2Pin, (jetzt - relais2Zeit < relais2EinZeit)  ); // true ist HIGH, false ist LOW
}

@kallio

Was meinst du mit "Zyklen" genau? Sind das nur 4 getrennte Blink LEDs / Relays oder ist das ein bestimmter Ablauf?

Simple "Blinkleds" hättest in Beispiel "Blink without Delay" gefunden.

Dann ersuche ich mal um eine schnelle klärende Antwort auf eine einfache Rückfrage.

Beispiele:
a) "Blinken" von my_xy_project leicht adaptiert:

b) "Sequenz"/Zyklen wie ich mir das vorstellen würde:

/*
    https://forum.arduino.cc/t/parallel-schalten/1125240

    Variant: define Steps with a bitmap of  on/off bits for each output
    2023-05-10 by noiasca
    sketch in forum
*/

struct Step {
  uint16_t out;      // a bitmask
  uint32_t interval; // how long
};

Step step[] {
  {0b0000, 2000},     // also used as start condition
  {0b0001, 1000},     // 1ein,
  {0b0011, 1000},     // 2ein
  {0b0010, 1000},     // 1aus,
  {0b0110, 1000},     // 3ein,
  {0b1110, 1000},     // 4ein,
  {0b1100, 1000},     // 2aus,
  {0b1101, 1000},     // 1ein,
  {0b1001, 1000},     // 3aus,
  {0b1000, 1000},     // 1aus,
  //{0b0000, 2000},   // 4aus,
  //{0b0301, 4000},   // 1ein,
  //{0b0301, 4000},   // 2ein
};
const size_t noOfSteps = sizeof(step) / sizeof(step[0]);
const uint8_t pin[] {10, 11, 12, 13};                 // the used pins.
const size_t noOfPins = sizeof(pin);
const bool off = LOW;  // set to HIGH if output(relay) is LOW active

void runSteps() {
  static uint32_t previousMillis = 0;
  static byte actual = 0;
  uint32_t currentMillis = millis();
  if (currentMillis - previousMillis > step[actual].interval) {
    previousMillis = currentMillis;
    actual++;
    if (actual >= noOfSteps) actual = 0;
    for (size_t i = 0; i < noOfPins; i++) {
      if (step[actual].out & (1 << i))
        digitalWrite(pin[i], !off);
      else
        digitalWrite(pin[i], off);
    }
    Serial.print(actual);
    Serial.print(" ");
    Serial.println(step[actual].out, BIN);
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("\r\nStart..."));
  for (size_t i = 0; i < noOfPins; i++) {                // durchzählen
    pinMode(pin[i], OUTPUT);                             // initialisieren
    digitalWrite(pin[i], off);                           // setzen
  }
}

void loop() {
  runSteps();
}

Danke für die vielen Antworten.
Teilweise konnte ich was davon rausziehen und mit diesem Code habe ich geschafft, was ich wollte.
Wichtig war die if funktion mit dem zustand des pins abzugleichen.

// Pin-Definitionen
int relais1Pin = 9; //tischkrake
int relais2Pin = 8; //kopf
int relais3Pin = 7;

// Schaltzeiten für Relais 1
const int relais1EinZeit = 40000;   // Zeit in ms, während das Relais eingeschaltet ist
const int relais1AusZeit = 20000;  // Zeit in ms, während das Relais ausgeschaltet bleibt

// Schaltzeiten für Relais 2
const int relais2EinZeit = 5000;  // Zeit in ms, während das Relais eingeschaltet ist
const int relais2AusZeit = 30000;  // Zeit in ms, während das Relais ausgeschaltet bleibt


// Schaltzeiten für Relais 3
const int relais3EinZeit = 8000;  // Zeit in ms, während das Relais eingeschaltet ist
const int relais3AusZeit = 50000;  // Zeit in ms, während das Relais ausgeschaltet 

// Variablen zur Speicherung der Zeiten
unsigned long relais1EinStartzeit = 0;
unsigned long relais1AusStartzeit = 0;
unsigned long relais2EinStartzeit = 0;
unsigned long relais2AusStartzeit = 0;
unsigned long relais3EinStartzeit = 0;
unsigned long relais3AusStartzeit = 0;

void setup() {
  Serial.begin(9600);                                             // 
  // Pin-Modi setzen
  pinMode(relais1Pin, OUTPUT);
  pinMode(relais2Pin, OUTPUT);
  pinMode(relais3Pin, OUTPUT);
}

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


  if (jetzt - relais1AusStartzeit >= relais1AusZeit && digitalRead(relais1Pin) == LOW) {
    digitalWrite(relais1Pin, HIGH);  // Relais einschalten
    relais1EinStartzeit = jetzt;     // Startzeit für Einschaltzeitpunkt setzen
    Serial.println ("1 schaltet an");
  }

  
    // Schaltzyklus für Relais 1
  if (jetzt - relais1EinStartzeit >= relais1EinZeit && digitalRead(relais1Pin) == HIGH) {
    digitalWrite(relais1Pin, LOW);  // Relais ausschalten
    relais1AusStartzeit = jetzt;   // Startzeit für Ausschaltzeitpunkt setzen
    Serial.println ("1 schaltet aus");
  }


  if (jetzt - relais2AusStartzeit >= relais2AusZeit && digitalRead(relais2Pin) == LOW) {
    digitalWrite(relais2Pin, HIGH);  // Relais einschalten
    relais2EinStartzeit = jetzt;     // Startzeit für Einschaltzeitpunkt setzen
  }

  
    // Schaltzyklus für Relais 1
  if (jetzt - relais2EinStartzeit >= relais2EinZeit && digitalRead(relais2Pin) == HIGH) {
    digitalWrite(relais2Pin, LOW);  // Relais ausschalten
    relais2AusStartzeit = jetzt;   // Startzeit für Ausschaltzeitpunkt setzen
  }


  if (jetzt - relais3AusStartzeit >= relais3AusZeit && digitalRead(relais3Pin) == LOW) {
    digitalWrite(relais3Pin, HIGH);  // Relais einschalten
    relais3EinStartzeit = jetzt;     // Startzeit für Einschaltzeitpunkt setzen
  }

  
    // Schaltzyklus für Relais 1
  if (jetzt - relais3EinStartzeit >= relais3EinZeit && digitalRead(relais3Pin) == HIGH) {
    digitalWrite(relais3Pin, LOW);  // Relais ausschalten
    relais3AusStartzeit = jetzt;   // Startzeit für Ausschaltzeitpunkt setzen
  }


}



Also ich verstehe wirklich garnichts von diesem code, aber wenn ich ihn einfach nur einfüge läufts nicht.

jetzt habe ich aber ein anderes problem, weshalb ich mir auch printen lasse, was das relais 1 macht.
Und zwar bleibt das immer stehen. Die anderen beiden machen weiter nach ihren xx sekunden kurz auf, auch vile minuten lang, aber das relais 1 schaltet immer ein paar mal an und aus, dann bleibt es in einem zustand stehen, während die anderen brav weitermachen. wie kann denn sowas sein? Das widerspricht doch jeder logik oder?

Seltsamerweise scheint das nur bei recht hohen Zahlen zu passieren, also bei kleinen Zahlen als Schaltzeitvariablen läuft es auch minutenlang weiter, nur bei höheren, so ab 40s bis 60s, die eigentlich ganz gut für mich wären hängt das immer wieder fest. weird.
Lass ich das Teil im 30 Sekunden Takt ein und ausschalten machts mit. Lass ich es 30 aus und 40 an, bleibts irgendwann einfach so dauerhaft an und schaltet nie wieder zurück.
(übrigens ist das alles für eine pneumatisch betriebene Kunstinstallation. Der Pin schickt ein Signal, das wird dann verstärkt und schaltet ein 5/2 Wege Ventil, wodurch so eine Figur sich bewegt./bewegen soll)

Welchen Wertebereich hat dein int?

Kommt mir elegant vor, aber wenn ich das machen will, dann kommt
Arduino: 1.8.19 (Mac OS X), Board: "Arduino Leonardo"

/var/folders/xz/169l5scd5ls8hd8q0hknctsr0000gn/T//cchXHHYX.ltrans0.ltrans.o: In function main': /private/var/folders/xz/169l5scd5ls8hd8q0hknctsr0000gn/T/AppTranslocation/391C55C8-D395-4CE5-BC3E-73DC954FA944/d/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/main.cpp:43: undefined reference to setup'
collect2: error: ld returned 1 exit status
exit status 1
Fehler beim Kompilieren für das Board Arduino Leonardo.

Dieser Bericht wäre detaillierter, wenn die Option
"Ausführliche Ausgabe während der Kompilierung"
in Datei -> Voreinstellungen aktiviert wäre.

also geht nicht, aber verstehe ich nicht.

tatsach. hab die ints durch longs ersetzt und jetzt gehts. wundert mich aber trotzdem, dass es erst nach ein paar zyklen ausgefallen ist anstatt gleich von anfang an zu streiken

Du scheinst mit ziemlich viel Unwissen gesegnet zu sein.
Oder um es positiv auszudrücken du hast ein großes Lernpotential was du realisieren kannst.

Vermutlich hast du dich nicht mit den Details der Integer-Rechnung beschäftigt.
Wenn man mit Variablen vom Typ unsigned int / unsigned long eine Rechnung macht

5 - 1000 dann kommt da nicht minus 995 heraus sondern wieder eine positive Zahl
Mit solchen und ähnlichen Effekten hängt das zusammen.

Um herauszufinden was genau passiert lässt du dir einfach ALLE und wenn ich schreibe ALLE dann meine ich ALLE Einzel-Werte, ALLE TEILErgebnisse auf dem seriellen Monitor ausgeben.

if (jetzt - relais1AusStartzeit >= relais1AusZeit && digitalRead(relais1Pin) == LOW)

print (jetzt)
print (relais1AusStartzeit)
print (jetzt - relais1AusStartzeit )
print (jetzt - relais1AusStartzeit >= relais1AusZeit)
print (digitalRead(relais1Pin) )
print (digitalRead(relais1Pin) == LOW )
usw. usw. usw. usw. usw. usw. usw.

Der reine Controller erweitert um serielle Ausgaben:

10:13:05.536 -> 
10:13:05.536 -> Start...
10:13:07.532 -> Actor 1 ausgelöst
10:13:08.538 -> Actor 1 gestoppt
10:13:09.536 -> Actor 2 ausgelöst
10:13:10.535 -> Actor 1 ausgelöst
10:13:11.536 -> Actor 1 gestoppt
10:13:12.539 -> Actor 2 gestoppt
10:13:13.537 -> Actor 1 ausgelöst
10:13:14.546 -> Actor 1 gestoppt
10:13:16.543 -> Actor 2 ausgelöst
10:13:16.543 -> Actor 1 ausgelöst
10:13:17.540 -> Actor 1 gestoppt
10:13:19.536 -> Actor 2 gestoppt
10:13:19.536 -> Actor 1 ausgelöst

mit diesem

code
// code editiert -> pinzuweisung und erste Schaltzeit für rel 2
struct ACTOR
{
  byte outPin;
  unsigned long onTime;
  unsigned long offTime;
  unsigned long switchTime;
};

ACTOR relOne {9, 1000, 2000, 0};
ACTOR relTwo {8, 3000, 4000, 0};
ACTOR actors[] = {relOne, relTwo};
const byte numActors = sizeof(actors) / sizeof(actors[0]);

const bool off = HIGH;  // Relaisbausteine sind oftmals LOW - aktiv...

void setup()
{
  Serial.begin(115200);                                             //
  Serial.println(F("\r\nStart..."));
  for (byte b = 0; b < numActors; b++)                           // durchzählen
  {
    pinMode(actors[b].outPin, OUTPUT);                           // initialisieren
    digitalWrite(actors[b].outPin, off);                         // setzen
  }
  relOne.switchTime = millis() + 2000;                           // erste Auslösezeit festlegen
  relTwo.switchTime = millis() + 3000;
}

void loop()
{
  uint32_t myTime = millis();                                    // aktuelle Zeit merken
  for (byte b = 0; b < numActors; b++)                           // Durchzählen
  {
    if (digitalRead(actors[b].outPin) == off)                    // Der PIN zustand ist gesetzt
    {
      if (myTime - actors[b].switchTime > actors[b].offTime)     // und die Zeit abgeaufen?
      {
        digitalWrite(actors[b].outPin, !off);                    // Pin neu setzen
        actors[b].switchTime = myTime;                           // Zeit merken
        Serial.print(F("Actor "));
        Serial.print(b + 1);
        Serial.println(F(" ausgelöst"));
      }
    }
    else                                                         // PIN zustand ist nicht gesetzt
    {
      if (myTime - actors[b].switchTime > actors[b].onTime)      // und Zeit abgelaufen
      {
        digitalWrite(actors[b].outPin, off);                     //
        actors[b].switchTime = myTime;                           //
        Serial.print(F("Actor "));
        Serial.print(b + 1);
        Serial.println(F(" gestoppt"));
      }
    }
  }
}

Hinweis: Die Zeiten des SerMon sind keine absoluten Zahlen und dienen nur als Schätzeisen.
Hinweis: Ich benutze eine andere Ausgabegeschwindigkeit

Ich hatte gehofft, das hättest du selber gesehen, dass mein Vorschlag nicht ganz komplett war, sondern eher als Ergänzungshinweis zu deiner Vorgabe zu sehen ist.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.