Need Help about button, LED and millis

Hi, so sorry. I am newbie for arduino programming.
I need your help about button, LED and multiple millis

My sketch:

#define BUTTON 6
#define SENSOR 7
#define ledPin 8
#define alwaysBlinkLED 13

int LED1state = LOW;
boolean request = false;
char lastCommand = '0';

unsigned long previousMillis = 0;
unsigned long interval = 3000;
unsigned long currentMillis = millis();

unsigned long LED1previousMillis = 0;
unsigned long LED1interval = 100;


void setup() {
  //Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(alwaysBlinkLED, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(SENSOR, INPUT_PULLUP);
  Serial.begin(9600);  
}

void loop() {
  
  ALWAYSBLINK();
  
  if (digitalRead(BUTTON) == LOW) { 
    request = true;
    currentMillis = millis();
    lastCommand = '1';   
  }    
    
  else if (digitalRead(SENSOR) == LOW) {
    delay(1);  
    if ( lastCommand == '1' ) 
      {   
       if ((request)&& currentMillis - previousMillis >= interval)
          {
          request = false;
          digitalWrite(ledPin, HIGH); 
          }     
      }
   }
}

void ALWAYSBLINK(){

  unsigned long LED1currentMillis = millis();
  if (LED1currentMillis - LED1previousMillis > LED1interval) {
  LED1previousMillis += LED1interval;
  
    if (LED1state == HIGH){
     digitalWrite(alwaysBlinkLED, HIGH);
     }
      else {
      digitalWrite(alwaysBlinkLED, LOW);
     }
  LED1state=!LED1state;
  }  
}

The “BUTTON” should turn “ledPin” on after 3 seconds if SENSOR LOW and “alwaysBlinkLED” should always blink. With this sketch the BUTTON function was not working. If I pressed the BUTTON then if SENSOR LOW, the “ledPin” suddenly on without delay. What’s wrong with my codes?

So sorry for bad english :-). I hope you can understand what I mean…

IF BUTTON LOW → IF SENSOR LOW → delay 3 seconds → ledPin HIGH

Edited: the goal :slight_smile:

Try putting some Serial.print()s in to see which sections of code are executing and the value of pertinent variables at that time.

What sort of sensor is being used ?

I notice that there is no code to take ledpin LOW. Is that intentional ?

Also note that

    if (LED1state == HIGH) {
      digitalWrite(alwaysBlinkLED, HIGH);
    }
    else {
      digitalWrite(alwaysBlinkLED, LOW);
    }

Can be reduced to

      digitalWrite(alwaysBlinkLED, LED1state);

The problem is probably that your previousMillis is initially set to zero. So depending on when the buttons was pressed, currentMillis - previousMillis will be greater than 3000.

No time to test, but maybe below change will solve the issue

void loop() {
  currentMillis = millis();

  ALWAYSBLINK();

  if (digitalRead(BUTTON) == LOW)
  {
    request = true;
    previousMillis = millis();
    lastCommand = '1';
  }
  ...
  ...
}

UKHeliBob: Try putting some Serial.print()s in to see which sections of code are executing and the value of pertinent variables at that time.

What sort of sensor is being used ?

I notice that there is no code to take ledpin LOW. Is that intentional ?

Also note that

    if (LED1state == HIGH) {
      digitalWrite(alwaysBlinkLED, HIGH);
    }
    else {
      digitalWrite(alwaysBlinkLED, LOW);
    }

Can be reduced to

      digitalWrite(alwaysBlinkLED, LED1state);

Yes, that is.. That is intentional. ledPin will LOW when the arduino is resetted

sterretje: The problem is probably that your previousMillis is initially set to zero. So depending on when the buttons was pressed, currentMillis - previousMillis will be greater than 3000.

No time to test, but maybe below change will solve the issue

void loop() {
  currentMillis = millis();

 ALWAYSBLINK();

 if (digitalRead(BUTTON) == LOW)  {    request = true;    previousMillis = millis();    lastCommand = '1';  }  ...  ... }

