Go Down

Topic: Millis() in Switch Case Problem (Read 1 time) previous topic - next topic

Floetzinger

guten Abend zusammen,
gibt es bekannte Schwierigkeiten bei derSwitch Case Anwendung und Millis()?

Prbier mich grad aus, ob ich bereits bekannte und erprobte Sketchteile auch in anderen Sketchen nutzen kann.
Bin dabei, eine primitive Pendelzugsteuerung mit 3 Halte/ Wendepunkte zu entwickeln.
Prizip: Überfahren eines Hallsensores löst eine zeitlich begrenzte Aktion aus (i.e. Ausgang 2 sec. High).
Allerdings stecke ich bereits beim ausschalten nach x Sec. fest.
da gibt es doch bestimmt den ein oderen anderen Lösungsschubser.
Der  (exemplarisch) Problembereich beginnt bei Case 1 und endet beim Break.
Löse ich einen , löse ich bestimmt alle (hoffe ich).

alle anderen Dinge wie Anzeige im LCD Display funktionieren, Case Auswertung funktioniert.
Danke für's weiterhelfen.

Code: [Select]

 

//***** Angaben zum Display*****
  #include <Bounce2.h>// Taster entprellen
  #include <Wire.h>   // Verdrahtung LCD Display
  #include <LiquidCrystal_I2C.h> // Ansteuerung LCD Display
  LiquidCrystal_I2C lcd(0x27,20,4); // Datenleitungen an A4/ A5
//***** Angaben zum Entprellen***** 
  Bounce debouncer = Bounce();
//***** Konstanzen Zuordnung der Taster/ Hallsensoren*****
  const int HSQ1 = 2;
  const int HSQ2 = 3;
  const int HSQ3 = 4;
  const int Taster_Start= 5;
//***** Konstanzen Zuordnung der Ansteuerung Relais*****
  const int Relais_HSQ1 = 7;
  const int Relais_HSQ2 = 8;
  const int Relais_HSQ3 = 9;
  const int Relais_Weiche_Abz = 10;
  const int Relais_Weiche_Ger = 11;
  const int Relais_Start= 12;
  const int Relais_Fahrstrom = 13;
  const int Relais_Umpolung = 14;
//***** Variablen der Startzeiten*****
  unsigned long Startzeit1 =0;
  unsigned long Startzeit2 =0;
  unsigned long Startzeit3 =0;
  unsigned long Startzeit4 =0;
  unsigned long Wecker = 3000;
//*****Beginn Setup Bereich*****
void setup()
   // Pin Modus  Ausgang Relais
  {
   pinMode(Relais_HSQ1,OUTPUT); // Pin 7
   pinMode(Relais_HSQ2,OUTPUT); // Pin 8
   pinMode(Relais_HSQ3,OUTPUT); // Pin 9
   pinMode(Relais_Weiche_Abz,OUTPUT); // Pin 10
   pinMode(Relais_Weiche_Ger,OUTPUT); // Pin 11
   pinMode(Relais_Start,OUTPUT);      // Pin 12
   pinMode(Relais_Fahrstrom,OUTPUT);  // Pin 13
   pinMode(Relais_Umpolung,OUTPUT);   // Pin 14
   // Pin Modus Hallsensoren/ Taster
   pinMode(HSQ1,INPUT); // Pin 2
   pinMode(HSQ2,INPUT); // Pin 3
   pinMode(HSQ3,INPUT); // Pin 4
   pinMode(Taster_Start,INPUT); // Pin 5
   // Entprellen vom Taster
   debouncer.attach(Taster_Start);
   debouncer.interval(5);
   // Initalisierung LCD Display
   lcd.init();
   lcd.backlight();
    }
//***** Ende Setup Bereich*****

