Millis beginnt zu zählen obwohl Bedingung NICHT WAHR?!

Hallo liebe Technikfreunde,

ich arbeite an einem Schulprojekt und zur Realisierung möchte ich gerne den Arduino verwenden. Da ich auf dem Gebiet der Programmierung noch etwas unerfahren bin, möchte ich euch um Hilfe bitten.

Die Schaltung funktioniert so weit, nur beginnt millis bereits zu zählen obwohl noch die if-Bedingung gar NICHT WAHR ist. Das bedeutet wenn die Bedingung WAHR wird sind LED und Warnton bereits an, obwohl Sie nacheinander und zeitverzögert geschaltet werden sollen und das bei jedem Mal wenn die Bedingung gelegentlich NICHT WAHR und dann wieder WAHR wird.

Hier mein Code:

  const int lenkradlinks_pin = 2;
  const int lenkradrechts_pin = 3;
  const int tuerverkleidung_pin = 4;
  const int mittelkonsole_pin = 5;
  const int geschwindigkeit_pin = 6;
  const int warnzeichen_pin = 7;
  const int warnton_pin = 8;

  int lenkradlinks_status;
  int lenkradrechts_status;
  int tuerverkleidung_status;
  int mittelkonsole_status;
  int warnzeichen_status;
  int warnton_status;
  int geschwindigkeit_signal;
  int geschwindigkeit_kmh;
  
  unsigned long previousmillis = 0;

  const long interval1 = 5000;
  const long interval2 = 10000;


void setup() {

  Serial.begin(9600);
  pinMode (lenkradlinks_pin, INPUT);
  pinMode (lenkradrechts_pin, INPUT);
  pinMode (tuerverkleidung_pin, INPUT);
  pinMode (mittelkonsole_pin, INPUT);
  pinMode (geschwindigkeit_pin, INPUT);
  pinMode (warnzeichen_pin, OUTPUT);
  pinMode (warnton_pin, OUTPUT);
  
}



void loop() {

  lenkradlinks_status = digitalRead(lenkradlinks_pin);
  lenkradrechts_status = digitalRead(lenkradrechts_pin);
  tuerverkleidung_status = digitalRead(tuerverkleidung_pin);
  mittelkonsole_status = digitalRead(mittelkonsole_pin);

  //Serial.println(lenkradlinks_status);
  //Serial.println(lenkradrechts_status);
  //Serial.println(tuerverkleidung_status);
  //Serial.println(mittelkonsole_status);

  if  ((lenkradlinks_status == LOW || lenkradrechts_status == LOW) && (lenkradlinks_status == LOW || mittelkonsole_status == LOW) && (lenkradrechts_status == LOW || tuerverkleidung_status == LOW)){

      unsigned long currentmillis = millis();
    
      if((currentmillis - previousmillis) > interval1){ 
      
      digitalWrite(warnzeichen_pin, HIGH);
    
      }
      
      if((currentmillis - previousmillis) > interval2){
      
      digitalWrite(warnton_pin, HIGH);
      
      }
  }

  else{

      digitalWrite(warnzeichen_pin, LOW);
      digitalWrite(warnton_pin, LOW);
    
  }
    
}

previousMillis wird nirgends gesetzt. Auf currentMillis kannst du verzichten und direkt millis() nutzen, oder aber currentmillis gehört in die Hauptschleife am Anfang der loop

millis() zählt immer. Es ist die Zeit in Millisekunden ab Einschalten des Arduino's.
Grüße Uwe

Ok, danke für deine schnelle Antwort. Nutze jetzt direkt millis(), dadurch hat sich aber nichts geändert.

Gewollt ist: Wird Bedingung WAHR, dann schalte nach 5 sek. Warnanzeige an, nach weiteren 5 sek. schalte Warnton an. Wird Bedingung NICHT WAHR schalte beides direkt aus. Wird Bedingung "wieder" WAHR, dann schalte nach 5sek. Warnanzeige...

Zur Zeit funktioniert es aber so, dass dieser Ablauf unabhängig von der Bedingung direkt nach dem einschalten abläuft. Der einzige Unterschied, bei WAHR kann ich den Ablauf sehen und dann hören, bei NICHT WAHR läuft dieser im Hintergrund ab, denn nach 10sek. und wenn die Bedingung wieder WAHR wird, sind Beide direkt an. Wird die Bedingung NICHT WAHR gehen Beide wieder aus (so wie gewollt), doch wird sie wieder WAHR sind Beide direkt an?!?!