Tried your suggestion but no luck! Your suggestion work like this: After BUTTON pressed I have to wait 3 seconds to able make SENSOR LOW. After SENSOR LOW the ledPin suddenly HIGH without delay.

So sorry, I just edited the goal to "The "BUTTON" should turn "ledPin" on after 3 seconds if SENSOR LOW and "alwaysBlinkLED" should always blink"

Let's take this in stages. Is the alwaysBlinkLED working as required ?

So is this an accurate description of what you want to achieve?

1) wait for button to be pressed 2) once pressed, wait three second 3) if sensor low after above three seconds, switch led on

Below should do that. If it does not work, be very accurate in what it does not do and what it does do.

void loop() {

  // current time
  currentMillis = millis();

  // blink
  ALWAYSBLINK();

  // check button
  if (digitalRead(BUTTON) == LOW) {
    // indicate an action was requested
    request = true;
    // set starttime of delay
    previousMillis = millis();
    // no idea what this does
    lastCommand = '1';
  }

  // if action was requested and if delay lapsed
  if (request == true && currentMillis - previousMillis >= interval)
  {
    // check sensor
    if (digitalRead(SENSOR) == LOW)
    {
      // indicate no action was requested
      request = false;
      digitalWrite(ledPin, HIGH);
    }
  }
}

Note: you might want to make the ledPin low in setup to make sure it is off before you start the loop().

Let's take this in stages. Is the alwaysBlinkLED working as required ?

Yes, It is. The "alwaysBlinkLED" working as required

sterretje: So is this an accurate description of what you want to achieve?

1) wait for button to be pressed 2) once pressed, wait three second 3) if sensor low after above three seconds, switch led on

This should:

1) wait for button to be pressed 2) no limit time after pressed. (>0 second) 3) if sensor low after above three seconds, switch led on

Below should do that. If it does not work, be very accurate in what it does not do and what it does do.

void loop() {

  // current time   currentMillis = millis();

  // blink   ALWAYSBLINK();

  // check button   if (digitalRead(BUTTON) == LOW) {     // indicate an action was requested     request = true;     // set starttime of delay     previousMillis = millis();     // no idea what this does     lastCommand = '1';   }

  // if action was requested and if delay lapsed   if (request == true && currentMillis - previousMillis >= interval)   {     // check sensor     if (digitalRead(SENSOR) == LOW)     {       // indicate no action was requested       request = false;       digitalWrite(ledPin, HIGH);     }   } }




Note:
you might want to make the ledPin low in setup to make sure it is off before you start the loop().

Your code still not meet what I want..

Tried to change to:

void loop() {
  currentMillis = millis();
  ALWAYSBLINK();
  
  if (digitalRead(BUTTON) == LOW) { 
    lastCommand = '1';   
  }    
    
  else if (digitalRead(SENSOR) == LOW) {
    delay(1);  
    request = true;
    previousMillis = millis();
    if ( lastCommand == '1' ) 
      {   
       if (request == true && currentMillis - previousMillis >= interval)
          {
          request = false;
          digitalWrite(ledPin, HIGH); 
          }     
      }
   }
}

Still not working..

 if (digitalRead(BUTTON) == LOW) { 
    lastCommand = '1';   
  }    

  if (digitalRead(BUTTON2) == LOW) { 
    lastCommand = '2';   
  }
  ...

  ....

I have plan to add more command inside if (digitalRead(SENSOR) == LOW) I am still learning arduino. and I want to learn it step by step :)

1) wait for button to be pressed 2) no limit time after pressed. (>0 second) 3) if sensor low after above three seconds, switch led on

Does the button have to remain pressed for 3 seconds or will a momentary press suffice ?

UKHeliBob: Does the button have to remain pressed for 3 seconds or will a momentary press suffice ?

No need to pressed for 3 seconds...

Something to play with

const byte buttonPin = A1;
const byte sensorPin = A2;
const byte ledPin = 13;
boolean waiting = false;
unsigned long startTime;
unsigned long currentTime;
unsigned long waitingTime = 3000;
byte currentButtonState;
byte previousButtonState;

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(sensorPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  Serial.println("Waiting for the button to be pressed");
}

