Man-Eh, die millis ärgern mich...

Die verzögerte Pumpenabschaltung soll im Display(MicroView) jede Sekunde runtergezählt angezeigt werden.

Wird merkwürdigerweise nur letze case angezeigt, also 3s.

switch (millis() - altMillis)
{
case 1000 … 1999:
Zeile1 = “Pume aus in 1s”;
DisplayChange = HIGH;
break;
case 2000 … 2999:
Zeile1 = “Pume aus in 2s”;
DisplayChange = HIGH;
break;
case 3000 … 3999:
Zeile1 = “Pume aus in 3s”;
DisplayChange = HIGH;
break;
}

Was mache ich falsch?

#include <MicroView.h>      // include MicroView library

int Pin0 = 0;
int Pin1 = 1;
int Pin2 = 2;
int Pin3 = 3;
int Pumpe = 5;

int State0 = HIGH;
int LastState0 = HIGH;
int State1 = HIGH;
int LastState1 = HIGH;
int State2 = HIGH;
int LastState2 = HIGH;
int State3 = HIGH;
int LastState3 = HIGH;
int Pumpenverzoegerung = 5000;

String Zeile1;
String Zeile2;
String Zeile3;
String Zeile4;
String Zeile5;
String Zeile6;
String Ereignis;

bool AutoPumpeAus = LOW;
bool AutoPumpeAusErkannt = LOW;
bool DisplayChange = HIGH;

unsigned long aktMillis, altMillis, printMillis, pumpenMillis;  // speichert wie viele Sekunden seit derletzten Änderung vergangen sind




void setup()
{
  Serial.begin(9600);
  
  /* Setup the pin direction. */
  pinMode(Pin0, INPUT);
  pinMode(Pin1, INPUT);
  pinMode(Pin2, INPUT);
  pinMode(Pin3, INPUT);
  pinMode(Pumpe, OUTPUT);

  digitalWrite(Pumpe, LOW);
  
  uView.begin();        // start MicroView
  uView.clear(PAGE);      // clear page
  uView.print("Initialisation complete.");
  uView.display();
  delay(2000);
}









void loop()
{
  State0 = digitalRead (Pin0);
  State1 = digitalRead (Pin1);
  State2 = digitalRead (Pin2);
  State3 = digitalRead (Pin3);
  


  //Aktion für Pin0
  if(LastState0 == LOW && State0 == HIGH)
  {
    Zeile2 = "Spr O aus";
    DisplayChange = HIGH;
    LastState0 = State0;
    AutoPumpeAus = HIGH;
  }

  if(LastState0 == HIGH && State0 == LOW)
  {
    Zeile2 = "Spr O an";
    Zeile1 = "Pumpe an";
    DisplayChange = HIGH;
    LastState0 = State0;
    digitalWrite(Pumpe, HIGH);
    AutoPumpeAus = LOW;
  }



  //Aktion für Pin1
  if(LastState1 == LOW && State1 == HIGH)
  {
    Zeile3 = "Spr S aus";
    DisplayChange = HIGH;
    LastState1 = State1;
    AutoPumpeAus = HIGH;
  }

  if(LastState1 == HIGH && State1 == LOW)
  {
    Zeile3 = "Spr S an";
    Zeile1 = "Pumpe an";
    DisplayChange = HIGH;
    LastState1 = State1;
    digitalWrite(Pumpe, HIGH);
    AutoPumpeAus = LOW;
  }

  

  
  //Aktion für Pin2
  if(LastState2 == LOW && State2 == HIGH)
  {
    Zeile4 = "Spr W aus";
    DisplayChange = HIGH;
    LastState2 = State2;
    AutoPumpeAus = HIGH;
  }

  if(LastState2 == HIGH && State2 == LOW)
  {
    Zeile4 = "Spr W an";
    Zeile1 = "Pumpe an";
    DisplayChange = HIGH;
    LastState2 = State2;
    digitalWrite(Pumpe, HIGH);
    AutoPumpeAus = LOW;
  }




  //Aktion für Pin3
  if(LastState3 == LOW && State3 == HIGH)
  {
    Zeile5 = "Spr N aus";
    //Zeile1 = "Pumpe aus";
    DisplayChange = HIGH;
    LastState3 = State3;
    digitalWrite(Pumpe, LOW);
    AutoPumpeAus = HIGH;
  }

  if(LastState3 == HIGH && State3 == LOW)
  {
    Zeile5 = "Spr N an";
    Zeile1 = "Pumpe an";
    DisplayChange = HIGH;
    LastState3 = State3;
    digitalWrite(Pumpe, HIGH);
    AutoPumpeAus = LOW;
  }




  //Automatische Pumpenabschaltung nach Zeit
  if(AutoPumpeAus == HIGH)
  {
    if(AutoPumpeAusErkannt == LOW)
    {
      aktMillis = millis();
      altMillis = aktMillis;
      AutoPumpeAusErkannt = HIGH;
    }
    Ereignis = "Automatische Pumpenabschaltung an";

    
    switch (millis() - altMillis)
    {
      case 1000 ... 1999:
        Zeile1 = "Pume aus in 1s";
        DisplayChange = HIGH;
        break;
      case 2000 ... 2999:
        Zeile1 = "Pume aus in 2s";
        DisplayChange = HIGH;
        break;
      case 3000 ... 3999:
        Zeile1 = "Pume aus in 3s";
        DisplayChange = HIGH;
        break;
    }

    
    
    


    
    if (millis() - altMillis > Pumpenverzoegerung)  //Pumpe aus
    {
      Ereignis = "5s Automatische Pumpenabschaltung vorbei";
      Zeile1 = "Pumpe aus";
      DisplayChange = HIGH;
      AutoPumpeAusErkannt = LOW;
      AutoPumpeAus = LOW;
    }
  }
 





  //Anzeige
  if(DisplayChange == HIGH)
  {  
    uView.begin();        // start MicroView
    uView.clear(PAGE);      // clear page
    uView.setCursor(0,0);      // set cursor at 0,0
    uView.print(Zeile1);
    uView.setCursor(0,9);     
    uView.print(Zeile2);
    uView.setCursor(0,18);     
    uView.print(Zeile3);
    uView.setCursor(0,27);     
    uView.print(Zeile4);
    uView.setCursor(0,36);     
    uView.print(Zeile5);
    uView.display();
    DisplayChange = LOW;
  }
  
}

