Security Keypad for Locks

Hi guys, I am new to arduino, currently doing a project base on security keypad. My aim is to build:

  1. Keypad, whenever i press it will have sound with it.
  2. Manually lock with choices if password want to be change or not it will go back to lock screen.
  3. Able to change password during lock screen when button A is pressed.
  4. When password key is wrong more than 3 times will get locked out and siren will be activated. Will be send to a screen displaying 'Provide Master Key to unlock'.

What I want to improvise on:

  1. Think of a way for the keypad to trigger into master key screen.
  2. Keypad 123A is not working, want to know where the coding gone wrong.

The code is under attachments. Please provide some assistance and thank you for your time and assistance in advance.

Testing_02.ino (11.8 KB)

Serial communication between the Arduino and your PC use pins 0 and 1 but you are also using pin 1 for your keypad. That will not work. rewire your keypad to use a different pin.

you did not do anything wrong. I just post this for every new guy:
Read "How To Use This Forum"

in particular, 7. If you are posting code or error messages, use "code" tags

This is what happens when you do not

The Arduino UNO only has one hardware serial port. it is used by the USB connection. it works best if you use Software Serial or another serial communication library for serial connections and stay off pins 1 and 0. or use a mega, which has 4 hardware serial ports

look in the Project Hub for similar projects. this wheel has been invented

blh64:
Serial communication between the Arduino and your PC use pins 0 and 1 but you are also using pin 1 for your keypad. That will not work. rewire your keypad to use a different pin.

Thank you so much guys for your advises, manage to use keypad 123A again but i am still stuck on the triggering part. Can't figure out how to use keypad to cut off the siren command while its running. Read some article about keypad.addEventListener, still figuring out how to use it.

Currently, using delay and move on to master screen but my aim is to use keypad and trigger into the master key screen instead. Another thing is once I am in master key screen, no matter what I key in, the screen will not go back to lock screen. Please provide me some insights thank you.

And how do I use "code" tags?

Testing_03.ino (12.4 KB)

tsunaliew:
And how do I use "code" tags?

How to use this forum.

You can't add a 11 kB file using code tags. So don't worry too much.

dougp:
How to use this forum.

Thanks, didn't saw this guide during previous post.

This is the code i am currently struggling with:

void Attempts() {
  if (WrongAttempts >= 3) { //UPS....
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("TO UNLOCK PLEASE");
    lcd.setCursor(0, 1);
    lcd.print("INPUT MASTER KEY");
    siren();
  }
  else {
    if (keypressed == 'B') {
      master();
    }
  }
}

void master() {
lockAgain: //goto label
retry: //label for goto
  lcd.clear();
  i = 1;
  while (password += keypressed) {      //Waiting for master password
    keypressed = myKeypad.getKey();   //Read pressed keys
    lcd.setCursor(0, 0);
    lcd.print("***MASTER KEY***");
    lcd.setCursor(0, 1);
    lcd.print(">");
    if (keypressed != NO_KEY) {
      if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
          keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
          keypressed == '8' || keypressed == '9' ) {
        password += keypressed;
        lcd.setCursor(i, 1);
        lcd.print("*");
        i++;
        tone(buzzer, 800, 200);
      }
      else if (keypressed == '#') {
        break;
      }
      else if (keypressed == '*') { //Check for password
        i = 1;
        if (password) {                  //If it's correct...
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Correct Password");
          goto lockAgain;
        }
        else {              //Try again
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*Wrong Password*");
          tone(buzzer, 500, 200);
          delay(300);
          tone(buzzer, 500, 200);
          delay(300);
          goto retry;
        }
      }
    }
  }
}

How to use keypad when siren command is running? I want both siren and keypad to work at the same time.

void master() {
  lcd.clear();
  i = 1;
  while (!checkPassword) {      //Waiting for master password
    lcd.setCursor(0, 0);
    lcd.print("***MASTER KEY***");
    lcd.setCursor(0, 1);
    lcd.print(">");
    keypressed = myKeypad.getKey();   //Read pressed keys
    if (keypressed != NO_KEY) {
      if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
          keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
          keypressed == '8' || keypressed == '9' ) {
        master_password += keypressed;
        lcd.setCursor(i, 1);
        lcd.print("*");
        i++;
        tone(buzzer, 800, 200);
      }
      else if (keypressed == '#') {
        break;
      }
      else if (keypressed == '*') {
        if (master_password += keypressed) {
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Correct Password");
          tone(buzzer, 100);   //Play a tone while door is unlocked
          delay(100);        // ...for 0.1 sec
          noTone(buzzer);     // Stop sound...
          delay(5000);
          unlockTheDoor();
        }
        else {              //Try again
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("*Wrong Password*");
          tone(buzzer, 500, 200);
          delay(300);
          tone(buzzer, 500, 200);
          delay(300);
          WrongAttempts++;  //ADDED
          Attempts();
        }
      }
    }
  }
}

