Cannot use milli() instead of delay()

Hello,
I'm looking for your help, I'm working on this code and I tried to replace delay() with millis() to add more functions that will run right after the delay(), but to be honest I'm not totally understanding how it precisely works, I tried but I think I'll understand practicing, so here's the full code before millis()

[code]
#include <Keypad.h>
#include <LiquidCrystal.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {6 , A1, 2, 4}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 7, 3}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
const int rs = 13, en = 12, d4 = 11, d5 = 10, d6 = 9, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int RELAY_PIN  = A0; // the Arduino pin, which connects to the IN pin of relay
const String password_1 = "03121990"; // change your password here
String input_password;
int cursorColumn = 0;
const int Beep = A2;

void setup()
{
  input_password.reserve(16);    // maximum input characters is 33, change if needed
  pinMode(RELAY_PIN, OUTPUT);    // initialize pin as an output.
  digitalWrite(RELAY_PIN, HIGH); // lock the door
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  pinMode (A2, OUTPUT);
}

void loop()
{  
  {
  lcd.setCursor(0, 0);
  lcd.print("ENTER PASSWORD:");
  }
  char key = keypad.getKey();
  {
  if (key)
  tone(A2, 2500, 100);
  }
  if (key)
  {
  if(key == '*')
  {
      input_password = ""; // reset the input password
      lcd.clear();
  } else if(key == '#')
    {
      lcd.clear();
      if(input_password == password_1)
      {
        lcd.setCursor(0, 0);
        lcd.print("CORRECT!");
        lcd.setCursor(0, 1);
        lcd.print("ACCESS GRANTED!");
        digitalWrite(RELAY_PIN, LOW);  // unlock the door for 20 seconds
        delay(2000);
        lcd.clear();
        delay(10000);
        digitalWrite(RELAY_PIN, HIGH); // lock the door
      }
      else
      {
        lcd.setCursor(0, 0);
        lcd.print("INCORRECT!");
        lcd.setCursor(0, 1);
        lcd.print("ACCESS DENIED!");
        delay(2000);
        lcd.clear();
      }

      input_password = ""; // reset the input password
    }
      else
      {
      if(input_password.length() == 0) {
        lcd.clear();
      }
      input_password += key; // append new character to input password string
      lcd.setCursor(input_password.length(), 2); // move cursor to new position
      lcd.print('*');                 // print * key as hiden character
      }
  }
}

[/code]

appreciate your help!!

You say you tried to change that to use millis() so post your best attempt. Then we can help you get it working. It's not very likely that anyone will want to simply do all the work for you.

Steve

Here is a very clear explanation/tutorial on use of millis().

You have to swim across a large pool. You are a good swimmer, this should not be a problem.

Do you..

A) Try to hold your breath the entire way across?

or

B) Take breaths at every stroke?

You wrote your code so it holds it breath 'till the fade is done.

We are trying to tell you to take a stroke, take a breath. Repeat.

Enter loop()
look at the time.
IF its time to make a change of the fade, do the change.
recalculate the time for the next change.
done.

Now, if you don't want to deal with millis() and all that. There is a timeObj you can use that tells you when your time is up. If you are still stuck, we can try that. (Its what I use.)

-jim lee

@JimLee, timeObj ? Please give a link.

@starwalker90, I see three options:

1. Basic
Doing everything with millis timers. Keep track of what you do with a variables. The code will not be pleasant to look at.

2. Finite State Machine
If you want to add more things, perhaps make it ten times more complex in the future, then you can implement a Finite State Machine. But only if you understand it for 100% : The Finite State Machine | Majenko Technologies.

3. A library
A library that can initiate a single-shot timer with a callback function can be helpful.

Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.

Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

And see Using millis() for timing. A beginners guide if you need more explanation.

...R

Here's my try in Millis() and I still got errors,

#include <Keypad.h>
#include <LiquidCrystal.h>
const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {6 , A1, 2, 4};
byte colPins[COLS] = {5, 7, 3};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
const int rs = 13, en = 12, d4 = 11, d5 = 10, d6 = 9, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int RELAY_PIN  = A0;
const String password_1 = "03121990";
int cursorColumn = 0;
const int Beep = A2;

unsigned long previousMillis = 0;
unsigned long interval = 1000;
int RELAY_STATE = HIGH;

void setup()
{
  input_password.reserve(16);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH);
  lcd.begin(16, 2);
  pinMode (A2, OUTPUT);
}

void loop()
{
  {
    lcd.setCursor(0, 0);
    lcd.print("ENTER PASSWORD:");
  }
  char key = keypad.getKey();
  {
    if (key)
      tone(A2, 2500, 100);
  }
  if (key)
  {
    if (key == '*')
    {
      input_password = "";
      lcd.clear();
    } else if (key == '#')
    {
      lcd.clear();
      if (input_password == password_1)
      {
        lcd.setCursor(0, 0);
        lcd.print("CORRECT!");
        lcd.setCursor(0, 1);
        lcd.print("ACCESS GRANTED!");
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis > interval) {
          previousMillis = currentMillis;
          if (RELAY_STATE == HIGH)
          RELAY_STATE = LOW;
          else
          RELAY_STATE = HIGH;
          digitalWrite(RELAY_PIN, RELAY_STATE);
        }
      }
      else
      {
        lcd.setCursor(0, 0);
        lcd.print("INCORRECT!");
        lcd.setCursor(0, 1);
        lcd.print("ACCESS DENIED!");
        delay(2000);
        lcd.clear();
      }

      input_password = "";
    }
    else
    {
      if (input_password.length() == 0) {
        lcd.clear();
      }
      input_password += key; // append new character to input password string
      lcd.setCursor(input_password.length(), 2); // move cursor to new position
      lcd.print('*');                 // print * key as hiden character
    }
  }
}

