Go Down

Topic: Zwei parallele Programme laufen lassen (Read 2103 times) previous topic - next topic

kahmui

wenn du mal die beiden Codes vergleichst wirst du feststellen dass sich diese gar nichtso sehr unterscheiden. Außer dass meiner Codeduplikate vermeidet. Auch das hinzufügen eines weiteren Sensors/Relais wäre nur die Sache von einer einzigen Zeile. Gehe  es einfach mal durch und sollte etwas unklar sein dann frage.
Werde ich auf jeden Fall machen! Danke :)

gregorss

Quote
BlinkWithoutDelay.... klingt interessant, fühlt sich aber an wie 'ne Pfanne die an den Kopf fliegt.
Das Prinzip eines endlichen Automaten ist für einen Anfänger nicht leicht zu verstehen. Meistens liegt's aber nur daran, wie es erklärt wird.

Mein Gesabbel dazu findest Du hier. Eine Erklärung, die IMO erheblich leichter zu verstehen ist, findest Du hier.

Gruß

Gregor
Nicht lange fackeln, lass' Backen wackeln! (Seeed)

agmue

#17
Jun 26, 2020, 04:25 pm Last Edit: Jun 26, 2020, 06:47 pm by agmue
EDIT: Da ein vorhergehender Beitrag gelöscht wurde, habe ich meinen Text angepaßt.

Dann noch eine OOP-Variante, die auf combies Überlegungen basieren, der TO möge wählen:

Code: [Select]
class Pumpe {
    const byte irPin, pumpPin;
    const uint32_t punpzeit;
    uint32_t vorhin;
  public:
    Pumpe(const byte irPin, const byte pumpPin, const uint32_t punpzeit)
      : irPin(irPin), pumpPin(pumpPin), punpzeit(punpzeit), vorhin(0) {}

    void initPumpe() {
      pinMode(irPin, INPUT);
      pinMode(pumpPin, OUTPUT);
    }

    void runPumpe() {
      if (digitalRead(pumpPin)) {
        if (millis() - vorhin >= punpzeit)
        {
          digitalWrite(pumpPin, LOW);
        }
      } else {
        if (digitalRead(irPin)) {
          digitalWrite(pumpPin, HIGH);
          vorhin = millis();
        }
      }
    }
};

Pumpe pumpe[] {
  {2, 5, 2000},
  {3, 6, 2000}
};

void setup() {
  for (Pumpe &p : pumpe) p.initPumpe();
}

void loop() {
  for (Pumpe &p : pumpe) p.runPumpe();
}
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

kahmui

Erstmal vielen Dank an alle, die mir bei meinem Problem so tatkräftig zur Seite stehen. Ich weiß eure Rückmeldungen und Hilfestellungen wirklich sher zu schätzen!

Natürlich wäre es einfach den fertigen Code von euch zu nehmen. Allerdings nehme ich mir lieber die Zeit die ganzen Lösungsansätze mal genauer unter die Lupe zu nehmen, um auch das Konstrukt dahinter zu verstehen und auf lange Sicht selbst in der Lage sein zu können, solche Probleme zu lösen :)

Jetzt habe ich erstmal eine Menge Code-Schnipsel von euch die ich mir in Ruhe anschauen kann!

combie

Quote
Allerdings nehme ich mir lieber die Zeit die ganzen Lösungsansätze mal genauer unter die Lupe zu nehmen, um auch das Konstrukt dahinter zu verstehen und auf lange Sicht selbst in der Lage sein zu können, solche Probleme zu lösen :)
So ist recht!

Hast du denn schon so ein schönes dickes modernes C++ Buch?
Nein? Dann anschaffen!
Säge kein Sägemehl.

my_xy_projekt

Dann hier auch noch mein fertiges Konstrukt - mit ein wenig Kommentar und serieller Ausgabe ;)

Code: [Select]

