Help modifying millis

How can I modify the millis related variables in my program, so that when I press '#', the automode starts running case 1 immediately?

#include <LiquidCrystal.h>
#include <Keypad.h>

//KEYPAD SETUP
const byte ROWS = 4; //DEFINE NUMBER OF ROWS ON KEYPAD
const byte COLS = 3; //DEFINE NUMBER OF COLUMNS ON KEYPAD
char keys[ROWS][COLS] = { //ARRAY FOR KEYPAD KEYS
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};//END ARRAY FOR KEYPAD KEYS

byte rowPins[ROWS] = {3, 10, 9, 2}; //PINS WHERE THE ROWS OF THE KEYPAD IS CONNECTED
byte colPins[COLS] = {17, 16, 15}; //PINS WHERE THE COLUMNS OF THE KEYPAD IS CONNECTED

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );//MAKING KEYMAP FOR KEYPAD


//LCD DISPLAY SETUP
LiquidCrystal lcd(7, 6, 5, 4, A0, 8);  //PINS WHERE THE LCD DISPLAY IS CONNECTED
/*
 * LCD RS pin to digital pin 7
 * LCD Enable pin to digital pin 6
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin A0
 * LCD D7 pin to digital pin 8
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:               VO on display connected directly to GND.
 * ends to +5V and ground      For optimising contract, use a potmeter as described
 * wiper to LCD VO pin (pin 3)
 */
const unsigned long debounceValue = 50UL; //SETTING FOR DEBOUNCE TIME IN MILLISECONDS
unsigned long debounceTime; //VARIABLE FOR DEBOUNCING KEYS PRESSED
boolean change;           //SETTING BOOLEAN VARIABLE FOR TOGGLING BETWEEN MANUAL AND AUTOMODE
boolean manKey1;          //SETTING BOOLEAN VARIABLE FOR MANUAL OPERATION
boolean manKey2;          //SETTING BOOLEAN VARIABLE FOR MANUAL OPERATION
boolean manKey3;          //SETTING BOOLEAN VARIABLE FOR MANUAL OPERATION


const byte rly1 = 11;      //DEFINE RELAY 1 VARIABLE ON PIN11
const byte rly2 = 12;      //DEFINE RELAY 2 VARIABLE ON PIN12
const byte rly3 = 13;      //DEFINE RELAY 3 VARIABLE ON PIN13

unsigned long currentMillis;  //CURRENTMILLIS MUST BE UNSIGNED LONG TO AVOID STACK OVERFLOW
unsigned long RLYmillis;      //RLYMILLIS MUST BE UNSIGNED LONG TO AVOID STACK OVERFLOW
unsigned long RLYdelay = 10000;//RLYDELAY MUST BE UNSIGNED LONG TO AVOID STACK OVERFLOW - DECIDES THE AMOUNT OF TIME EACH RELAY SHOULD BE ON IN AUTOMODE

byte currentState;        //MAKE VARIABLE CURRENTSTATE

//INITIALIZE SETUP
void setup()
{
  Serial.begin(9600);        //SET BAUD RATE


  lcd.begin(20, 2);   // SETTING UP LCD'S NUMBER OF COLUMNS AND ROWS

  debounceTime = millis(); //DEBOUNCETIME = CURRENT TIME

  pinMode(rly1, OUTPUT);  //RELAY 1 PIN IS OUTPUT
  digitalWrite(rly1, LOW); //INITIALLY RELAY 1 IS OFF
  pinMode(rly2, OUTPUT);  //RELAY 2 PIN IS OUTPUT
  digitalWrite(rly2, LOW); //INITIALLY RELAY 2 IS OFF
  pinMode(rly3, OUTPUT);  //RELAY 3 PIN IS OUTPUT
  digitalWrite(rly3, LOW); //INITIALLY RELAY 2 IS OFF

  keypad.addEventListener(keypadEvent); //INITIALIZE CHECKUP ON KEYPAD USAGE
} // END OF SETUP

