Electronic Lock System

So the hand in time has passed.
Try to see if you can follow everything in this sketch:

// This demonstrates how to code a simple electronic lock
// using 3 switches wired as below.
// Arduino pin-----SwitchPin1-----SwitchPin2-----GND
// Switch pressed = LOW, released = HIGH
// LarryD
// Version 1.00 16/11/12  code = 1233
//         1.01 17/08/05  added: switch de-bouncing, heartBeatLED stuff
//         1.02 17/08/07  added the following: 
//                        - keyPushedLED, ON when a switch is pushed
//                        - newCodeLED, ON when ready for new code
//                        - failedLED, On if the wrong code is entered
//
//We have 3 switches. If the newCodeLED is on, we are allowed 4 switch presses to open the lock. 
//Any wrong 4 presses will freeze the program for 10 seconds. 
//While frozen any further presses will start the 10 second period over again.
//Four correct presses will turn on the unLockedLED, any further presses will turn off the unLockedLED.
//Each time a switch is pressed the keyPressedLED comes on. 
//


//****************
#define OFF      HIGH
#define ON       LOW
#define Pressed  LOW
#define Released HIGH

//****************
const byte keyPushedLED = 5;
const byte failedLED    = 6;
const byte newCodeLED   = 7;
const byte switch1      = 8;
const byte switch2      = 9;
const byte switch3      = 10;
const byte unLockedLED  = 11;
const byte HeartBeatLED = 13;

//****************
byte lastSwitch1        = Released;
byte lastSwitch2        = Released;
byte lastSwitch3        = Released;
byte pushedCounter      = 0;

//****************
const unsigned long HeartBeatDelay = 500ul;       //500ms
unsigned long HeartBeatMillis;

unsigned long bounceMillis;
const unsigned long bounceDelay    = 10ul;        //10ms

unsigned long failedMillis;
unsigned long failedDelay          = 10 * 1000ul; //10 seconds

//****************
enum MachineStates {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, FAILED, WAIT};
MachineStates STATE = ZERO;

//OR
//enum MachineStates {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, FAILED, WAIT} STATE = ZERO;



//                      s e t u  p ( )
//***********************************************************
void setup()
{
  pinMode(switch1, INPUT_PULLUP);
  pinMode(switch2, INPUT_PULLUP);
  pinMode(switch3, INPUT_PULLUP);

  pinMode(unLockedLED, OUTPUT);
  digitalWrite(unLockedLED, OFF);
  
  pinMode(keyPushedLED, OUTPUT);
  digitalWrite( keyPushedLED, OFF);
  
  pinMode(newCodeLED, OUTPUT);
  digitalWrite(newCodeLED, OFF);
  
  pinMode(failedLED, OUTPUT);
  digitalWrite(failedLED, OFF);
  
  pinMode(HeartBeatLED, OUTPUT);

  bounceMillis = millis();

} //END of             s e t u  p ( )


//                      l o o p ( )
//***********************************************************
void loop()
{
  //****************
  //helps check for blocking code
  if (millis() - HeartBeatMillis >= HeartBeatDelay)
  {
    //reset timing
    HeartBeatMillis = millis();
    //toggle the HeartBeatLED
    digitalWrite(HeartBeatLED , !digitalRead(HeartBeatLED));
  }

  //****************
  switch (STATE)
  {
    case ZERO:
      {
        //Lock the device
        digitalWrite(unLockedLED, OFF);
        digitalWrite(newCodeLED, OFF);
        pushedCounter = 0;

        //Proceed
        STATE = ONE;

      }
      break;

    //****************
    case ONE:
      {
        digitalWrite(newCodeLED, ON);

        if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          //Proceed
          STATE = TWO;
        }

        else if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case TWO:
      {
        digitalWrite(newCodeLED, OFF);
        if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          //Proceed
          STATE = THREE;
        }

        else if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case THREE:
      {
        if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          //Proceed
          STATE = FOUR;
        }

        else if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case FOUR:
      {
        if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          //Proceed with unlocking the device
          STATE = FIVE;
        }

        else if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case FIVE:
      {
        //Unlock the device
        digitalWrite(unLockedLED, ON);
        
        //Proceed
        STATE = SIX;

      }
      break;

    //****************
    case SIX:
      {
        //Should we lock the device
        if (readSwitch(switch1, lastSwitch1) || readSwitch(switch2, lastSwitch2)
            || readSwitch(switch3, lastSwitch3))
        {
          //Proceed
          STATE = ZERO;
        }

      }
      break;

    //****************
    case FAILED:
      {
        digitalWrite(newCodeLED, OFF);

        if (pushedCounter >= 4)
        {
          failedMillis = millis();
          digitalWrite(failedLED, ON);

          //Proceed
          STATE = WAIT;
        }

        //We need 4 presses
        if (readSwitch(switch1, lastSwitch1) || readSwitch(switch2, lastSwitch2)
            || readSwitch(switch3, lastSwitch3))
        {
          pushedCounter++;
        }

      }
      break;

    //****************
    case WAIT:
      {
        if (millis() - failedMillis >= failedDelay)
        {
          digitalWrite(failedLED, OFF);

          //Proceed
          STATE = ZERO;
        }

        //NOTE! any switch press will reset the wait period.
        if (readSwitch(switch1, lastSwitch1) || readSwitch(switch2, lastSwitch2)
            || readSwitch(switch3, lastSwitch3))
        {
          //restart timer
          failedMillis = millis();
        }

      }
      break;

      //****************

  } //END of switch/case

} //END of              l o o p ( )