Bevor sich jemand wundert: ... bei switch/case ist eine Erweiterung die von manchen Compilern wie gcc unterstützt wird:
https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Case-Ranges.html#Case-Ranges

Da kann man aber auch gleich if/else nehmen

Geht aber auch mit if/else nicht... :confused:

Hallo,

zählt deine Differenzbildung nicht eher hoch statt runter?
Okay, wirst du besser wissen. Ich würde ja nur den reinen Sekundenwert aktualisieren.

unsigned int Differenz = (millis()-altMillis)/1000;
lcd.cursor(1,7); lcd.print(Differenz);

Doc_Arduino:
Hallo,

zählt deine Differenzbildung nicht eher hoch statt runter?
Okay, wirst du besser wissen. Ich würde ja nur den reinen Sekundenwert aktualisieren.

unsigned int Differenz = (millis()-altMillis)/1000;

lcd.cursor(1,7); lcd.print(Differenz);

Hab alles so aufgebaut damit Display nicht flackert. Wert soll nur bei Änderung angezeigt werden.

Hallo,

mit deinem Pseudo Code würde auch permanent auf das Display geschrieben. Außerdem kann nichts flackern wenn immer das gleiche Zeichen an die gleiche Stelle geschrieben wird. Den Text davor mußte ja nicht ständig schreiben sondern nur die Sekunden. Würde aber auch nicht flackern, weil er gleich bleibt.

Doc_Arduino:
Hallo,

mit deinem Pseudo Code würde auch permanent auf das Display geschrieben. Außerdem kann nichts flackern wenn immer das gleiche Zeichen an die gleiche Stelle geschrieben wird. Den Text davor mußte ja nicht ständig schreiben sondern nur die Sekunden. Würde aber auch nicht flackern, weil er gleich bleibt.

Nö, nö Doc.
Display wird nur beschrieben wenn DisplayChange auf H gesetzt wird.

Aber warum wird bei case 1s nicht angezeigt?

Hallo,

das ist doch permanent "high" zwischen 1000 und 3999. Also wird auch permanent geschrieben.

case 1s, weil das Ergebnis scheinbar nie kommt, da würde Debugging helfen. Sich die ms Differenz und altMillis permanent anzeigen lassen. Und zwar direkt nach