I am having trouble figuring out this part of the code, do not know where went wrong. No matter what code I enter, it keep says correct, i want the master code to be the only code to unlock the master key screen.

else if (keypressed == '*') {
        if (master_password == keypressed) {
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Correct Password");
          tone(buzzer, 100);   //Play a tone while door is unlocked
          delay(100);        // ...for 0.1 sec
          noTone(buzzer);     // Stop sound...
          delay(5000);
          unlockTheDoor();
        }

If i change it to (master_password == keypressed) double equal it say wrong password.

And I have not found any project that can use siren and keypad at the same time. Please tell me whats wrong.

Testing_04.ino (12.6 KB)

I think it would be best to change your design to a "state machine" rather than having a big pile of state flags that you have to check everywhere. You obviously have a bunch of states and figuring out which one you are in is going to be complicated and error prone.

Lock Clear input buffer.
Wait for password character, retry key, password change key, or 'Enter' key.
On 'Enter': Check password.
Password correct, unlock. Reset password failure count.
Wait for lock request.

Password incorrect.
Wait for retry request.
Too many password failures.
Sound alarm, clear input buffer.
Wait for alarm master password.

On password change key:
Wait for master password.
Check master password.
Valid master password: Clear master password failure count. Wait for new password
On enter: Repeat new password.
Valid repeat: Store new password

Invalid master password.
Wait for password retry or password change request.
Too many invalid master password failures: Alarm.

johnwasser:
I think it would be best to change your design to a "state machine" rather than having a big pile of state flags that you have to check everywhere. You obviously have a bunch of states and figuring out which one you are in is going to be complicated and error prone.

Lock Clear input buffer.
Wait for password character, retry key, password change key, or 'Enter' key.
On 'Enter': Check password.
Password correct, unlock. Reset password failure count.
Wait for lock request.

Password incorrect.
Wait for retry request.
Too many password failures.
Sound alarm, clear input buffer.
Wait for alarm master password.

On password change key:
Wait for master password.
Check master password.
Valid master password: Clear master password failure count. Wait for new password
On enter: Repeat new password.
Valid repeat: Store new password

Invalid master password.
Wait for password retry or password change request.
Too many invalid master password failures: Alarm.

Thank you so much for your advice. Thanks to your post it have given me a better idea what to improve on and make me figure out what is wrong with the master function. Right now the only thing that is still bothering me is the siren.

Is there anyway to keep the siren function running while keypad able to press 'B' interrupt and trigger into the master function?

Testing_05.ino (13.8 KB)

topic=642475.0

First things first
1)
Use decent names for your variables. The letter 'l' does not mean anything at all; neither does the letter 'x' or any of the others. Searching for the variable named 'l' is a disaster; the letter 'l' occured 330 times in the code in reply #9 and not all of them refer to the variable.
2)
To solve your issue, get rid of for-loops (and the likes) and delays. It makes your code unresponsive.
3)
Get rid of goto.

Below a rewrite of sound2_5. My understanding of your code is that variables 'x' and 'y' represent the minimum and maximum frequency of the siren and that variable 'l' represents a frequency.

Your current variable 'j' represents the number of times that you want the siren to cycle.

Note in advance:
static variables are remembered just like global variables when the function finishes; they however have local scope (only known in the function where they are used).

At the top of your code, rename the variables 'x' and 'y' to reflect their real meaning; I've also renamed t2 (based on how I understand your code). The below assumes that these variables never change (I did not look too much at the rest of your code).

// siren constants
const uint16_t minSirenFrequency = 400;
const uint16_t maxSirenFrequency = 1000;
const uint32_t sirenToneDuration = 500;

Next the sound2_5

/*
  sound2_5
  In:
    stop; if true, forces the stop state
  Returns:
    true when siren has cycled 10 times or is stopped, else false
*/
bool sound2_5(bool reset)
{
  // count the cycles
  static uint8_t numCycles;
  // the current frequency
  static uint16_t frequency;
}

Variable 'n' is a variable that indicates if you want to increase the frequency or decrease the frequency. We will implement a simple state machine with three steps reflecting the three states (increase, decrease, off)

  // indicate if we want to increase (0) or decrease (1) the frequency or switch the buzzer off (2)
  static uint8_t state = 0;