@Koepel Its at your fingertips as we type.

timeObj -> IDE library manager : LC_baseTools

LC_baseTools is the tool set I use to keep out of this low level morass.

-jim lee

1 - Where is input_password declared ?

      tone(2, 2500, 100);

2 - You have not #included the Tone library

  {
    lcd.setCursor(0, 0);
    lcd.print("ENTER PASSWORD:");
  }
  char key = keypad.getKey();
  {
    if (key)
      tone(2, 2500, 100);
  }

3 - What are the braces there for ?

the tone is working on keypress that way tone(PIN, FREQ, DURATION) and about input_password braces that's why i get an error, still hasn't solved

You are correct, tone() does not need a library #included in order to work

You need to declare input_password before you use it

Please share the full error messages with us

UKHeliBob:
You are correct, tone() does not need a library #included in order to work

You need to declare input_password before you use it

Please share the full error messages with us

Arduino: 1.8.13 (Windows Store 1.8.42.0) (Windows 10), Board: "Arduino Uno"
C:\Users\Bilal\AppData\Local\Temp\arduino_modified_sketch_806079\sketch_oct21b.ino: In function 'void setup()':
sketch_oct21b:28:3: error: 'input_password' was not declared in this scope
input_password.reserve(16);
^~~~~~~~~~~~~~
C:\Users\Bilal\AppData\Local\Temp\arduino_modified_sketch_806079\sketch_oct21b.ino: In function 'void loop()':
sketch_oct21b:50:7: error: 'input_password' was not declared in this scope
input_password = "";
^~~~~~~~~~~~~~
sketch_oct21b:55:11: error: 'input_password' was not declared in this scope
if (input_password == password_1)
^~~~~~~~~~~~~~
sketch_oct21b:81:7: error: 'input_password' was not declared in this scope
input_password = "";
^~~~~~~~~~~~~~
sketch_oct21b:85:11: error: 'input_password' was not declared in this scope
if (input_password.length() == 0) {
^~~~~~~~~~~~~~
sketch_oct21b:88:7: error: 'input_password' was not declared in this scope
input_password += key; // append new character to input password string
^~~~~~~~~~~~~~
exit status 1
'input_password' was not declared in this scope

Declare input_password as a String at the start of the sketch

UKHeliBob:
Declare input_password as a String at the start of the sketch

I found that it has been removed by mistake at the start of the code, now i have no errors but I still cannot make the Relay lock after exact time using milli()

#include <Keypad.h>
#include <LiquidCrystal.h>
const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {6 , A1, 2, 4};
byte colPins[COLS] = {5, 7, 3};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
const int rs = 13, en = 12, d4 = 11, d5 = 10, d6 = 9, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int RELAY_PIN  = A0;
const String password_1 = "03121990";
String input_password;
int cursorColumn = 0;
const int Beep = A2;

unsigned long previousMillis = 0;
unsigned long interval = 1000;
int RELAY_STATE = HIGH;

void setup()
{
  input_password.reserve(16);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH);
  lcd.begin(16, 2);
  pinMode (A2, OUTPUT);
}

void loop()
{
  {
    lcd.setCursor(0, 0);
    lcd.print("ENTER PASSWORD:");
  }
  char key = keypad.getKey();
  {
    if (key)
      tone(A2, 2500, 100);
  }
  if (key)
  {
    if (key == '*')
    {
      input_password = "";
      lcd.clear();
    } else if (key == '#')
    {
      lcd.clear();
      if (input_password == password_1)
      {
        lcd.setCursor(0, 0);
        lcd.print("CORRECT!");
        lcd.setCursor(0, 1);
        lcd.print("ACCESS GRANTED!");
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis > interval) {
          previousMillis = currentMillis;
          if (RELAY_STATE == HIGH)
          RELAY_STATE = LOW;
          else
          RELAY_STATE = HIGH;
          digitalWrite(RELAY_PIN, RELAY_STATE);
        }
      }
      else
      {
        lcd.setCursor(0, 0);
        lcd.print("INCORRECT!");
        lcd.setCursor(0, 1);
        lcd.print("ACCESS DENIED!");
        delay(2000);
        lcd.clear();
      }
      input_password = "";
    }
    else
    {
      if (input_password.length() == 0) {
        lcd.clear();
      }
      input_password += key; // append new character to input password string
      lcd.setCursor(input_password.length(), 2); // move cursor to new position
      lcd.print('*');                 // print * key as hiden character
    }
  }
}

I still cannot make the Relay lock after exact time using milli()

Do not embed the millis() timing section inside the key reading routine. If the password is correct, set a control flag to enable running the relay lock code. Clear the flag when done.

cattledog:
Do not embed the millis() timing section inside the key reading routine. If the password is correct, set a control flag to enable running the relay lock code. Clear the flag when done.

I'm sorry and excuse my unawareness, but what does a control flag mean??

what does a control flag mean??

Conventionally it would be a boolean variable with a meaningful name set to true when something has happened, something like

correctPassword = true;

Then later you can test the value and act, such as changing the state of the relay, if it is true