//*****Beginn Loop Bereich*****   
  void loop() {
  int Eingabe = 0; // Variable Switch Case Auswertung
  //***** Taster entprellen und auswerten*****
  debouncer.update();
  int value = debouncer.read();
  if ( value == LOW) {
  digitalWrite(Relais_Start,HIGH );
   }
  else {
 digitalWrite(Relais_Start, HIGH );
  Eingabe = 4;// Änderung der Variable
  }
//*****Abfrage Hallsensoren HSQ1- HSQ3*****
if (digitalRead(HSQ1)==HIGH){
 Eingabe = 1;// Änderung der Variable
}
if (digitalRead(HSQ2)==HIGH){
 Eingabe = 2;// Änderung der Variable
 }
 if (digitalRead(HSQ3)==HIGH){
 Eingabe = 3;// Änderung der Variabble
 }
//*****Beginn Switch Case*****
switch (Eingabe){
case 1://***** Abfrage HSQ1 *****
 if (digitalRead(HSQ1)==HIGH){
     digitalWrite(Relais_HSQ1,HIGH);
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0,0); // Cursorpos 0, Zeile 1   
    lcd.print(F("Hallsen. HSQ1 aktiv"));
   
  Startzeit1=millis();
  }
  else if (millis()-Startzeit1>=2000){
          digitalWrite(Relais_HSQ1,LOW);
         
  }
break;
case 2://***** Abfrage HSQ2 *****
if (digitalRead(HSQ2)==HIGH){
    digitalWrite(Relais_HSQ2,HIGH);
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0,1); // Cursorpos 1, Zeile 2 
    lcd.print(F("Hallsen. HSQ2 aktiv"));
 
   Startzeit2=millis();
  }
  else if (millis()-Startzeit2>=2000){
   digitalWrite(Relais_HSQ2,LOW);
  }
break;
case 3:////***** Abfrage HSQ3 *****
if (digitalRead(HSQ3)==HIGH){
  digitalWrite(Relais_HSQ3,HIGH);
 
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0,2); // Cursorpos 1, Zeile 2 
    lcd.print(F("Hallsen. HSQ3 aktiv"));
   
   Startzeit2=millis();
  }
  else if (millis()-Startzeit2>=2000){
   digitalWrite(Relais_HSQ2,LOW);
  }
break;
case 4:////***** Abfrage Taster  *****
if (digitalRead(Taster_Start)==HIGH){
   
    digitalWrite(Relais_Weiche_Ger,HIGH);
   
    lcd.backlight();
    lcd.clear();
    lcd.setCursor(0,3); // Cursorpos 1, Zeile 2 
    lcd.print(F("Taster aktiv"));
 
   Startzeit4=millis();
  }
  else if (millis()-Startzeit4>=5000){
  digitalWrite(Relais_Weiche_Ger,LOW);
  }
break;
default:; 
}//***** Ende Switch Case

 
}//***** Ende Loop Bereich*****


Doc_Arduino

Hallo,

du aktualisierst vor jeden Vergleich den Zeitmerker. Wie soll dann der Vergleich jemals wahr werden?
Nachdem der Vergleich gültig wurde zieht man den Zeitmerker nach auf die aktuelle Zeit damit er für den nächsten Vergleich erneut warten kann.

Code: [Select]

case 1://***** Abfrage HSQ1 *****
        if (digitalRead(HSQ1) == HIGH) {
          digitalWrite(Relais_HSQ1, HIGH);
            
          Startzeit1 = millis();
        }
        else if (millis() - Startzeit1 >= 2000) {
          digitalWrite(Relais_HSQ1, LOW);
        }
        break;


ändern in
Code: [Select]

case 1://***** Abfrage HSQ1 *****
        if (digitalRead(HSQ1) == HIGH) {
          digitalWrite(Relais_HSQ1, HIGH);
        }
        else if (millis() - Startzeit1 >= 2000) {
          Startzeit1 = millis();
          digitalWrite(Relais_HSQ1, LOW);
        }
        break;
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

MicroBahner

#2
Dec 03, 2018, 06:40 pm Last Edit: Dec 03, 2018, 06:41 pm by MicroBahner
Nein, das ist nicht das Problem. Er startet die Zeit im if-Zweig, wenn das Relais eingeschaltet wird, und fragt die Zeit im else-Zweig ab. Das wäre schon in Ordnung.
Allerdings steht der else-Zweig auch im case 1. Und wenn der Hall-Sensor inaktiv ist, kommt er da gar nicht mehr hin - kann also das Ablaufen der Zeit gar nicht mehr erkennen. Es ist ziemlich unsinnig , denn case nur bei aktivem Hall-Sensor aufzurufen, und dann im case-Zweig nochmal nach dem Status des Hallsensors verzweigen zu wollen.
Gruß, Franz-Peter