sschultewolter:
previousMillis wird nirgends gesetzt.

Hast du das auch verändert?

Ich steh wohl aufm Schlauch...hab ich das nicht schon oben mit

unsigned long previousmillis = 0;

getan? :confused:

Schau dir noch mal BlinkwithoutDelay an :wink:

preveousmillis ist im ganzen Sketch 0, also ist die Bedingung ab dem ersten Intervallablauf immer erfüllt. Du musst nach Ablauf des zweiten Intervalls in preveousmillis die aktuellen millis speichern.

Danke für den Tipp, hab ich gemacht, funktioniert leider immer noch nicht so wie es soll. Sobald der zweite Intervall beendet ist geht ganz kurz der Warnton an und alles beginnt wieder von neu durch zu laufen (unabhängig von der if-Bedingung). Ist die if-Bedingung NICHT WAHR, geht zwar die LED und TON nicht auf HIGH, jedoch wiederholt sich der Intervall trotzdem im Hintergrund?!

Beides soll ja so lange HIGH bleiben bis die if-Bedingung wieder NICHT WAHR wird und der Intervall erst dann wieder durchlaufen soll wenn Sie wieder WAHR wird. Kann es sein dass ich hier mit einer while-Schleife arbeiten muss oder den "loop" an einer Stelle stoppen muss bis eine andere Bedingung erfüllt wird?

Dann darf previousmillis erst gesetzt werden, wenn die anderen Bedingungen stimmen. Du brauchst also eine zusätzliche IF-Abfrage.

Meinst du etwa so? Funzt nämlich nicht :o Ich hab mal die if-Bedingung etwas vereinfacht damit ich es leichter hab die Funktion zu überprüfen.

Ich versteh einfach nicht warum der Intervall direkt nach dem einschalten schon im Hintergrund anfängt abzulaufen, obwohl die if-Bedingung noch gar nicht TRUE war?! Theoretisch müsste er doch diesen Teil überspringen und nur den else-Teil machen?!

  const int lenkradlinks_pin = 2;
  const int lenkradrechts_pin = 3;
  const int tuerverkleidung_pin = 4;
  const int mittelkonsole_pin = 5;
  const int geschwindigkeit_pin = 6;
  const int warnzeichen_pin = 7;
  const int warnton_pin = 8;

  int lenkradlinks_status;
  int lenkradrechts_status;
  int tuerverkleidung_status;
  int mittelkonsole_status;
  int warnzeichen_status;
  int warnton_status;
  int geschwindigkeit_signal;
  int geschwindigkeit_kmh;
  
  unsigned long previousmillis = 0;

  const long interval1 = 5000;
  const long interval2 = 10000;


void setup() {

  Serial.begin(9600);
  pinMode (lenkradlinks_pin, INPUT);
  pinMode (lenkradrechts_pin, INPUT);
  pinMode (tuerverkleidung_pin, INPUT);
  pinMode (mittelkonsole_pin, INPUT);
  pinMode (geschwindigkeit_pin, INPUT);
  pinMode (warnzeichen_pin, OUTPUT);
  pinMode (warnton_pin, OUTPUT);
  
}



void loop() {

  lenkradlinks_status = digitalRead(lenkradlinks_pin);
  lenkradrechts_status = digitalRead(lenkradrechts_pin);
  tuerverkleidung_status = digitalRead(tuerverkleidung_pin);
  mittelkonsole_status = digitalRead(mittelkonsole_pin);

  //Serial.println(lenkradlinks_status);
  //Serial.println(lenkradrechts_status);
  //Serial.println(tuerverkleidung_status);
  //Serial.println(mittelkonsole_status);

  if  (lenkradlinks_status == LOW || lenkradrechts_status == LOW){

      unsigned long currentmillis = millis();
    
      if((currentmillis - previousmillis) > interval1){ 
      
        digitalWrite(warnzeichen_pin, HIGH);
    
      }
      
      if((currentmillis - previousmillis) > interval2){
      
        digitalWrite(warnton_pin, HIGH);
      
      }

      if(lenkradlinks_status == HIGH && lenkradrechts_status == HIGH){
        
        previousmillis = currentmillis;
        
      }     
  }

  else{

      digitalWrite(warnzeichen_pin, LOW);
      digitalWrite(warnton_pin, LOW);
    
      }
}