//INITIALIZE THE MAIN LOOP
void loop()
{
  char key = keypad.getKey();
  //================== is it time to check the switches?
  if (millis() - debounceTime >= debounceValue)
  {
    debounceTime = millis(); //re-initialize to the current time
  }
  if (change == 1) {
    automode();
  }
  else if (change == 0) {
    manualmode();
  }
}//END MAIN LOOP=============================================================================================

//INITIALIZE THE MANUAL MODE FUNCTION========================================================================
void manualmode (void)

{
  lcd.setCursor(0, 0);
  lcd.print ("Manual Mode Enabled   ");
  if (manKey1 == 1) {
    digitalWrite (rly1, HIGH);
    lcd.setCursor(0, 1);
    lcd.print ("1:ON ");
  }
  else if (manKey1 == 0) {
    digitalWrite (rly1, LOW);
    lcd.setCursor(0, 1);
    lcd.print ("1:OFF");
  }

  if (manKey2 == 1) {
    digitalWrite (rly2, HIGH);
    lcd.setCursor(6, 1);
    lcd.print ("2:ON ");
  }
  else if (manKey2 == 0) {
    digitalWrite (rly2, LOW);
    lcd.setCursor(6, 1);
    lcd.print ("2:OFF");
  }

  if (manKey3 == 1) {
    digitalWrite (rly3, HIGH);
    lcd.setCursor(12, 1);
    lcd.print ("3:ON ");
  }
  else if (manKey3 == 0) {
    digitalWrite (rly3, LOW);
    lcd.setCursor(12, 1);
    lcd.print ("3:OFF");
  }

}//END MANUAL MODE FUNCTION==================================================================================

//INITIALIZE THE AUTOMODE FUNCTION========================================================================
void automode (void)
{
      lcd.setCursor(0, 0);
  lcd.print ("Automode Enabled    ");
   //print the number of seconds since reset:
  //lcd.setCursor(0, 1);
  //lcd.print ("Been running for:");
  //lcd.setCursor(18, 1);
  //lcd.print(millis() / 1000);
  
  currentMillis = millis();

 if (currentMillis - RLYmillis >= RLYdelay)
  {
    RLYmillis = currentMillis;

    switch (currentState)
    {
      
      //***************************
      case 1:
 
    
        lcd.setCursor(0, 1);
        lcd.print ("Relay 1 ON            ");
        digitalWrite(rly1, HIGH);
        currentState = 2;
        break;
      //***************************
      case 2:

        lcd.setCursor(0, 1);
        lcd.print ("Relay 2 ON            ");
        digitalWrite(rly1, LOW);
        digitalWrite(rly2, HIGH);
        //Change to the next state
        currentState = 3;
        break;
      //***************************
      case 3:

        lcd.setCursor(0, 1);
        lcd.print ("Relay 3 ON            ");
        digitalWrite(rly2, LOW);
        digitalWrite(rly3, HIGH);
        //Change to the next state
        currentState = 4;
        break;
      //***************************
      case 4:

        lcd.setCursor(0, 1);
        lcd.print ("All relays OFF        ");
        digitalWrite(rly3, LOW);
        //Change to the next state
        currentState = 1;
        break;
      //***************************

      default:
        currentState = 1;              //Back to state 1
    } // END SWITCH/CASE===========================================================
  } //END IF STATEMENT=============================================================
} //END THE AUTOMODE FUNCTION======================================================