Doc_Arduino

Hallo,

stimmt. Das rücksetzen muss außerhalb von switch-case erfolgen.
In case3 stimmt auch etwas mit den Variablen nicht. Alles 2 statt 3 am Ende. Das nur am Rande.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Hallo,

Wenn ich das richtig überblicke steuert jeder Sensor ein bestimmtes Relais?
Wenn Sensor aktiv Relais umschalten?
Wenn Sensor nicht mehr aktiv Relais verzögert zurückschalten?
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

#5
Dec 03, 2018, 08:58 pm Last Edit: Dec 03, 2018, 09:45 pm by Doc_Arduino
Hallo,

in der Hoffnung das meine Annahme stimmt, hab ich das komplett umgebaut und einfach mal erlerntes konsequent angewendet.
Das mag für dich TO erstmal komplizierter aussehen, vereinfacht aber fast alles mit dem Umgang der Variablenwerte.
Vereinfacht gesagt werden ständig alle struct Arrays mittels Indexdurchlauf abgearbeitet.
Erst werden alle Sensoren eingelesen und im state Array gespeichert.
Dann wird state verglichen.
Wenn das jeweilige state wahr ist, wird das zugehörige Relais eingeschalten.
Wenn das jeweilige state unwahr ist, wird die Zeit abgewartet und das zugehörige Relais ausgeschalten.

Zur Zeit weiß ich nur nicht recht ob man den Taster mit ins struct Array nimmt und damit die Funktion read_sensor aller paar ms aufruft, was dann alle betrifft oder gänzlich separat behandlet inkl. Entprellung. Meinungen?

Ich hoffe ich habe die Logik überall richtig korrigiert, weil ich mit Input Pullups arbeite.

Code: [Select]
/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.7
  Arduino Mega2560
  03.12.2018
  https://forum.arduino.cc/index.php?topic=583029.0
*/

struct t_setup
{
  const byte pin_S;
  const byte pin_R;
  bool state;
  unsigned int delay;
  unsigned long last_ms;

  // Konstruktor
  t_setup (byte _S, byte _R, unsigned int _delay) :
    pin_S(_S),
    pin_R(_R),
    state(false),
    delay(_delay),
    last_ms(0)
  {}
};

t_setup KOMBI[] = {
  {2, 7, 2000},  // Sensorpin, Relaispin, Delay
  {3, 8, 3000},
  {4, 9, 4000},
};

unsigned long global_millis;

const byte ANZAHL = sizeof(KOMBI) / sizeof(t_setup);


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

  Serial.print("Anzahl "); Serial.println(ANZAHL);      // Debug

  // bei Bedarf Pullup aktivieren, ansonsten auskommtieren
  /*
  for (byte i = 0; i < ANZAHL; i++) {
    pinMode(KOMBI[i].pin_S, INPUT_PULLUP);
  }
  */

  // Ausgänge setzen
  for (byte i = 0; i < ANZAHL; i++) {
    digitalWrite(KOMBI[i].pin_R, LOW);
    pinMode(KOMBI[i].pin_R, OUTPUT);
  }
}


void loop()
{
  global_millis = millis();                   // für einen loop Umlauf für alle die gleiche Zeit

  read_sensor();

  Auswertung();
}

// ****** Funktionen ******
void read_sensor()
{
  for (byte i = 0; i < ANZAHL; i++) {
    KOMBI[i].state = digitalRead(KOMBI[i].pin_S);
  }
}

void Auswertung()
{
  for (byte i = 0; i < ANZAHL; i++) {         // alle Sensoren per Indexdurchlauf
    if (KOMBI[i].state) {                     // true ?
      digitalWrite(KOMBI[i].pin_R, HIGH);
      KOMBI[i].last_ms = global_millis;
    }

    if (!KOMBI[i].state) {                    // false?
      if (global_millis - KOMBI[i].last_ms > KOMBI[i].delay) {
        digitalWrite(KOMBI[i].pin_R, LOW);
      }
    }
  }
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

agmue

#6
Dec 03, 2018, 09:21 pm Last Edit: Dec 03, 2018, 09:23 pm by agmue
Huch, wie bin ich denn in dieses Thema gerutscht? Meinst Du eventuell combie?

Ruft die Funktion nicht danach, eine Methode zu werden? Irgendwann wäre dann auch ANZAHL überflüssig, so wie bei den Blumen: for (Blumen &b : blumen) b.init();

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

Doc_Arduino

#7
Dec 03, 2018, 09:45 pm Last Edit: Dec 03, 2018, 09:49 pm by Doc_Arduino
Hallo,

upps, ich hatte den Grundstock von einem anderen Sketch übernommen, Latzefratz falls du dich erinnerst.
Ich nehms raus.  ;)