Next you can implement the states; each state will do one step of the increase or decrease or switches the buzzer off. Below the framework.

/*
  sound2_5
  In:
    stop; if true, forces the stop state
  Returns:
    true when siren has cycled 10 times or is stopped, else false
*/
bool sound2_5(bool stop)
  // count the cycles
  static uint8_t numCycles;
  // the current frequency; initial value minSirenFrequency
  static uint16_t frequency = minSirenFrequency;
  // indicate if we want to increase (0) or decrease (1) the frequency or switch the buzzer off (2); initial value increase (0)
  static uint8_t state;

  delayMicroseconds(sirenToneDuration);

  switch (state)
  {
    // increase siren frequency
    case 0:
      // do whatever needs to be done
      // stop when you reach maxSirenFrequency and go to decrease state
      break;
    // decrease siren frequency
    case 1:
      // do whatever needs to be done
      // stop when you reach minSirenFrequency, increment number of cycles and go to off state when all cycles done or to the increase state when not
      break;
    // buzzer off
    case 2:
      // do whatever needs to be done
      // cleanup
      break;
  }
}

Before we do the real implementation, we will give the numbers 0, 1 and 2 meaningful names. Place the below near the top of your code.

// sound states
enum SOUND_STATES
{
  SOUND_INCREASE,
  SOUND_DECREASE,
  SOUND_STOP,
};
/*
  sound2_5
  In:
    stop; if true, forces the stop state
  Returns:
    true when siren has cycled 10 times, else false
*/
bool sound2_5(bool stop)
{
  // count the cycles
  static uint8_t numCycles;
  // the current frequency; initial value minSirenFrequency
  static uint16_t frequency = minSirenFrequency;
  // indicate if we want to increase or decrease the frequency or switch the buzzer off; initial value increase
  static SOUND_STATES state = SOUND_INCREASE;

  if (stop == true)
  {
    Serial.println("stop");
    state = SOUND_STOP;
  }

  delayMicroseconds(sirenToneDuration);

  switch (state)
  {
    case SOUND_INCREASE:
      //Serial.print("frequency = ");
      //Serial.println(frequency);
      tone(buzzer, frequency);
      frequency += 2;
      // if we've reached the maximum frequency
      if (frequency >= maxSirenFrequency)
      {
        // go to the next state
        state = SOUND_DECREASE;
      }
      return false;
    case SOUND_DECREASE:
      //Serial.print("frequency = ");
      //Serial.println(frequency);
      tone(buzzer, frequency);
      frequency -= 2;
      if (frequency <= minSirenFrequency)
      {
        numCycles++;
        Serial.println(numCycles);
        if (numCycles < 10)
        {
          state = SOUND_INCREASE;
        }
        else
        {
          state = SOUND_STOP;
        }
      }
      return false;
    case SOUND_STOP:
      Serial.println("off");
      noTone(buzzer);
      numCycles = 0;
      state = SOUND_INCREASE;
      return true;
    default:
      return false;
  }
}

The SOUND_INCREASE state stops when the maximum frequency is reached by changing the state variable to SOUND_DICREASE. The next time that you call the sound2_5 function, it will do the decrease of the frequency

The default case was added to keep the compiler happy.

You need to call this function as often as possible from e.g. loop(); directly or indirectly (from your siren() function).

Below demonstrates the use of the function in loop(). The code uses the Serial input to start (and optionally) stop the siren.

void loop()
{
  static bool runIt = false;
  if (Serial.available() > 0)
  {
    char ch = Serial.read();
    Serial.println(ch);
    if (ch == 'A')
    {
      runIt = true;
    }
    else if (ch == 'B')
    {
      sound2_5(true);
      runIt = false;
    }
  }

  if (runIt == true)
  {
    if (sound2_5(false) == true)
    {
      sound2_5(true);
      runIt = false;
    }
  }
}

If you press A in a terminal program, the siren starts. You can interrupt it by pressing be or let it run till completion.

The sound2_5() function now no longer uses a for-loop which makes it more responsive but it still uses a delay. To get rid of that, you will have to use a micros() based approach.

Add two variables to the function.

  // keep track of startTime of delay
  static uint32_t delayStartTime;
  // keep track if the siren was already started or not
  static bool sirenInProgress = false;

And add an else to the if(stop == true).

  if (stop == true)
  {
    Serial.println("stop");
    state = SOUND_STOP;
  }
  else
  {
    // do timing here; replace delayMicroseconds
  }