// HIER DIE ANZAHL DER KREISE ANGEBEN
const int Kreise = 2;
// Für jeden Kreis ab hier einen Wert angeben!
// Hier die Angabe der PIN
const int irPin[] = {2, 3};
const int pumpPin[] = {5, 6};
// Hier die Angabe für die Zeiten
const int laufzeit[] = {2000, 2000};
const int pausezeit[] = {3000, 3000} ;
// Zeitvariablen init immer 0
unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};
// Ende Eintrag Werte
void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT);
    pinMode(pumpPin[i], OUTPUT);
  }
}
void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    if ((digitalRead(irPin[i])) && (millis() - pausemillis[i] > pausezeit[i]) && (!digitalRead(pumpPin[i])))
    {
      Serial.print("Sensor ");
      Serial.print(i+1);
      Serial.println(": Objekt erkannt!");
      digitalWrite(pumpPin[i], HIGH);
      laufmillis[i] = millis();
    }
    if ((millis() - laufmillis[i] > laufzeit[i]) && (digitalRead(pumpPin[i])))
    {
      Serial.println("Pumpe aus!");
      digitalWrite(pumpPin[i], LOW);
      pausemillis[i] = millis();
    }
  }
}

agmue

Allerdings nehme ich mir lieber die Zeit die ganzen Lösungsansätze mal genauer unter die Lupe zu nehmen, um auch das Konstrukt dahinter zu verstehen und auf lange Sicht selbst in der Lage sein zu können, solche Probleme zu lösen :)
Meine OOP-Variante faßt die Informationen, die zusammengehören, zusammen. Sagt combie und damit hat er mich eingefangen, weshalb ich es mal zeigen wollte.

Bei Interesse bitte nachfragen :)

Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

combie

Quote
.... faßt die Informationen, die zusammengehören, zusammen. Sagt combie ....
Ja, das sage ich!
> Fasse zusammen, was zusammen gehört!

Ein wichtiges Stilmittel, um Übersicht zu schaffen.

Säge kein Sägemehl.

kahmui

#23
Jun 30, 2020, 11:26 am Last Edit: Jun 30, 2020, 11:40 am by kahmui
Code: [Select]

const int ir1Pin = 2;      // Infrarotsensor 1
const int rel1Pin = 5;    // Relais 1

const int laufzeit = 1000;
const int pausezeit = 5000;

long pausemillis1 = 0;
long laufmillis1 = 0;


void setup()
{
  Serial.begin(115200);
  pinMode(ir1Pin, INPUT);
  pinMode(rel1Pin, OUTPUT);
}


void loop()
{
  if ((digitalRead(ir1Pin)) && (millis() - pausemillis1 > pausezeit) && (!digitalRead(rel1Pin)))
  {
    Serial.println("Sensor 1: Objekt erkannt!");
    digitalWrite(rel1Pin, HIGH);
    laufmillis1 = millis();
   
  }
  if ((millis() - laufmillis1 > laufzeit) && (digitalRead(rel1Pin)))
  {
    Serial.println("Pumpe aus!");
    digitalWrite(rel1Pin, LOW);
    pausemillis1 = millis();
  }
}



Dieser Code funktioniert in der Simulation einwandfrei (erstmal mit nur einem Kreis).

In meinem Nachbau hab ich allerdings das Problem, dass das Relais nach Einschalten des Arduino permanent schaltet (1s aus, 5s an) Was läuft falsch?

Zusätzlich beibt das Relais permanent geschaltet WÄHREND ich meine Hand vor den Sensor halte.


combie

Wenn dir deine Automatenzustände durcheinander geraten, dann ist es meist an der Zeit, den Teil nochmal zu überdenken.

Tipp:
Denke in Zuständen
Benenne die Zustände
Schaffe klare Zustandswechsel.

Säge kein Sägemehl.

kahmui

#25
Jun 30, 2020, 02:03 pm Last Edit: Jun 30, 2020, 02:27 pm by kahmui
Ich gehe das hier nochmal Step für Step für einen Kreis durch. Vielleicht könnt ihr fehlerhafte Gedankengänge feststellen und mich korrigieren:

Code: [Select]

int ir1Pin = 2;    // Infrarotsensor 1
int relais1Pin = 5;   // Relais 1

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(relais1Pin , OUTPUT);
}

 
void loop() {
 digitalWrite(relais1Pin , HIGH);
 digitalWrite(ir1Pin, HIGH);
 
 int i1 = digitalRead(ir1Pin);
  if( i1 == LOW){   
      Serial.println("Sensor 1: Objekt erkannt!");     
      digitalWrite(relais1Pin , LOW);                               
      delay(2000);                                                 
  }
}



Damit schaltet das Relais schonmal wenn ich meine Hand vor den Sensor halte.