switch (millis() - altMillis)
    {

Das mit den millis-Anzeigen
hab ich schon gemacht.
Das Ereignis tritt ein. Ich dachte schon ein loop-Durchlauf wäre zu lange - ist aber bei ca. 40ms.

Hmm, bin etwas ratlos...

Scheint dem Dislay zu schnell zu gehen:

Mit bösem delay(300)

switch (millis() - altMillis)
{
case 1000 ... 1999:
Zeile1 = "Pume aus in 1s";
DisplayChange = HIGH;
delay(300);
break;
case 2000 ... 2999:
Zeile1 = "Pume aus in 2s";
DisplayChange = HIGH;
delay(300);
break;
case 3000 ... 3999:
Zeile1 = "Pume aus in 3s";
DisplayChange = HIGH;
delay(300);
break;
}

wird auch 1s & 2s angezeigt. Flackernd - aber geht. Muß also Anzeige nach 1. Anzeige verriegeln und erst bei Änderung wieder neu anzeigen...

Hallo,

wenn das Ereignis nachweislich eintritt, dann wird es auch ausgeführt. Kommt ja direkt danach dran. Ich wette es wird durch etwas anderes sofort überschrieben. Setz mal nach der 1s Anzeige ein hartes delay rein. Dann mußt du die 1s im Display sehen. Wenn ja, ab da weiter im Code nach überschreiben suchen.

Edit:
hattest schon die gleiche Idee. Dann suche danach warum es überschrieben wird.
Ich meine das Freigabe "High" ist ja immer noch ständig "High". Vielleicht liegst daran.
Das ordentlich zwischen H und L zu schalten wäre bestimmt wichtig.
Oder mit if und eine eigene bool Sperrvariable einbauen.

Aufwändig aber funktioniert: Nur einmal anzeigen.

    switch (millis() - altMillis)
    {
      case 1000 ... 1999:
        Zeile1 = "Pumpe 4s";
        if (SchonAngezeigt1 == LOW)
        {
          DisplayChange = HIGH;
          SchonAngezeigt1 = HIGH;
        }
        break;
      case 2000 ... 2999:
        Zeile1 = "Pumpe 3s";
        if (SchonAngezeigt2 == LOW)
        {
          DisplayChange = HIGH;
          SchonAngezeigt2 = HIGH;
        }
        break;
      case 3000 ... 3999:
        Zeile1 = "Pumpe 2s";
        if (SchonAngezeigt3 == LOW)
        {
          DisplayChange = HIGH;
          SchonAngezeigt3 = HIGH;
        }
        break;
      case 4000 ... 4999:
        Zeile1 = "Pumpe 1s";
        if (SchonAngezeigt4 == LOW)
        {
          DisplayChange = HIGH;
          SchonAngezeigt4 = HIGH;
        }
        break;
    }

Übrigends:
Das MicroView-Display lässt sich nur komplett anzeigen - nur ein einzelnes Zeichen ändern & anzeigen geht nicht. Daher der Aufwand.

stoni99:
Übrigends:
Das MicroView-Display lässt sich nur komplett anzeigen - nur ein einzelnes Zeichen ändern & anzeigen geht nicht. Daher der Aufwand.

aha, na dann muß man leider paar Umstände einbauen. Schön das es jetzt funktioniert.

Finde nur ich den Code etwas unübersichtlich? Das mit dem switch und "..." mag zwar gehen, wenn Serenfly angemerkt hat (wusste ich nicht), aber sollte man nicht verwenden, ausser man WILL Verwirrung stiften

uint32_t actMillis = millis();
static uint32_t lastMillis = 0;

uint8_t actCt = (uint32_t)(actMillis - lastMillis)/1000;
static uint8_t lastCt = 0;

if(actCt != lastCt) {
    lastCt = actCt;
    printf("CTVAL in Sekunden\n");
}

aber sollte man nicht verwenden, ausser man WILL Verwirrung stiften

Solange man es selbst versteht ist es ja ok. Und es ist auch etwas besser lesbar als

if (var > y && var < z)

Da es nicht Standard ist sollte man es halt erwähnen wenn man Code postet, da es nicht jeder kennt

Bei seinen Switch Abfragen kann man sich x > y && x < z sparen. Hier reicht eine einfache 1000er Division

Ja, das stimmt. Gibt noch einiges zu verbessern - ist auch noch nicht fertig.

Hallo,

ähm, will ja nichts sagen, aber das "durch 1000" hatte ich weiter oben schon erwähnt, war scheinbar der Zeit zu weit voraus ... muß immer erst ein anderer kommen um das nochmal bestätigen. :slight_smile:

ruhiges WE