And the implementation with explanation

  else
  {
    // if this is the first time that the function is called for the sequence
    if (sirenInProgress == false)
    {
      delayStartTime = micros();
      sirenInProgress = true;
    }

    // if it's not time yet
    if (micros() - delayStartTime < sirenToneDuration)
    {
      // nothing to do yet
      return false;
    }

    delayStartTime = micros();
  }

Once you have modified all your sound functions, you can implement the above in a state machine in siren(). If all your sound functions are implemented as shown, siren can look like (not tested)

bool siren()
{
  static uint8_t state;

  switch (state)
  {
    case 0:
      if (sound2_1(false) == true)
        state++;
      break;
    case 1:
      if (sound2_1(false) == true)
        state++;
      break;
    case 2:
      delay(300);
      state++;
      break;
    case 3:
      if (sound2_3(false) == true)
        state++;
      break;
    case 4:
      if (sound2_2(false) == true)
        state++;
      break;
    case 5:
      delay(300);
      state++;
      break;

    // other case here
    ...
    ...
    default:
      noTone(buzzer);
      delay(1000);
      state = 0;
      return true;
      //break;
  }
  return false;
}

Full example code without the siren() function; just in case there are bugs in the snippets above

// pins
const uint8_t buzzer = 10;        //Buzzer/small speaker

// siren constants
const uint16_t minSirenFrequency = 400;
const uint16_t maxSirenFrequency = 1000;
const uint32_t sirenToneDuration = 500;

// siren states
enum SOUND_STATES
{
  SOUND_INCREASE,
  SOUND_DECREASE,
  SOUND_STOP,
};

void setup()
{
  Serial.begin(57600);
  while (Serial.available() > 0)
  {
    Serial.read();
  }
}

void loop()
{
  static bool runIt = false;
  if (Serial.available() > 0)
  {
    char ch = Serial.read();
    Serial.println(ch);
    if (ch == 'A')
    {
      runIt = true;
    }
    else if (ch == 'B')
    {
      sound2_5(true);
      runIt = false;
    }
  }

  if (runIt == true)
  {
    if (sound2_5(false) == true)
    {
      runIt = false;
    }
  }
}


/*
  sound2_5
  In:
    stop; if true, forces the stop state
  Returns:
    true when siren has cycled 10 times, else false
*/
bool sound2_5(bool stop)
{
  // count the cycles
  static uint8_t numCycles;
  // the current frequency; initial value minSirenFrequency
  static uint16_t frequency = minSirenFrequency;
  // indicate if we want to increase (0) or decrease (1) the frequency or switch the buzzer off (2); initial value increase (0)
  static SOUND_STATES state = SOUND_INCREASE;

  // keep track of startTime of delay
  static uint32_t delayStartTime;
  // keep track if the siren was already started or not
  static bool sirenInProgress = false;

  if (stop == true)
  {
    Serial.println("stop");
    state = SOUND_STOP;
  }
  else
  {
    // if this is the first time that the function is called for the sequence
    if (sirenInProgress == false)
    {
      delayStartTime = micros();
      sirenInProgress = true;
    }

    // if it's not time yet
    if (micros() - delayStartTime < sirenToneDuration)
    {
      // nothing to do yet
      return false;
    }

    delayStartTime = micros();
  }

  //delayMicroseconds(sirenToneDuration);

  switch (state)
  {
    case SOUND_INCREASE:
      //Serial.print("frequency = ");
      //Serial.println(frequency);
      tone(buzzer, frequency);
      frequency += 2;
      if (frequency >= maxSirenFrequency)
      {
        state = SOUND_DECREASE;
      }
      return false;
    case SOUND_DECREASE:
      //Serial.print("frequency = ");
      //Serial.println(frequency);
      tone(buzzer, frequency);
      frequency -= 2;
      if (frequency <= minSirenFrequency)
      {
        numCycles++;
        if (numCycles < 1)
        {
          state = SOUND_INCREASE;
        }
        else
        {
          state = SOUND_STOP;
        }
      }
      return false;
    case SOUND_STOP:
      Serial.println("off");
      noTone(buzzer);
      frequency = minSirenFrequency;
      numCycles = 0;
      state = SOUND_INCREASE;
      sirenInProgress = false;
      return true;
    default:
      return false;
  }
}

sterretje:
Full example code without the siren() function; just in case there are bugs in the snippets above

// pins

const uint8_t buzzer = 10;        //Buzzer/small speaker

// siren constants
const uint16_t minSirenFrequency = 400;
const uint16_t maxSirenFrequency = 1000;
const uint32_t sirenToneDuration = 500;

// siren states
enum SOUND_STATES
{
 SOUND_INCREASE,
 SOUND_DECREASE,
 SOUND_STOP,
};