//***********************************************************


//                 r e a d S w i t c h ( )
//***********************************************************
//Return 'true' if the switch was released
bool readSwitch(byte button, byte & lastState)
{
  //****************
  //Handle switch de-bounce
  if (millis() - bounceMillis < bounceDelay)
  {
    //it is not time yet
    return false;
  }

  //reset timing
  bounceMillis = millis();

  //****************
  byte currentState = digitalRead(button);

  if (currentState == lastState)
  {
    //there was no change
    return false;
  }

  //get eady for the next switch test
  lastState = currentState;

  //****************
  if (currentState == Released)
  {
    //the button was just released
    digitalWrite(keyPushedLED, OFF);
    
    return true;
  }

  //****************
  //the button was just pressed
  digitalWrite(keyPushedLED, ON);
  
  return false;

} //END of          r e a d S w i t c h ( )


//***********************************************************
//                 E N D   o f   S k e t c h
//***********************************************************

Hello LarryD I removed the KeyPress case from my states.

This time the breadboard responds better when i enter the correct password and also the failed password.

Sometimes it behaves in a weird way:

Lets say I now run the code. Now I am in Ready state and the Ready LED is ON. The system waits for me to pressed a key to go to case ONE. Okay, now instead of writing the correct password which is {2,3,1,2}, I keep pressing {2,2,2,2,2,2,2...} bunch of times. After that I enter the correct password {2,3,1,2} and the system would not go to Open case and turn ON the OpenLED light. Instead it would be stuck in case ONE. After couple of tries of pushing correct password then suddenly, out of the blue, the OpenLED turns ON.

When case KeyPress is removed and now i have those cases below:

enum MyState {Ready, ONE, TWO, THREE, FOUR, Open, Fail}; //Putting all the possible cases.
MyState STATE = Ready; // Initial State = case Ready.

The code runs even better with less mistakes than before. But still sometimes i get the error mentioned above.

I have some questions.

  1. Why did you use pushedCounter++; in the code you just sent? I see no use of it. I don't know i am a beginner, but i noticed that it does not do anything.

  2. Why do you have the below stuff. I was not able to comprehend their use:

const unsigned long HeartBeatDelay = 500ul; //500ms
unsigned long HeartBeatMillis;

unsigned long bounceMillis;
const unsigned long bounceDelay = 10ul; //10ms

unsigned long failedMillis;
unsigned long failedDelay = 10 * 1000ul; //10 seconds

  1. why do you have [bounceMillis = millis();] in the void setup()?

Thank you for helping me make a good progress on this LarryD. Without help I would have been stuck for a long time in syntax errors.

I attached the updated version.

Lock.ino (7.04 KB)

If you look at the code posted in #25, you see pushedCounter is used to limit 4 switch presses before there is a 'unlock' or a 'fail' condtion.
You need the counter to prevent what you are experiencing, stuff like 2,2,2,2,2,2,2,2,2,. . . .

HeartBeat gives you a visual indication if the program is locked up or the code is blocking.
As long as you see the LED on pin 13 flashing, you have a good indication the code is cycling as it should.
Stuff like delay() stops code execution for the delay amount of time.
You should always 'avoid' using delay().

Every switch bounces a few times when it first closes or opens.
This bounce can cause weird problems as pushing a switch once can actually result in the program thinking it was pushed several times.
The bounce section of code ignores the bouncing that switches exhibit.