Darfste gern optimieren. Tue dir keinen Zwang an. Dann hat man die Wahl zwischen den Varianten.

Zudem der Taster noch rein muss. Den kann man auch als Sensor betrachten. Da bin ich mir immer noch nicht schlüssig wie es am Dümmsten ist.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

agmue

Tue dir keinen Zwang an.
Na gut, ich würde es etwas zusammenfassen (alles ungetestet):

Code: [Select]
void loop()
{
  global_millis = millis();                   // für einen loop Umlauf für alle die gleiche Zeit

  for (byte i = 0; i < ANZAHL; i++) {         // alle Sensoren per Indexdurchlauf
    Auswertung(i);
  }
}

// ****** Funktionen ******
void Auswertung(sensor)
{
  if (digitalRead(KOMBI[sensor].pin_S)) {                     // true ?
    digitalWrite(KOMBI[sensor].pin_R, HIGH);
    KOMBI[sensor].last_ms = global_millis;
  } else {                                                    // false?
    if (global_millis - KOMBI[sensor].last_ms > KOMBI[sensor].delay) {
      digitalWrite(KOMBI[sensor].pin_R, LOW);
    }
  }
}

Ich sehe es als Schritt zur Methode:

Code: [Select]
void Auswertung()
{
  if (digitalRead(pin_S)) {                     // true ?
    digitalWrite(pin_R, HIGH);
    last_ms = global_millis;
  } else {                                      // false?
    if (global_millis - last_ms > delay) {
      digitalWrite(pin_R, LOW);
    }
  }
}

Dann in loop aber

Code: [Select]
  for (byte i = 0; i < ANZAHL; i++) {         // alle Sensoren per Indexdurchlauf
    KOMBI[i].Auswertung;
  }

oder man überläßt das Zählen dem "System":

Code: [Select]
for (t_setup &k : KOMBI) k.Auswertung();
Bin gespannt, was der TO zum Fehlen von switch/case meint :)
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Hausknecht

#9
Dec 04, 2018, 09:10 am Last Edit: Dec 04, 2018, 09:10 am by Hausknecht
Wenn ich solche Programme sehe, dann komme ich mir sooo klein vor.
Ihr habt's geschafft ich hab das Buch "Der C++ Programmierer" von Ulrich Breymann angefangen zu lesen.  :)
___________________________________________________
Grüße Hans

agmue

Wenn ich solche Programme sehe, dann komme ich mir sooo klein vor.
Dann können wir uns zusammentun, denn ich plappere nur nach, was combie mal in OOP gezeigt hat. Aber Übung macht den Meister, auch wenn ich der wohl nie werde. Aber der Weg dahin macht Spaß.

Als fauler Mensch hat mich for ohne explizite Zählung gereizt, der Compiler übernimmt das. Damit entfällt eine mögliche Fehlerquelle.

Ich traue mich nur deshalb, Dinge hier zu veröffentlichen, weil Fehler gnadenlos angesprochen werden. Darauf kann ich mich verlassen, da bleibt am Ende kein Blödsinn übrig.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Doc_Arduino

Hallo,

Hausknecht:

Keine Sorge ich stecke da auch noch mittendrin.

Das ist nur die Zusammensetzung bzw. gemeinsame Nutzung von struct und array. Das vermeidet die Ellenlangen globalen Variablenlisten wo am Ende niemand mehr durchblickt. Jedem Eingang ist ein Ausgang inkl. einer Verzögerungszeit zugewiesen. Die eigentlichen Werte werden mit t_setup KOMBI[] = { ... } initialisiert. Damit man default Werte nicht extra angegeben muss bei der Initialisierung ist im struct noch ein Konstruktor hinzugefügt wurden.