void loop()
{
  previousButtonState = currentButtonState;
  currentButtonState = digitalRead(buttonPin);
  if (currentButtonState != previousButtonState && currentButtonState == LOW && !waiting)  //button has become pressed
  {
    waiting = true;
    startTime = millis();  //start timing
    digitalWrite(ledPin, HIGH);
    Serial.println("Button has become pressed.  Started waiting");
  }

  if (waiting)
  {
    currentTime = millis();
    if (currentTime - startTime >= waitingTime)
    {
      waiting = false;
      if (digitalRead(sensorPin) == LOW)
      {
        digitalWrite(ledPin, LOW);
        Serial.println("Sensor was LOW 3 seconds after button press");
      }
      else
      {
        Serial.println("Sensor was not LOW after 3 seconds");
      }
    }
  }
}

Depending on how your LED and switches are wired you may need to change the logic within the program.

UKHeliBob: Something to play with

const byte buttonPin = A1;
const byte sensorPin = A2;
const byte ledPin = 13;
boolean waiting = false;
unsigned long startTime;
unsigned long currentTime;
unsigned long waitingTime = 3000;
byte currentButtonState;
byte previousButtonState;

void setup() {   Serial.begin(115200);   pinMode(buttonPin, INPUT_PULLUP);   pinMode(sensorPin, INPUT_PULLUP);   pinMode(ledPin, OUTPUT);   digitalWrite(ledPin, HIGH);   Serial.println("Waiting for the button to be pressed"); }

void loop() {   previousButtonState = currentButtonState;   currentButtonState = digitalRead(buttonPin);   if (currentButtonState != previousButtonState && currentButtonState == LOW && !waiting)  //button has become pressed   {     waiting = true;     startTime = millis();  //start timing     digitalWrite(ledPin, HIGH);     Serial.println("Button has become pressed.  Started waiting");   }

  if (waiting)   {     currentTime = millis();     if (currentTime - startTime >= waitingTime)     {       waiting = false;       if (digitalRead(sensorPin) == LOW)       {         digitalWrite(ledPin, LOW);         Serial.println("Sensor was LOW 3 seconds after button press");       }       else       {         Serial.println("Sensor was not LOW after 3 seconds");       }     }   } }



Depending on how your LED and switches are wired you may need to change the logic within the program.

Hi.. Thanks for your help. Its almost done but Your code is working if the duration between button pressed and sensor low less than 3 seconds. If the duration more than 3 seconds its not working.

I need it to not count the duration between button pressed and sensor low. The delay only after sensor low

I need it to not count the duration between button pressed and sensor low. The delay only after sensor low

1) wait for button to be pressed 2) no limit time after pressed. (>0 second) 3) if sensor low after above three seconds, switch led on

I can't reconcile the two requirements above as they seem different. My code waits for the start button to be pressed then, if after 3 seconds the sensor input is LOW the LED is turned on. Please can you describe again what you want. Now it sounds like the program should wait for the start button to be pressed then at any time, if the sensor input is LOW for more than 3 seconds the LED should be turned on. Is that right ?

UKHeliBob:
Now it sounds like the program should wait for the start button to be pressed then at any time, if the sensor input is LOW for more than 3 seconds the LED should be turned on. Is that right ?

The program should wait for the start button to be pressed then at any time, if the sensor input is LOW then delay 3 seconds the LED should be turned on.

Maybe this code should make you understand what I mean :slight_smile:

void loop() {
  
  ALWAYSBLINK();
  
  if (digitalRead(BUTTON) == LOW) { 
    //request = true;
    //currentMillis = millis();
    lastCommand = '1';   
  }    
    
  else if (digitalRead(SENSOR) == LOW) {
    delay(1);  
    if ( lastCommand == '1' ) 
      {   

        

       while (digitalRead(SENSOR) == LOW)
          {
          //request = false;
          delay(3000); //<-- the delay should be here
          digitalWrite(ledPin, HIGH); 
          }     
      }
   }
}

This code is working but ALWAYSBLINK was blocked during delay and while statement

Try this