The 'failed' section of code uses failedMillis to determine if the 10 second period has expired.
It is important that all code be written so it is non-blocking.
In this case, any switch press during the 10 seconds can still be detected.
If you use delay(10000); you would not be able to do anything until the time is up.

setup() is part of the start sequence of your code.
You put things in setup that require initialization.
bounceMillis = millis(); initializes the bounceMillis variable with the current time found in the millis() function.
You should always initialize your variables.

.

Study the 'Blink Without Delay' example in the IDE.
This code times events without using the blocking function delay().

For further study, see Robin2's great discussion:
http://forum.arduino.cc/index.php?topic=223286.0

Something to watch:

Only 'very' simple code should use delay().
Even then, you must be aware of 'delays' ramifications.

.

Try this code with your hardware, use 1233 as the switch sequence:

// This demonstrates how to code a simple electronic lock
// using 3 switches wired as below.
// Arduino pin-----SwitchPin1-----SwitchPin2-----GND
// Switch pressed = LOW, released = HIGH
// LarryD
// Version 1.00 16/11/12  code = 1233
//         1.01 17/08/05  added: switch de-bouncing, heartBeatLED stuff
//         1.02 17/08/07  added the following: 
//                        - keyPushedLED, ON when a switch is pushed
//                        - newCodeLED, ON when ready for new code
//                        - failedLED, On if the wrong code is entered
//
//We have 3 switches. If the newCodeLED is on, we are allowed 4 switch presses to open the lock. 
//Any wrong 4 presses will freeze the program for 10 seconds. 
//While frozen any further presses will start the 10 second period over again.
//Four correct presses will turn on the unLockedLED, any further presses will turn off the unLockedLED.
//Each time a switch is pressed the keyPressedLED comes on. 
//


//****************
#define OFF      HIGH
#define ON       LOW
#define Pressed  LOW
#define Released HIGH

//****************
const byte unLockedLED  = 41;
const byte keyPushedLED = 39;
const byte failedLED    = 43;
const byte newCodeLED   = 37;
const byte switch1      = 26;
const byte switch2      = 24;
const byte switch3      = 22;
const byte HeartBeatLED = 13;

//****************
byte lastSwitch1        = Released;
byte lastSwitch2        = Released;
byte lastSwitch3        = Released;
byte pushedCounter      = 0;

//****************
//Timing stuff
const unsigned long HeartBeatDelay = 500ul;       //500ms
unsigned long HeartBeatMillis;

unsigned long bounceMillis;
const unsigned long bounceDelay    = 10ul;        //10ms

unsigned long failedMillis;
unsigned long failedDelay          = 10 * 1000ul; //10 seconds

//****************
enum MachineStates {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, FAILED, WAIT};
MachineStates STATE = ZERO;

//OR
//enum MachineStates {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, FAILED, WAIT} STATE = ZERO;



//                      s e t u  p ( )
//***********************************************************
void setup()
{
  pinMode(switch1, INPUT_PULLUP);
  pinMode(switch2, INPUT_PULLUP);
  pinMode(switch3, INPUT_PULLUP);

  pinMode(unLockedLED, OUTPUT);
  digitalWrite(unLockedLED, OFF);
  
  pinMode(keyPushedLED, OUTPUT);
  digitalWrite( keyPushedLED, OFF);
  
  pinMode(newCodeLED, OUTPUT);
  digitalWrite(newCodeLED, OFF);
  
  pinMode(failedLED, OUTPUT);
  digitalWrite(failedLED, OFF);
  
  pinMode(HeartBeatLED, OUTPUT);

  bounceMillis = millis();

} //END of             s e t u  p ( )