Hallo,

deine if Abfragen sind falsch aufgebaut und dein currentmillis ist falsch. Das wird jedesmal neu gesetzt, darum funktioniert das nicht. Lass das weg. Nimm nur millis.

if ( (millis() - previousmillis) > interval1 )  { 
  ...

//und am Ende
previousmillis = millis();

Male dir mal ein ordentliches Ablaufdiagramm auf Papier ohne auf deinen Code zu schauen.
Danach formulierst du das in Code.

millis() ist ein endloser Zeitzähler wie schon gesagt wurde. Mit previosmillis ziehst du nur deine Vergleichszeit nach um später wieder deine Differenz abwarten zu können.

arokon:
Ich versteh einfach nicht warum der Intervall direkt nach dem einschalten schon im Hintergrund anfängt abzulaufen, obwohl die if-Bedingung noch gar nicht TRUE war?! Theoretisch müsste er doch diesen Teil überspringen und nur den else-Teil machen?!

  if  (lenkradlinks_status == LOW || lenkradrechts_status == LOW){

if(lenkradlinks_status == HIGH && lenkradrechts_status == HIGH){

Ich weiß nicht was lenkradstatus ist, ich gehe mal davon aus, dass nur eins zu einer Zeit High sein kann. Demnach wäre erste Abfrage immer erfüllt, zweite Abfrage kann nie erfüllt werden. Ein Diagramm kann echt helfen die Abfragen logisch richtig zu machen.

Danke für eure Unterstützung. Ein solches Kopfzerbrechen wegen einer so einfachen Sache bringt einen zur Verzweiflung. Ich werde mal versuchen ein solches Ablaufdiagramm die Tage anzufertigen. Der Ablauf ist eigentlich relativ einfach:

"WENN beide Hände am Lenkrad "DANN" soll nix passieren (LED & TON aus).

"WENN" nur eine Hand am Lenkrad "DANN" nach geht nach 5 sek. LED an, nach weiteren 5 sek. geht zusätzlich TON an.

LED und TON bleiben solange eingeschaltet bis wieder beide Hände am Lenkrad sind. Nimmt man wieder eine Hand weg geht nach 5 sek. LED...

Theseus:

  if  (lenkradlinks_status == LOW || lenkradrechts_status == LOW){

if(lenkradlinks_status == HIGH && lenkradrechts_status == HIGH){

Jetzt verstehe ich die Logik.
Auf den ersten Blick, dürfte die zweite If-Abfrage an der falschen Stelle stehen. Sie steht beim Erzeugen des Warntons. Sie müsste zu der ersten If-Abfrage gehören.

Hallo,

genau, dass meinte ich. Die 2. if hat nie eine Chance ausgewertet zu werden, weil sie von der ersten if abhängig ist überhaupt dran zu kommen.

Habs mal lauffähig umgebaut.

Wie du das mit den Eingängen machst kann ich nicht wissen. Ob die noch einen Pulldown/up benötigen oder was du da für Taster/Schalter angeschlossen hast. Ob die noch entprellt werden müssen oder ob das auch so funktioniert. Mußt du wissen.

  const byte lenkradlinks_pin    = 2;
  const byte lenkradrechts_pin   = 3;
  const byte warnzeichen_pin     = 7;
  const byte warnton_pin         = 8;

  bool lenkradlinks_status;
  bool lenkradrechts_status;
  bool warnzeichen_status;
  bool warnton_status;
 
  unsigned long previousmillis;

  const unsigned int interval1 = 5000;
  const unsigned int interval2 = 10000;


void setup() {
  Serial.begin(9600);
  pinMode (lenkradlinks_pin, INPUT);
  pinMode (lenkradrechts_pin, INPUT);
  pinMode (warnzeichen_pin, OUTPUT);
  pinMode (warnton_pin, OUTPUT);
 
}


void loop() {

  lenkradlinks_status = digitalRead(lenkradlinks_pin);
  lenkradrechts_status = digitalRead(lenkradrechts_pin);

  if  (lenkradlinks_status == false || lenkradrechts_status == false)  {
    if((millis() - previousmillis) > interval1)  {
      digitalWrite(warnzeichen_pin, HIGH);
    }
    if((millis() - previousmillis) > interval2)  {
      digitalWrite(warnton_pin, HIGH);
    }
  }
  
  // if(lenkradlinks_status == true && lenkradrechts_status == true)  {
  else  {
    previousmillis = millis();
    digitalWrite(warnzeichen_pin, LOW);
    digitalWrite(warnton_pin, LOW);
  }      

}

Edit:
die letzte if Abfrage kannste ebenso durch else ersetzen. Das erste if erschlägt mit der OR Verknüpfung alle Eingänge, dann bleibt nur noch der Ruhezustand für else.

Wunderbar es funktioniert endlich, ich muss aber zugeben, dass ich es auf diese Weise schon versucht hatte, es aber nicht funktioniert hat, weil das Signal der Sensoren nicht sauber war und der erste Intervall dadurch immer wieder unterbrochen wurde. Ich dachte zuerst es liegt am Code :sob:

Jetzt kann das ganze erweitert werden und noch von der Fahrgeschwindigkeit abhängig gemacht werden.

Hoffentlich klappt das Alles. Danke für eure Hilfe :wink:

So, das Projekt ist fast schon einbaufertig. Ich möchte nur noch dass der Warnton nicht durchgängig piept, sondern in einem bestimmten Intervall.

Habe dies mit dem Code "BlinkWithoutDelay" versucht, nur leider piept dieser dann nicht in dem festgelegten Intervall von einer Sekunde, sondern wahrscheinlich im Intervall der Bedingung vorher.

Kurz zum Ablauf: Wenn die Bedingung wahr ist, soll nach 2 sek. das Warnlicht an gehen, nach weiteren 5 sek. soll zusätzlich ein Warnton in einem Intervall von einer Sekunde ertönen.

Den Code hab ich etwas abgekürzt:

  byte warnton_status = LOW;

  unsigned long previousmillis = 0;

  const int interval1 = 2000;
  const int interval2 = 7000;
  const int interval3 = 1000;


void setup() {

  //Serial.begin(9600);
  pinMode (warnlicht_pin, OUTPUT);
  pinMode (warnton_pin, OUTPUT);

}

void loop() {


      if((millis() - previousmillis) >= interval1){
               
        digitalWrite(warnlicht_pin, HIGH);
        
      }
      
      if((millis() - previousmillis) >= interval2){
          
          if ((millis() - previousmillis) >= interval3) {

              previousmillis = millis();

              if (warnton_status == LOW) {
              
                  warnton_status = HIGH;
             
             } else {
              
             warnton_status = LOW;
             
             }
          
             digitalWrite(warnton_pin, warnton_status);
             
          }
          
      }

}

Mit zwei Startzeiten tust du dich leichter.

z.B.
unsigned long previousmillis; // Zeit seit Alarmbeginn
unsigned long piepsZeit; Zeit um piepser an/aus zu steuern.

Wann soll das Licht wieder aus gehen?
Soll man Piepser nicht separat "quittieren" (also aus, obwohl Alarm noch ansteht) können ?

hi michael_x,

es funktioniert, danke für den Tipp. Ich werde bald den kompletten Code veröffentlichen, ich wäre sehr dankbar wenn sich das dann mal ein Profi anschaut.

Hier ein paar Infos zum eigentlichen Projekt: Die Hardware besteht aus einem kapazitiven Sensor von Adafruit (CAP1188), angeschlossen ist dieser an ein Lenkrad. Es wird jeweils die rechte und die linke Seite erkannt.

An der Türverkleidung und an der Mittelkonsole befinden sich Infrarotsensoren. Ein digitaler Pin (PWM) ist an den Tachoausgang angeschlossen wo ein Rechtecksignal anliegt.

Nun zum Ablauf des Programms:

WENN nur eine Hand erkannt wird UND die Fahrgeschwindigkeit höher als 20 km/h beträgt

DANN soll nach 2 Sekunden die LED aufleuchten. Nach einem weiteren Intervall, abhängig von Geschwindigkeit und gefahrener Strecke, soll die LED in einem Intervall von 0,5s blinken und ein Warnton in einem Intervall von 1s ertönen.

Das ganze solange bis wieder beide Hände erkannt werden. Verbesserungsvorschläge sind erwünscht.

Hier ist nun der Code dazu:

  #include <Adafruit_CAP1188.h>
  #define CAP1188_RESET 12
  #define CAP1188_SENSITIVITY 0x1F

  Adafruit_CAP1188 cap = Adafruit_CAP1188();
 
  const byte tuerverkleidung_pin = 2;
  const byte mittelkonsole_pin = 3;
  const byte tachoausgang_pin = 5;
  const byte warnlicht_pin = 8;
  const byte warnton_pin = 9;

  byte lenkrad_status;
  byte tuerverkleidung_status;
  byte mittelkonsole_status;
  byte warnlicht_status = HIGH;
  byte warnton_status = LOW;
  
  unsigned long v_signal;
  double v_kmh;

  int ablenkungsstrecke = 50;
     
  unsigned long previousmillis;
  unsigned long blinkzeit;
  unsigned long piepszeit;
  unsigned long ablenkungsinterval;

  const long freizeitinterval = 2000;
  const long blinkinterval = 500;
  const long piepsinterval = 1000;


void setup() {

  //Serial.begin(9600);
  
  pinMode (tuerverkleidung_pin, INPUT);
  pinMode (mittelkonsole_pin, INPUT);
  pinMode (tachoausgang_pin, INPUT);
  pinMode (warnlicht_pin, OUTPUT);
  pinMode (warnton_pin, OUTPUT);
  
  if (!cap.begin()) {
  Serial.println("CAP1188 nicht gefunden!");
  while (1);
  }
  Serial.println("CAP1188 gefunden!");
  //Einstellung der Sensivitaetstufe des CAP1188
  //cap.writeRegister(CAP1188_SENSITIVITY, 0x2F);  // 32x Sensivitaet
  //cap.writeRegister(CAP1188_SENSITIVITY, 0x3F);  // 16x Sensivitaet
  //cap.writeRegister(CAP1188_SENSITIVITY, 0x4F);  // 8x Sensivitaet
  cap.writeRegister(CAP1188_SENSITIVITY, 0x5F);  // 4x Sensivitaet
  //cap.writeRegister(CAP1188_SENSITIVITY, 0x6F);  // 2x Sensivitaet
  //cap.writeRegister(CAP1188_SENSITIVITY, 0x7F);  // 1x Sensivitaet
  Serial.print("Sensivitaet: 0x");
  Serial.println(cap.readRegister(CAP1188_SENSITIVITY), HEX);
}

void loop() {

  uint8_t lenkrad_status = cap.touched();
  tuerverkleidung_status = digitalRead(tuerverkleidung_pin);
  mittelkonsole_status = digitalRead(mittelkonsole_pin);
  v_signal = pulseIn(tachoausgang_pin, HIGH) + pulseIn(tachoausgang_pin, LOW);
  v_kmh = 1/(double)v_signal;
  
  
  //Serial.println(lenkrad_status);
  //Serial.println(tuerverkleidung_status);
  //Serial.println(mittelkonsole_status);
  //Serial.println(v_kmh);

  
  if  (((lenkrad_status != 129) && (lenkrad_status != 1 || tuerverkleidung_status == HIGH) && (lenkrad_status != 128 || mittelkonsole_status == HIGH)) && (v_kmh > 20)){

      ablenkungsinterval = (ablenkungsstrecke*1000)/(v_kmh/3,6);
      
      unsigned long currentmillis = millis();

      if((currentmillis - previousmillis) >= freizeitinterval){
               
        digitalWrite(warnlicht_pin, warnlicht_status);
        
      }
      
      if((currentmillis - previousmillis) >= (freizeitinterval + ablenkungsinterval)){
          
          if ((currentmillis - blinkzeit) >= blinkinterval) {

              blinkzeit = currentmillis;

              if (warnlicht_status == LOW) {

                  warnlicht_status = HIGH;
             
             } else {

             warnlicht_status = LOW;
             
             }

             digitalWrite(warnlicht_pin, warnlicht_status);

          }
          
          if ((currentmillis - piepszeit) >= piepsinterval) {

              piepszeit = currentmillis;

              if (warnton_status == LOW) {
              
                  warnton_status = HIGH;
             
             } else {
              
             warnton_status = LOW;
             
             }
          
             digitalWrite(warnton_pin, warnton_status);
             
          }
      
      }

} else  {

        digitalWrite(warnlicht_pin, LOW);
      
        digitalWrite(warnton_pin, LOW);

        warnlicht_status = HIGH;

        warnton_status = LOW;
        
        previousmillis = millis();
 
        }
}