void keypadEvent(KeypadEvent key) {

  //MANUAL MODE OPERATION PARAMETERS
  if (keypad.getState() == PRESSED) {

    if (key == '1' && change == 0) { //IF KEY '1' IS PRESSED AND VARIABLE CHANGE == 0,
      if (key == '1') { //TOGGLE VARIABLE MANKEY1
        if (manKey1) manKey1 = 0;
        else manKey1 = 1;
      }//END BOOLEAN TOGGLE FOR VARIABLE MANKEY1
    }//END 'IF KEY 1'

    if (key == '2' && change == 0) {//IF KEY '2' IS PRESSED AND VARIABLE CHANGE == 0,
      if (key == '2') { //TOGGLE VARIABLE MANKEY2
        if (manKey2) manKey2 = 0;
        else manKey2 = 1;
      }//END BOOLEAN TOGGLE FOR VARIABLE MANKEY2
    }//END 'IF KEY 2'

    if (key == '3' && change == 0) { //IF KEY '3' IS PRESSED AND VARIABLE CHANGE == 0,
      if (key == '3') { //TOGGLE VARIABLE MANKEY3
        if (manKey3) manKey3 = 0;
        else manKey3 = 1;
      }//END BOOLEAN TOGGLE FOR VARIABLE MANKEY3
    }//END 'IF KEY 3'
  }//END MANUAL MODE OPERATION PARAMETERS


  //AUTOMODE OPERATION PARAMETERS
  if (keypad.getState() == PRESSED) {

    if (key == '#') { //IF KEY '#' IS PRESSED, TOGGLE VARIABLE CHANGE
      if (change) change = 0;
      else change = 1;
       lcd.setCursor(0, 1);
    lcd.print ("                               "); //CLEARING THE DISPLAY LINE 2 TO AVOID CONFLICT WHEN TOGGLING BETWEEN AUTO AND MANUAL
    }//END BOOLEAN TOGGLE FOR VARIABLE CHANGE
  }//END AUTO MODE OPERATION PARAMETERS
}//END KEYPADEVENT FUNCTION

Also, if an explanation comes with the solution, it'd be awesome! :slight_smile:

Damn, I could not resist going over the whole code. Please take a very very good look at the changes. Made it a bit more streamlined.

And, WHY ARE MOST OF THE COMMANDS SHOUTING TO MEEEEEEE?????

I also changed the name of the var change, it's such a bad name.... (change of what?????)

But back to business. You're delay is because when you enable and the time for automode to do something isn't over it starts to wait. To fix this, when auto mode is enabled kind of reset the timer with:

relayMillis -= RLYdelay;

This will force the check to always be true the next time the automode is run after enabling it.

#include <LiquidCrystal.h>
#include <Keypad.h>

//KEYPAD SETUP
const byte ROWS = 4; //DEFINE NUMBER OF ROWS ON KEYPAD
const byte COLS = 3; //DEFINE NUMBER OF COLUMNS ON KEYPAD
char keys[ROWS][COLS] = { //ARRAY FOR KEYPAD KEYS
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};//END ARRAY FOR KEYPAD KEYS

byte rowPins[ROWS] = {3, 10, 9, 2}; //PINS WHERE THE ROWS OF THE KEYPAD IS CONNECTED
byte colPins[COLS] = {17, 16, 15}; //PINS WHERE THE COLUMNS OF THE KEYPAD IS CONNECTED

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );//MAKING KEYMAP FOR KEYPAD


//LCD DISPLAY SETUP
LiquidCrystal lcd(7, 6, 5, 4, A0, 8);  //PINS WHERE THE LCD DISPLAY IS CONNECTED
/*
 * LCD RS pin to digital pin 7
 * LCD Enable pin to digital pin 6
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin A0
 * LCD D7 pin to digital pin 8
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:               VO on display connected directly to GND.
 * ends to +5V and ground      For optimising contract, use a potmeter as described
 * wiper to LCD VO pin (pin 3)
 */
 
 /* not used...
const unsigned long debounceValue = 50UL; //SETTING FOR DEBOUNCE TIME IN MILLISECONDS
unsigned long debounceTime; //VARIABLE FOR DEBOUNCING KEYS PRESSED
*/

boolean autoModeEnable = 0;           //SETTING BOOLEAN VARIABLE FOR TOGGLING BETWEEN MANUAL AND AUTOMODE
boolean manKey1;          //SETTING BOOLEAN VARIABLE FOR MANUAL OPERATION
boolean manKey2;          //SETTING BOOLEAN VARIABLE FOR MANUAL OPERATION
boolean manKey3;          //SETTING BOOLEAN VARIABLE FOR MANUAL OPERATION


