Conditional millis()

I have a project that there's a motor that its speed is being controlled by a rotary encoder and there's a button counting how many rotations the motor is making by continuously being pressed by the motor each time the motor makes a spin. the button is on a piece of metal that should be broken after a huge number of spins, so then when the piece of metal breaks I need the motor to stop automatically after 5 seconds of the button being pressed.

No matter how I try writing the code, millis() keep counting since the start of the program and it stops after 5 seconds of running. Can you please help by making millis count the time after the button has not been pressed.

In the notes there are also lines i tried that did not work.

void loop() {

  if (valRotary > 0 && lastValRotary == 0) { // start at first loop lap after that val > 0
    startMillis = millis(); 
  }

  

  Serial.print(valRotary); //print the value on the serial monitor
  
  lcd.setCursor(0,1);  // set LCD cursor to coloumn 0 row 1 
  
  if(valRotary>lastValRotary)
  {
  Serial.print("  CW"); // print clockwise direction on serial monitor if the current encoder value is bigger than the last encoder value 

  }
  if(valRotary<lastValRotary)  {

  Serial.print("  CCW"); // print counter clockwise direction on serial monitor if current encoder value is less than the last encoder value

  }
  lastValRotary = valRotary;
  Serial.println(" "); // print space if the last encoder value is the same as the current encoder value 


 lcd.print(valRotary); // print on LCD 
 lcd.print("  ");
 lcd.setCursor(7,1);
  delay(50);

 
 analogWrite(motorPin1,valRotary); // control motor by value in the rotary encoder 


buttonState = digitalRead(switch1); //read the value of the button 
  
if (buttonState != lastButtonState) {
    if (buttonState == LOW) {
      // if the current state is LOW then the button went from off to on and count should increase:
    count = count + 1; 
    Serial.println(count);
    lcd.print(count);
    } else {
      // if the current state is HIGH then the button went from on to off:
        currentMillis = millis();
      Serial.println("TEST");
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  

  /*if (currentMillis - startMillis >= period)  //test whether the period has elapsed and button is not pressed 
{ 
  digitalWrite(motorPin1, LOW); 
  Serial.println("done");

}*/


   if (count % 5 == 0 && count > 4) {
    digitalWrite(motorPin1, LOW);
  }


/* if (val == LOW)  //BUTTON GOT PRESSED
{
  
  count = count + 1; 
  Serial.println(count);
  lcd.print(count);
  
    

} 


 if (val == HIGH){
currentMillis = millis() ; //get the current "time" (actually the number of milliseconds since the program started)
Serial.println("TEST"); 
} 

if (currentMillis - startMillis >= period)  //test whether the period has elapsed and button is not pressed 
{ 
  digitalWrite(motorPin1, LOW); 
  Serial.println("done");

} */


//
//
//
 
/* if (val == LOW){
 logic = true; //button pressed  
}

if (logic == true){
  currentMillis = millis(); //Last Pressed time stamp
  logic = false;
} else (logic == false); {
    if (currentMillis - startMillis >= period ){ //Last pressed time stamp vs. acual time stamp of system if more than period brake up
      digitalWrite(motorPin1, LOW); 
    } 
} */


}

The easiest way to do this is to save the value of millis() each time the button is found to be pressed

Later in loop() test whether millis() now is more than 5 seconds greater than the saved value. If it is then the button has not been pressed for 5 seconds and the metal strip has presumably broken so take whatever action you need

1 Like

I have tried the following code but the motor stops with the first button press. Do you have any suggestions?

if (buttonState != lastButtonState) {
    if (buttonState == LOW) {
      // if the current state is LOW then the button went from off to on and count should increase:
    count = count + 1; 
    Serial.println(count);
    lcd.print(count);
    currentMillis = millis();
    lastButtonState = buttonState;

  if (currentMillis - startMillis >= period)  //test whether the period has elapsed and button is not pressed 
{ 
  digitalWrite(motorPin1, LOW); 
  Serial.println("done");

}

In the code snippet you posted you are not saving the value of startMillis when the button becomes pressed and you also need to take the test for the timing period to have ended outside of the test for the button becoming pressed. That is why I said

Detecting that the button has become pressed and testing that the period has ended are 2 different actions

To simplify things you don't really need to test that the button has become pressed. It would be good enough to detect that the button is pressed. That would make the code simpler

startMillis starts when the rotary encoder has a value as stated in the post not in the comment snippet.

I don't understand how I should do the code. Could you please explain more to me?

where is valRotary set?

Start with something simple like this

const byte buttonPin = A3;

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
  const unsigned long period = 5000;
  unsigned long currentTime = millis();
  static unsigned long startTime = currentTime;
  if (digitalRead(buttonPin) == LOW)
  {
    startTime = currentTime;
    Serial.println("waiting");
  }

  if (currentTime - startTime >= period)
  {
    Serial.print("button not pressed for ");
    Serial.print(period/1000);
    Serial.println(" seconds");
  }
}

NOTE the use of INPUT_PULLUP to keep the input in a known state and the test for LOW to determine that the button is pressed

When you run the sketch you should see the "button not pressed" message after 5 seconds. If you press the button the sketch will move to "waiting" for 5 seconds. If you press the button within 5 seconds the waiting period will start again

Looking at what you are doing again I see that detecting when the button becomes pressed would be needed despite what I said previously, as you need to count the number of times it occurs. Debouncing the input is also necessary to prevent multiple counting of one button press. To simplify things you might like to consider using a library to handle the detection of button presses

It finally worked! Thank you

That's good

Please post your working code for the benefit of others

Do you really want the piece of metal that the switch is mounted on to break at some point? More conventional method of detecting shaft rotation would be a non-contact optical sensor, either an optical interrupter detecting a slot in a disk mounted on the motor shaft, or a reflective spot on the shaft itself reflecting a light back to a sensor.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.