Mit struct baut man sich eigene Datentypen. Zu besseren Erkennung setze ich ein t_ davor.
Mit arrays baut man "Listen" von Werten die aufgefädelt sind.
Array Zugriff auf dessen Elemente erfolgt mit dem Index.
Zugriffe auf eine struct Element erfolgt mit dem Punkt-Operator.
Ich denke soweit ist dir das mit Buch klar.

Code: [Select]

struct t_setup
{
  byte pin;
  unsigned int delay;
};

Der neue Datentyp besteht aus einem byte Wert und einem unsigned int Wert.

Variablen mit dem neuen Datentyp erstellt man

t_setup var1;
t_setup var3;
t_setup var3;

oder 
Code: [Select]

struct t_setup
{
  byte pin;
  unsigned int delay;
} var;

Zugriff lautet nun var.pin oder var.delay

Wenn du nun 2 struct Arrays angelegt hast, Array Name KOMBI, Datentyp t_setup
Code: [Select]

t_setup KOMBI[] = {
  {2, 2000},          // Index 0   KOMBI[0].pin oder KOMBI[0].delay
  {3, 3000},          // Index 1   KOMBI[1].pin oder KOMBI[1].delay
};

erfolgt der Zugriff erst mittels Index und dann mit der struct Variablen.
Zum Schluss wird nur noch in einer for Schleife, worin für alle die Indexnummer gleich ist, darauf zugriffen.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Floetzinger

uih, ne Menge zu leen und zu verstehen lernen.
Erstmal Danke.
mehr Rückmeldung nach dem Studium eurer ansätze und Hinweise/ Vorschläge.
Ich versuche das mal zu erkennen, wie,wann, wo welche Frage/ Antwort nötig ist.
Lieben Dank.
bis später dann!

wbr. Flötzinger

Floetzinger

...fix mal alles zusammen in ein Dokument kopiert.
Versuch das zuverstehen.
vermutlich sieht/ liest man sich erst Freitag/ Samstag wieder...

Flötzinger

Floetzinger

Hallo, just nen Moment Zeit gefunden.
Erstmal zum Verstehen würde ich das Switch Case Szenario aufdröseln und lernen wie das genau geschrieben werden muss, damit es funktioniert.

Danach die " Struct" Geschichte und abschliessend den Rest.
...denke mir, so lerne ich drei Varianten richtig schreiben und anzuwenden.

hier Quasi mein Teil 1 im Quote mit anschliessneder Frage:

Hallo,

du aktualisierst vor jeden Vergleich den Zeitmerker. Wie soll dann der Vergleich jemals wahr werden?
Nachdem der Vergleich gültig wurde zieht man den Zeitmerker nach auf die aktuelle Zeit damit er für den nächsten Vergleich erneut warten kann.

Code: [Select]

case 1://***** Abfrage HSQ1 *****
        if (digitalRead(HSQ1) == HIGH) {
          digitalWrite(Relais_HSQ1, HIGH);
           
          Startzeit1 = millis();
        }
        else if (millis() - Startzeit1 >= 2000) {
          digitalWrite(Relais_HSQ1, LOW);
        }
        break;


ändern in
Code: [Select]

case 1://***** Abfrage HSQ1 *****
        if (digitalRead(HSQ1) == HIGH) {
          digitalWrite(Relais_HSQ1, HIGH);
        }
        else if (millis() - Startzeit1 >= 2000) {
          Startzeit1 = millis();
          digitalWrite(Relais_HSQ1, LOW);
        }
        break;





Nein, das ist nicht das Problem. Er startet die Zeit im if-Zweig, wenn das Relais eingeschaltet wird, und fragt die Zeit im else-Zweig ab. Das wäre schon in Ordnung.
Allerdings steht der else-Zweig auch im case 1. Und wenn der Hall-Sensor inaktiv ist, kommt er da gar nicht mehr hin - kann also das Ablaufen der Zeit gar nicht mehr erkennen. Es ist ziemlich unsinnig , denn case nur bei aktivem Hall-Sensor aufzurufen, und dann im case-Zweig nochmal nach dem Status des Hallsensors verzweigen zu wollen.
...bedeutet für mich, den else if teil komplett hinter der "default:" Anweisung zu schreiben?
 btw: Schreibfehler im Case 3 korrigiert.

Go Up