const byte rly1 = 11;      //DEFINE RELAY 1 VARIABLE ON PIN11
const byte rly2 = 12;      //DEFINE RELAY 2 VARIABLE ON PIN12
const byte rly3 = 13;      //DEFINE RELAY 3 VARIABLE ON PIN13

//Can use it local..
//unsigned long currentMillis;  //CURRENTMILLIS MUST BE UNSIGNED LONG TO AVOID STACK OVERFLOW
unsigned long relayMillis;      //RLYMILLIS MUST BE UNSIGNED LONG TO AVOID STACK OVERFLOW
const int RLYdelay = 10000;//RLYDELAY 
//No it does not...
/*MUST BE UNSIGNED LONG TO AVOID STACK OVERFLOW - DECIDES THE AMOUNT OF TIME EACH RELAY SHOULD BE ON IN AUTOMODE*/

byte currentState;        //MAKE VARIABLE CURRENTSTATE

//INITIALIZE SETUP
void setup()
{
  Serial.begin(9600);        //SET BAUD RATE


  lcd.begin(20, 2);   // SETTING UP LCD'S NUMBER OF COLUMNS AND ROWS

  debounceTime = millis(); //DEBOUNCETIME = CURRENT TIME

  pinMode(rly1, OUTPUT);  //RELAY 1 PIN IS OUTPUT
  digitalWrite(rly1, LOW); //INITIALLY RELAY 1 IS OFF
  pinMode(rly2, OUTPUT);  //RELAY 2 PIN IS OUTPUT
  digitalWrite(rly2, LOW); //INITIALLY RELAY 2 IS OFF
  pinMode(rly3, OUTPUT);  //RELAY 3 PIN IS OUTPUT
  digitalWrite(rly3, LOW); //INITIALLY RELAY 2 IS OFF

  keypad.addEventListener(keypadEvent); //INITIALIZE CHECKUP ON KEYPAD USAGE
} // END OF SETUP

//INITIALIZE THE MAIN LOOP
void loop()
{
  /* You never use this.... and all related stuff as well
  char key = keypad.getKey();
  //================== is it time to check the switches?
  if (millis() - debounceTime >= debounceValue)
  {
    debounceTime = millis(); //re-initialize to the current time
  }
  */
  if (autoModeEnable) {
    automode();
  }
  else{
    manualmode();
  }
}//END MAIN LOOP=============================================================================================

//INITIALIZE THE MANUAL MODE FUNCTION========================================================================
void manualmode (void)

{
  lcd.setCursor(0, 0);
  lcd.print ("Manual Mode Enabled   ");
  
  lcd.setCursor(0, 1);
  if (manKey1) {
    digitalWrite (rly1, HIGH);
    lcd.print ("1:ON ");
  }
  else{
    digitalWrite (rly1, LOW);
    lcd.print ("1:OFF");
  }
  
  lcd.setCursor(6, 1);
  if (manKey2) {
    digitalWrite (rly2, HIGH);
    lcd.print ("2:ON ");
  }
  else{
    digitalWrite (rly2, LOW);
    lcd.print ("2:OFF");
  }
  
  lcd.setCursor(12, 1);
  if (manKey3) {
    digitalWrite (rly3, HIGH);
    lcd.print ("3:ON ");
  }
  else{
    digitalWrite (rly3, LOW);
    lcd.print ("3:OFF");
  }

}//END MANUAL MODE FUNCTION==================================================================================