Als nächstes muss ich schauen, dass ich mein delay() durch millis() ersetze, um die Möglichkeit zu haben, zwei voneinander unabhängige Kreise laufen zu lassen und die Laufzeit sowie die anschließende Zwangspause zu timen.

Dazu benötige ich 2 weitere konstante Variablen sowie je Kreis 2 Variablen mit unsigned long:

- zwei konstante Variablen für die Laufzeit und die Pausenzeit
Code: [Select]
const int laufzeit1 = 1000
const int pausezeit1 = 3000


- zwei Variablen (je Kreis) für die Zeitenmessung von Laufzeit und Pause
Code: [Select]
unsigned long laufmillis1
unsigned long pausemillis1


Sieht im Kopf dann so aus:
Code: [Select]

int ir1Pin = 2;    // Infrarotsensor 1
int relais1Pin = 5;   // Relais 1
int ir2Pin = 3;   // Infrarotsensor 2
int relais2Pin = 6;   // Relais 2

const int laufzeit1 = 1000;   // Laufzeit der Relaisbetätigung Kreis 1
const int pausezeit1 = 3000;   // Laufzeit der Zwangspause nach Relaisbetätigung Kreis 1

unsigned long laufmillis1;
unsigned long pausemillis1;

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(relais1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(relais2Pin, OUTPUT);
}


Dann setze ich den Zustand meiner Bauteile (Sensor und Relais) fest und vergebe Namen für digitalRead:

Code: [Select]
void loop() {
 digitalWrite(relais1Pin, HIGH);
 digitalWrite(ir1Pin, HIGH);
 
 int i1 = digitalRead(ir1Pin);
 int r1 = digitalRead(ir1Pin);



Als nächstes muss ich meine Bedingungen zum Betätigen des Relais entsprechend anpassen und festlegen was passieren soll, wenn alle Bedingungen erfüllt sind.

Dazu prüfe ich:
- ob mein Infrarotsensor 1 etwas erkennt,
- mein Relais ausgeschaltet ist,
- die vergangene Zeit von jetzt bis zu meiner Pause größer als die festgelegte Pausenzeit ist (hier ist wahrscheinlich mein gedanklicher Knackpunkt)

und teile ihm mit:
- , dass ich eine Textzeile im Monitor haben möchte
- , dass Relais 1 schalten soll
- wie lange Relais 1 schalten soll

Code: [Select]

if ((i1 == LOW) && (r1 == HIGH) && (millis() - pausemillis1 > pausezeit1))  {
      Serial.println("Sensor 1: Objekt erkannt!");     
      digitalWrite(relais1Pin, LOW);                               
      laufmillis1 = millis();
}

 

Damit diese Bedingung funktioniert, muss ich zusätzlich sagen, dass er nach der Laufzeit:
- das Relais 1 abschaltet
- die vergangene Zeit von jetzt bis zu meiner erneut möglichen Betätigung des Sensors größer als die festgelegte Zwangspausenzeit ist.

Dazu prüfe ich
- ob das Relais 1 betätigt ist
- die Laufzeit von Relais 1 abgelaufen ist.

Code: [Select]

if ((r1 == LOW) && (millis() - laufmillis1 > laufzeit1)) {
       Serial.println("Relais ausgeschaltet!");
       digitalWrite(relais1Pin, HIGH);
       pausemillis1 = millis();
}


Fasst man das ganze jetzt nochmal zusammen sieht es wie folgt aus:

Code: [Select]
int ir1Pin = 2;    // Infrarotsensor 1
int relais1Pin = 5;   // Relais 1
int ir2Pin = 3;   // Infrarotsensor 2
int relais2Pin = 6;   // Relais 2

const int laufzeit1 = 1000;   // Laufzeit der Relaisbetätigung Kreis 1
const int pausezeit1 = 3000;   // Laufzeit der Zwangspause nach Relaisbetätigung Kreis 1

unsigned long laufmillis1;
unsigned long pausemillis1;

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(relais1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(relais2Pin, OUTPUT);
}

void loop() {
  digitalWrite(relais1Pin, HIGH);
  digitalWrite(ir1Pin, HIGH);
 
  int i1 = digitalRead(ir1Pin);
  int r1 = digitalRead(relais1Pin);

  if ((i1 == LOW) && (r1 == HIGH) && (millis() - pausemillis1 > pausezeit1))  {
      Serial.println("Sensor 1: Objekt erkannt!");     
      digitalWrite(relais1Pin, LOW);                               
      laufmillis1 = millis();
  }
  if ((r1 == LOW) && (millis() - laufmillis1 > laufzeit1)) {
       Serial.println("Relais ausgeschaltet!");
       digitalWrite(relais1Pin, HIGH);
       pausemillis1 = millis();
  }
}


Alles drin alles dran. Nichts funktioniert :( SObald ich die millis Funktion mit drin hab reagiert weder das Relais noch der Sensor.

noiasca

gib dir auch die Werte deiner Variablen auf der seriellen aus bevor du pins veränderst!
Vermutlich hast du eine falsche Logik.

da du es zweimal machen musst (für beide Ifs), mach dir eine eigene Funktion
Code: [Select]

void debugAusgabe()
{

Serial.print ("irPin"); Serial.println(digitalRead(irPin);
Serial.print ("millis"); Serial.println(millis()); // mit der Unschönheit, dass es bei der Ausgabe schon weiter ist, musst leben
Serial.print ("pausemillis1"); Serial.println(pausemillis1);
usw.



zumindest kannst du dann beobachten auf Grund welcher Werte du in welchem if gelandest bist und deine (hingeschriebene) Logik überprüfen
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

combie

#27
Jun 30, 2020, 02:29 pm Last Edit: Jun 30, 2020, 02:35 pm by combie
Quote
Ich gehe das hier nochmal Step für Step für einen Kreis durch. Vielleicht könnt ihr fehlerhafte Gedankengänge feststellen und mich korrigieren:
Ich kann leider so vielen Entscheidungen/Bedingungen nicht folgen.
(und du selber offensichtlich auch nicht wirklich)

Da wäre also ein Punkt wo man/du ansetzen könntest.
Quote
Tipp:
Denke in Zuständen
Benenne die Zustände
Schaffe klare Zustandswechsel.
Beispiel:
Code: [Select]
enum Zustand {Bereitschaft,Pumpen,Pausieren};



Ein Tipp am Rande:
Das durchnummerieren von Variablen/Konstanten ist eigentlich IMMER eine schlechte Idee.
Es führt zu Codeduplikaten
Zu C&P Fehlern.
Säge kein Sägemehl.

my_xy_projekt

Code: [Select]

void loop() {
 digitalWrite(relais1Pin , HIGH);
 digitalWrite(ir1Pin, HIGH);

[...]

Was soll da passieren?

Code: [Select]

int i1 = digitalRead(ir1Pin);
int r1 = digitalRead(ir1Pin);
[...]
if ((i1 == LOW) && (r1 == HIGH)


Was soll da passieren?
Hinweis: Diese Bedingung kann niemals erfüllt sein.

kahmui

Was soll da passieren?

Code: [Select]

int i1 = digitalRead(ir1Pin);
int r1 = digitalRead(ir1Pin);
[...]
if ((i1 == LOW) && (r1 == HIGH)


Was soll da passieren?
Hinweis: Diese Bedingung kann niemals erfüllt sein.

Zu 1.
Die Idee war, die beiden Bauteile erstmal auf den Zustand high, also nicht aktiv zu zwingen.


Zu 2.
Es heißt natürlich
int i1 = digitalRead(ir1Pin);
int r1 = digitalRead(relais1Pin);

War ein Kopierfehler.


Bin bisher auch noch nicht zu einer Lösung gekommen. Um die Anlage zu testen und Versuche zu fahren läuft das Programm erstmal notwendigerweise mit der einfachen delay Variante.



Um dem ganzen ein wenig Durchblick zu verschaffen: es geht um eine Anlage die über zwei Kreise zwei bestimmte Desinfektionsmittel für hygienische Bereiche mittels zweier Pumpen, die über zwei Relais geschaltet werden, auftragen. Die beiden Kreise müssen am Ende zwingend unabhängig voneinander betrieben werden können,  da zu unterschiedlichen Zeiten unterschiedliche Mittel genutzt werden müssen.
Die Anlage steht nun und wird getestet. Da ich mit dem Code leider nicht weiterkomme, greife ich für Testzwecke auf meine erste Variante zurück.

Go Up