//                      l o o p ( )
//***********************************************************
void loop()
{
  //****************
  //helps check for blocking code
  if (millis() - HeartBeatMillis >= HeartBeatDelay)
  {
    //reset timing
    HeartBeatMillis = millis();
    //toggle the HeartBeatLED
    digitalWrite(HeartBeatLED , !digitalRead(HeartBeatLED));
  }

  //****************
  switch (STATE)
  {
    case ZERO:
      {
        //Lock the device
        digitalWrite(unLockedLED, OFF);
        digitalWrite(newCodeLED, OFF);
        pushedCounter = 0;

        //Proceed
        STATE = ONE;

      }
      break;

    //****************
    case ONE:
      {
        digitalWrite(newCodeLED, ON);

        if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          //Proceed
          STATE = TWO;
        }

        else if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case TWO:
      {
        digitalWrite(newCodeLED, OFF);
        if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          //Proceed
          STATE = THREE;
        }

        else if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case THREE:
      {
        if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          //Proceed
          STATE = FOUR;
        }

        else if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case FOUR:
      {
        if (readSwitch(switch3, lastSwitch3) == true)
        {
          pushedCounter++;
          
          //Proceed with unlocking the device
          STATE = FIVE;
        }

        else if (readSwitch(switch1, lastSwitch1) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

        else if (readSwitch(switch2, lastSwitch2) == true)
        {
          pushedCounter++;
          
          STATE = FAILED;
        }

      }
      break;

    //****************
    case FIVE:
      {
        //Unlock the device
        digitalWrite(unLockedLED, ON);
        
        //Proceed
        STATE = SIX;

      }
      break;

    //****************
    case SIX:
      {
        //Should we lock the device
        if (readSwitch(switch1, lastSwitch1) || readSwitch(switch2, lastSwitch2)
            || readSwitch(switch3, lastSwitch3))
        {
          //Proceed
          STATE = ZERO;
        }

      }
      break;

    //****************
    case FAILED:
      {
        digitalWrite(newCodeLED, OFF);

        if (pushedCounter >= 4)
        {
          failedMillis = millis();
          digitalWrite(failedLED, ON);

          //Proceed
          STATE = WAIT;
        }

        //We need 4 presses
        if (readSwitch(switch1, lastSwitch1) || readSwitch(switch2, lastSwitch2)
            || readSwitch(switch3, lastSwitch3))
        {
          pushedCounter++;
        }

      }
      break;

    //****************
    case WAIT:
      {
        if (millis() - failedMillis >= failedDelay)
        {
          digitalWrite(failedLED, OFF);

          //Proceed
          STATE = ZERO;
        }

        //NOTE! any switch press will reset the wait period.
        if (readSwitch(switch1, lastSwitch1) || readSwitch(switch2, lastSwitch2)
            || readSwitch(switch3, lastSwitch3))
        {
          //restart timer
          failedMillis = millis();
        }

      }
      break;

      //****************

  } //END of switch/case

} //END of              l o o p ( )

//***********************************************************


//                 r e a d S w i t c h ( )
//***********************************************************
//Return 'true' if the switch was released
bool readSwitch(byte button, byte & lastState)
{
  //****************
  //Handle switch de-bounce
  if (millis() - bounceMillis < bounceDelay)
  {
    //it is not time yet
    return false;
  }

  //reset timing
  bounceMillis = millis();

  //****************
  byte currentState = digitalRead(button);

  if (currentState == lastState)
  {
    //there was no change
    return false;
  }

  //get eady for the next switch test
  lastState = currentState;

  //****************
  if (currentState == Released)
  {
    //the button was just released
    digitalWrite(keyPushedLED, OFF);
    
    return true;
  }

  //****************
  //the button was just pressed
  digitalWrite(keyPushedLED, ON);
  
  return false;

} //END of          r e a d S w i t c h ( )


//***********************************************************
//                 E N D   o f   S k e t c h
//***********************************************************

Thank you for the helpful resources LarryD.

I started reading your code and it worked perfectly on my breadboard. Then i wanted to make changes to my code to make it similar to yours. I wanted to make my code 100% error free. Anyway I was reading your code and constantly changing some stuff on my code. That did not work well for me at the beginning. I was trying to copy bits and pieces here and their and was not patient enough to read the whole code. Then after 5 hours of trying and failing. I made my code worse than before. Things wouldn't make sense. Lights would turn ON and OFF on my breadboard without any good reason.

After that i took a long break and did the same thing. Still, I was not patient to read the whole code first. Because of that i got the same headache i got five hours ago.I then decided to read the whole code. I mean I did not have any other choice. After spending time in reading your code everything started to make sense. The boolean function at the bottom of the code is the main important thing. That function form is similar to building Matlab functions. The SwitchWithOutDelay Example was another great and simple code to understand. Now, I know why i should not use Delay(); cuz I want my code to run the whole time and my whole functions to get executed at the same time without interruption.

I still need to watch the youtube video and read Robin2's great discussion, which you posted. I need to rest my brain a little bit and tomorrow morning I can finish those two stuff.

Thank you for all of the valuable information LarryD. Every information you posted was helpful. Thank you.

BTW
Always, always, always make backups before making changes.
If things do not work, you will be able to retrace to a point where things worked.

There is nothing wrong with having 10+ versions of the code.
After things are finalized, you can delete the old versions.

Congratulations, you are a programmer now!
Headache, don't get dehydrated, drink lots of water :wink:

Ask questions if you have any.

Sleep time here :sleeping:
.