//INITIALIZE THE AUTOMODE FUNCTION========================================================================
void automode (void)
{
  unsigned long currentMillis = millis(); //local ;)
  
  lcd.setCursor(0, 0);
  lcd.print ("Automode Enabled    ");
   //print the number of seconds since reset:
  //lcd.setCursor(0, 1);
  //lcd.print ("Been running for:");
  //lcd.setCursor(18, 1);
  //lcd.print(millis() / 1000);
 
  //see above..
  //currentMillis = millis();

 if (currentMillis - relayMillis >= RLYdelay)
  {
    relayMillis = currentMillis;

    switch (currentState)
    {
     
      //***************************
      case 1:
 
   
        lcd.setCursor(0, 1);
        lcd.print ("Relay 1 ON            ");
        digitalWrite(rly1, HIGH);
        currentState = 2;
        break;
      //***************************
      case 2:

        lcd.setCursor(0, 1);
        lcd.print ("Relay 2 ON            ");
        digitalWrite(rly1, LOW);
        digitalWrite(rly2, HIGH);
        //Change to the next state
        currentState = 3;
        break;
      //***************************
      case 3:

        lcd.setCursor(0, 1);
        lcd.print ("Relay 3 ON            ");
        digitalWrite(rly2, LOW);
        digitalWrite(rly3, HIGH);
        //Change to the next state
        currentState = 4;
        break;
      //***************************
      case 4:

        lcd.setCursor(0, 1);
        lcd.print ("All relays OFF        ");
        digitalWrite(rly3, LOW);
        //Change to the next state
        currentState = 1;
        break;
      //***************************

      default:
        currentState = 1;              //Back to state 1
    } // END SWITCH/CASE===========================================================
  } //END IF STATEMENT=============================================================
} //END THE AUTOMODE FUNCTION======================================================

void keypadEvent(KeypadEvent key) {
  //button pressed check
  if (keypad.getState() == PRESSED) {
    //If in manual mode
    if(!autoModeEnable){
      if (key == '1') { 
        mankey1 = !manKey1;
      }//END 'IF KEY 1'

      else if (key == '2') {
        manKey2 = !manKey2;
      }//END 'IF KEY 2'

      else if (key == '3') { 
        manKey3 = !manKey3;
      }//END 'IF KEY 3'
    }
    
    if (key == '#') { //if key '#' is pressed, toggle autoModeEnable
      autoModeEnable = !autoModeEnable;
      
      //clearing the display line 2 to avoid conflict when toggling between auto and manual
      lcd.setCursor(0, 1);
      for(byte i = 0; i < 31; i++){
        lcd.print(" ");
      }
      
      //this will force the automode delay to be true the first time
      relayMillis -= RLYdelay;
      
  }//END of pressed
}//END KEYPADEVENT FUNCTION

Thanks for the reply... seems like you had your work cut out for you. :slight_smile:

Well, the code doesn't compile, and I can't find the reason why just at the moment.. but I will try to implement the stuff you suggested. :slight_smile:

I may have made a mistake somewhere. I couldn't check because I was to lazy to search for the keypad library. If you past the error message I'll have a look.

Doesnt matter... implemented relayMillis -= RLYdelay; where you said, and it works like a charm. But what exactly does the '-=' do? Also redid the key toggles as per your example. MUCH easier to read!

About the :

const int RLYdelay = 10000;//RLYDELAY 
//No it does not..

Why doesn't what, and if not - then what?

And:

unsigned long currentMillis = millis(); //local ;)

Any advantage of doing it like this or is it just to keep it seperate from the rest of the code to make it easier to understand what's going on?

Indeed way more readable :slight_smile: Have you also seen I move some if statements around?

RLYdelay doesn't need to be a long. It will never store data from millis but only a fixed value. 10000 in this case so an int is okay.

Indeed, if you don't need something to be global don't make it global.

And here's another tip.

Thanks man... added 1 more karma your way. Also, I edited my post with a question about the function of '-='... what does it do?

Have a look at Wikipedia.

In other words a -= b is short hand for a = a - b

Alright... nice to know. Too much shortening of commands can be tough on a newcomer. :slight_smile:

Now that I'm pestering you with questions, how about just one more? I'm wondering why my auto function starts with no relays on and not relay 1 on.

Quite simple, currentState isn't initialized so it's 0. 0 isn't a case in the switch so the default case is used which is just setting the currentState to 1. I guess you would always want to start at state 1 when you start autoMode?

Add "currentState = 1;" after the "relayMillis -= RLYdelay;"

That's so simple and logic I'm almost ashamed.. guess I could also just put a '=1' where I set the variable. :slight_smile:

You can indeed but if you want the auto mode to always start at state 1 you need to add it in the keypadEvent as well. Because otherwise if you stop auto mode at state 3 it will start at state 3 the next time you enable auto mode.