void setup()
{
 Serial.begin(57600);
 while (Serial.available() > 0)
 {
   Serial.read();
 }
}

void loop()
{
 static bool runIt = false;
 if (Serial.available() > 0)
 {
   char ch = Serial.read();
   Serial.println(ch);
   if (ch == 'A')
   {
     runIt = true;
   }
   else if (ch == 'B')
   {
     sound2_5(true);
     runIt = false;
   }
 }

if (runIt == true)
 {
   if (sound2_5(false) == true)
   {
     runIt = false;
   }
 }
}

/*
 sound2_5
 In:
   stop; if true, forces the stop state
 Returns:
   true when siren has cycled 10 times, else false
*/
bool sound2_5(bool stop)
{
 // count the cycles
 static uint8_t numCycles;
 // the current frequency; initial value minSirenFrequency
 static uint16_t frequency = minSirenFrequency;
 // indicate if we want to increase (0) or decrease (1) the frequency or switch the buzzer off (2); initial value increase (0)
 static SOUND_STATES state = SOUND_INCREASE;

// keep track of startTime of delay
 static uint32_t delayStartTime;
 // keep track if the siren was already started or not
 static bool sirenInProgress = false;

if (stop == true)
 {
   Serial.println("stop");
   state = SOUND_STOP;
 }
 else
 {
   // if this is the first time that the function is called for the sequence
   if (sirenInProgress == false)
   {
     delayStartTime = micros();
     sirenInProgress = true;
   }

// if it's not time yet
   if (micros() - delayStartTime < sirenToneDuration)
   {
     // nothing to do yet
     return false;
   }

delayStartTime = micros();
 }

//delayMicroseconds(sirenToneDuration);

switch (state)
 {
   case SOUND_INCREASE:
     //Serial.print("frequency = ");
     //Serial.println(frequency);
     tone(buzzer, frequency);
     frequency += 2;
     if (frequency >= maxSirenFrequency)
     {
       state = SOUND_DECREASE;
     }
     return false;
   case SOUND_DECREASE:
     //Serial.print("frequency = ");
     //Serial.println(frequency);
     tone(buzzer, frequency);
     frequency -= 2;
     if (frequency <= minSirenFrequency)
     {
       numCycles++;
       if (numCycles < 1)
       {
         state = SOUND_INCREASE;
       }
       else
       {
         state = SOUND_STOP;
       }
     }
     return false;
   case SOUND_STOP:
     Serial.println("off");
     noTone(buzzer);
     frequency = minSirenFrequency;
     numCycles = 0;
     state = SOUND_INCREASE;
     sirenInProgress = false;
     return true;
   default:
     return false;
 }
}

Thank you for the explanation but I have given up on the siren as i do not understand how it works, so I have chosen to use (buzzer, high) for 5 sec delay as i cannot find a way to use keypad and interfere while the delay is running.

Right now I am making a safe box using the circuit i made, adding 12V solenoid lock using 8xAA battery with 5V relay module, everything is working perfectly but i am not sure about the total ampere drawn from the circuit. I know that this is not a programming question but i hope someone can correct me if I am wrong.

My plan is to get a 12V 3 pin adapter plug for the whole circuit, connect to L7812 Voltage Regulator Input and the Output to both Arduino and Relay Module (normally open to common) for Solenoid Door Lock. From what I researched and base on my calculation, 16x2 LCD with backlight on (120-160mA), 3-24V piezo buzzer (20mA), 5V relay module (7-10mA), 12V solenoid lock around (1.2A), 4x4 Matrix Membrane Keypad (30mA). Total Ampere will be around 1.42A, what should I get for my adapter?

Is 12V 1.5A/2A 3 pin plug AC/DC adapter acceptable for this?

Connecting 12V to a 12V regulator (L7812) does not make sense.
2)
Compared to modern alternatives like buck/booster converters, the L7812 is extremely inefficient. You will more than likely need a proper heatsink for it.
3)
For your calculation, you need to think in watts (P=V*I). Current at 12V is about 50% of current at 5V. As an example, your LCD counts for 160 * 5/12 mA at the 12V side.

sterretje:
1)
Connecting 12V to a 12V regulator (L7812) does not make sense.
2)
Compared to modern alternatives like buck/booster converters, the L7812 is extremely inefficient. You will more than likely need a proper heatsink for it.
3)
For your calculation, you need to think in watts (P=V*I). Current at 12V is about 50% of current at 5V. As an example, your LCD counts for 160 * 5/12 mA at the 12V side.

So my watt should be around 18 watt?