const byte buttonPin = A1;
const byte sensorPin = A2;
const byte ledPin = 13;
boolean waitingThreeSeconds = false;
unsigned long startTime;
unsigned long currentTime;
unsigned long waitingTime = 3000;
byte currentButtonState;
byte previousButtonState;

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(sensorPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);  //make sure LED starts off
  Serial.println("Waiting for the start button to be pressed");
}

void loop()
{
  previousButtonState = currentButtonState;
  currentButtonState = digitalRead(buttonPin);
  if (currentButtonState != previousButtonState && currentButtonState == LOW)  //button has become pressed
  {
    Serial.println("Start button has been pressed\nWaiting for sensor input");//
    digitalWrite(ledPin, HIGH);
  }

  if (digitalRead(sensorPin) == LOW && !waitingThreeSeconds)
  {
    Serial.println("Sensor pin has gone LOW\nWaiting 3 seconds");
    startTime = millis();  //start timing
    waitingThreeSeconds = true;
  }

  if (waitingThreeSeconds)
  {
    currentTime = millis();
    if (currentTime - startTime >= waitingTime)
    {
      Serial.println("End of 3 seconds wait");
      waitingThreeSeconds = false;
      digitalWrite(ledPin, LOW);    //turn LED on
    }
  }
}

Hi, thanks very much Bob!
Its working like what I want…
I think its very easy for you but very hard to me to solve this case :slight_smile:

After integrated your code:

#define BUTTON 6
#define SENSOR 7
#define ledPin 8
#define alwaysBlinkLED 13

int LED1state = LOW;
char lastCommand = '0';

boolean waiting = false;
unsigned long startTime;
unsigned long currentTime;
unsigned long waitingTime = 3000;
boolean waitingThreeSeconds = false;

unsigned long LED1previousMillis = 0;
unsigned long LED1interval = 100;


void setup() {
  
  pinMode(ledPin, OUTPUT);
  pinMode(alwaysBlinkLED, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(SENSOR, INPUT_PULLUP);
  digitalWrite(ledPin, HIGH);
  Serial.begin(115200);
  Serial.println("Waiting for the button to be pressed");
}

void loop() {
  
  ALWAYSBLINK();
  
  if (digitalRead(BUTTON) == LOW) { 
    Serial.println("Start button has been pressed\nWaiting for sensor input");
    digitalWrite(ledPin, LOW);
    lastCommand = '1';   
  }    
    
  else if (digitalRead(SENSOR) == LOW && !waitingThreeSeconds) {
    delay(1);  
    Serial.println("Sensor pin has gone LOW\nWaiting 3 seconds");
    startTime = millis();  //start timing
    waitingThreeSeconds = true;
  }
  
  if (waitingThreeSeconds && lastCommand == '1')
  {
    currentTime = millis();
      if (currentTime - startTime >= waitingTime)
         {
            Serial.println("End of 3 seconds wait");
            waitingThreeSeconds = false;
            digitalWrite(ledPin, HIGH);    //turn LED on
         }
  }     
      
   
}

void ALWAYSBLINK(){

  unsigned long LED1currentMillis = millis();
  if (LED1currentMillis - LED1previousMillis > LED1interval) {
  LED1previousMillis += LED1interval;
  
    if (LED1state == HIGH){
     digitalWrite(alwaysBlinkLED, HIGH);
     }
      else {
      digitalWrite(alwaysBlinkLED, LOW);
     }
  LED1state=!LED1state;
  }  
}

It’s bad form to use all caps for a function name. That is traditionally reserved for defined constants.

Do you need the lastCommand variable and the test that goes with it ? If waitingThreeeSeconds is not true then the 3 second wait will not happen anyway.

aarg:
It’s bad form to use all caps for a function name. That is traditionally reserved for defined constants.

Thanks for your suggestion :slight_smile:

UKHeliBob: Do you need the lastCommand variable and the test that goes with it ? If waitingThreeeSeconds is not true then the 3 second wait will not happen anyway.

lastCommand variable already work with that. If lastCommand = '1' then sensor = low, after 3 seconds led goes ON