HOME - - - - - - - - Table of contents, my Arduino "How To" articles
Other material for programmers      Delicious Bookmark this on Delicious   Recommend to StumbleUpon

Simple Arduino Lock

with scope for embellishment

A "tutorial" in "project" clothing... ("wolf in sheep's"? Sorry.)

On this page I will tell you how to build an electronic "lock". You press some buttons, and if you press the right buttons, and output goes high for a period.

In a typical use for this code, you would put the buttons outside a locked door, and have an electronically operated strikeplate driven from the output on the inside. Press buttons. Door becomes unlocked. Re-locks after a suitable interval.

Slight rearrangements, and/ or slight modifications to the code... it should be easy... make this the basis for other things. It could, for instance, give a parent a way to turn a child's bedroom TV on for just a half hour... not, I hope, that we are going into a world where parents use electronic locks rather than simple (maybe "basic" would be a better word here!) authority to limit TV time.

This really ought to be a tutorial... but I haven't the energy just now. In any case, the "product" of the not-written tutorial makes a perfectly usable real world device, so here it is.

Details.... hardware

As implemented, the lock has three buttons, labeled "A", "C", and "E". (This is just a coincidence arising from the actual buttons I used in developing the code. Label them as you wish... but the variable names in the program are chosen to match the labels on the buttons I had.)

Each button is just a momentary switch which can pull one of the Arduino's input lines low. (You can see which is on what pin from the code, I hope!) I used the Arduino's internal pull up resistors to avoid floating inputs.

I used an LED on D13 to stand for the "lock". I call the lock "locked" when the LED is off. Whether a high or a low on the output makes the LED on or off depends how you wire it... we don't all have LEDs on our Arduino clones... but the program was written so that it is easy to change things around. (Subroutines LockIt and Unlock are the only place you need to make changes, if your LED/ lock is wired differently.) In a real world use of this code, you would want to think carefully about which was best for your needs: output high locking door, or output low locking it? Remember: Power sometimes fail. Will the door be the way you want it when the power fails?

Details.... using the installed system

To gain access, you have to press the following keys on the keyboard: A E C E

When you've pressed those keys, in that order, the "lock" "opens" for one second, and then re-locks.

You simply change the "1000" in the "loop" procedure to change how long the lock is unlocked. You could even, quite easily, change the program so that entering the code once unlocked the door, and entering it againunlocked it.

If you "go wrong" while entering the code, it doesn't matter. You can start again at any time, and the door will unlock if the last 4 keys you pressed were A E C E.

You could quite easily revise the code so that if someone entered a wrong code, a short delay would start, during which another attempt would be ignored. An "I'm ignoring all input" LED would probably be a good idea in such an extension. And the "ignore you" time could increase... logarithmically, if you chose, in the event of multiple failed attempts to enter.

You can change the code that opens the lock... just change what is put in SecretMessage at the start of the program. But! The first letter must be an A, and A may not be used again. The rest of the letters must not have any immediate repeats, so ACEC is okay, ACCE is not.

You can change the number of letters in the code.... just change CodeLength

You can have more than 3 buttons... just add lines similar to...

int InAPin=2;  //Pin with "A" button on it.

digitalWrite(InAPin,HIGH); //"Connect" internal pull up resistor

if (digitalRead(InAPin)==LOW) Tmp='A';

Enough features??


The Code

Here's the code that implements the access control system.

Often when you work with momentary switches as inputs, all sorts of problems arise over issues of "processor blocking" and "switch bounce". The following program isn't bothered about either issue... although it does lack "n-key rollover", but so does the commercial alarm system on my home. How many people even know what that is? And of those, how many care?

The program is deceptively simple.... really. More on that after the code....

/*
 * Locb11
   ver 5Jan2010
 *
 * A simple keyboard lock
 * example, with steps taken to make bounce irrelevant
 *
 * Sheepdogsoftware.co.uk
 */

int LockPin=13;    // Pin controlling "lock"
int InAPin=2;  //Pin with "A" button on it.
int InCPin=3;   //with "C"... pull low when button pressed
int InEPin=4;    //with "E"

#define CodeLength 4 //no ; here. Can't use "int" because using in
  //next line to define length of SecretMessage array
char SecretMessage[CodeLength+1]="AECE"; //+1 for... um. But it works.
int PlaceInCode=0;
char PresentChar='Z';
char PrevChar='Z';


void setup()                    // run once, when the sketch startspinMode(LockPin, OUTPUT);      // sets the digital pin as output

  // pins for A, B, C all inputs, by default
digitalWrite(InAPin,HIGH); //"Connect" internal pull up resistor
digitalWrite(InCPin,HIGH);
digitalWrite(InEPin,HIGH);
}

void loop()                     // run over and over again
{ LockIt();
  PresentChar=ReadKeybd();

//Next is "first if"
  if ((PlaceInCode>0) && (PresentChar=='A'))
  {
   PlaceInCode=0;
   PrevChar='A';
  }//end of first if

//Next allows bounces to pass, etc...
//This is "2nd if"
if ((PlaceInCode>0) &&
    (PresentChar!='Z') &&
    (PresentChar!=PrevChar))
       {
         PrevChar=PresentChar;
         PlaceInCode++;
         if (WrongKey()==true)
           {PlaceInCode=0;}
            else
           {  if (PlaceInCode==CodeLength)
                {
                  Unlock();
                  delay(1000); //Will re-lock at start of loop
                }//end of "if PlaceInCode..."
           }//end of "else" block 
       }//end of 2nd if
       
//Next is "3rd if"
if (PlaceInCode==0)
  {
    if (PresentChar=='A')
      {
        PlaceInCode=1;
        PrevChar='A';
      }
  }//end of 3rd if

}

void Unlock()
{
digitalWrite(LockPin,HIGH);   // sets the LED on, in mock up. On=unlocked  
}

void LockIt()
{
digitalWrite(LockPin,LOW);   // sets the LED off. See "Unlock"
}

char ReadKeybd()
{ char Tmp='Z';
  if (digitalRead(InAPin)==LOW) Tmp='A';
  if (digitalRead(InCPin)==LOW) Tmp='C';
  if (digitalRead(InEPin)==LOW) Tmp='E';
  return Tmp;
}

boolean WrongKey()
{ if (SecretMessage[PlaceInCode]==PresentChar)
    {return true;}
    else
    {return false;};
}

Discussion of program

In the "setup" procedure, apart from the statements taking care of setting pin usage, and "connecting" the internal pull ups, we have...

int PlaceInCode=0;
char PresentChar='Z';
char PrevChar='Z';

The variable PlaceInCode counts how far through the door opening code we've advanced at the moment.

At this point, other the names aren't 100% sensible, but PresentChar holds the letter, if any, we've just read from the buttons, or 'Z' if there was no button pressed when we looked. As we haven't looked yet, it is okay to initialize PresentChar with 'Z'; PrevChar holds the character we read the last time we succeeded in reading something. As we haven't read anything yet, 'Z' is right again.

In the program's main loop, the door is (re) locked at the beginning of each pass through the loop.... many times each second, in other words.

And then it looks at the pins connected to the buttons, and fills "PresentChar" with a letter depending on what key is pressed, or a 'Z', if no key is pressed.

Then there are just three simple "ifs". The order those ifs arise is important, as are the three rules about what "codes" are allowed to open the door....

Without those simple rules, the program for a keypad operated lock becomes a pain to write.

So... the three "ifs"

The first "if" is saying "If the user has already made some progress towards entering the code, and enters a second 'A', start going back to "square one". (That "going back" will be completed during the 3rd "if")

The second "if" is the most troublesome... but you skip over it most of the time.

You don't do it if you're still just starting, in other words if you are entering the "A"

You don't do it if the "PresentChar" is 'Z', i.e., at the last check, no key was pressed.

And you don't do it if ReadKeybd "saw" again the key it saw previously.

However! If you have had an 'A' already, and the present key isn't a 'Z', and it is new, it is time to look closely at the new input from the user. If the wrong key was pressed, merely setting PlaceInCode back to zero is all it takes... given the rest of the program... to send us back to the beginning. If the right key is pressed, we add one to what's in PlaceInCode ("PlaceInCode++;"). If we've had enough letters, we open the lock, and wait a bit ("delay(1000)") before going on, as almost as soon as we go on, the door will be re-locked.

And then there's the third "if". This takes care of the special case which arises when we are starting through the code.

(At the back of my mind, there's a little suspicion that this code can be even simpler... but it is simple enough for me now, and I can understand it. Very clever, highly optimized code can sometimes be so clever that I can't follow it all. And if I can't follow it, I can't (safely) adapt it for other needs.


So! There you have it!

I hope you enjoyed that. I hope you found things in it interesting. Half of me hopes you tried to do the program for yourself before seeing the above... you'd be surprised at all the little "gotchas" I avoided (or, to be honest, wrung out of the early editions of this code!). But the other half of me is glad that you didn't have to endure reinventing that wheel.

As I said, believe that the above is easily modified. The first thing I will do, when I get time, is replace the three (or more) input buttons with a matrix keypad. Everything you need for that is in the Keypad library which is well explained in the Keypad tutorial in the Arduino Playground.

Umm. Challenge for the reader...

In April 2016, a Gentle Reader attempted something which seemed entirely reasonable: He added another button for users to press. He called it 'F'. With the extra button, it should have been possible to require users to press, say, ACFE to open the lock.

It didn't work right. He spent time. I spent time. (But didn't wire up the necessary bits to really struggle with the issue, I admit.)

It should have worked! Can YOU add an extra button or two?? While you're at it, can you also revise the code so that the "combination" to open the lock is 5 letters long? (Do one at a time! Either one can be your first challenge). Remember the constraints which were agreed: The first letter of the combination will always be 'A', and that is not used again in the combination. No letter is repeated at any time. I.e. ACEC is allowed, but not ACCE or ACAE. (The constraints make the programming much easier.)

The only consolation was that it seemed that the code was written in a way that made it easy to extend. But it is only good code in that respect if, after simple tweaks, the old code becomes a new version which works!

Your help in getting to the bottom of this would be much appreciated. Contact details below.





   Search this site or the web        powered by FreeFind
 
  Site search Web search
Site Map    What's New    Search

The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
In addition to the tutorials for which this page serves as Table of Contents, I have other sites with material you might find useful.....

Sequenced set of tutorials on Arduino programming and electronics interfacing.
Tutorials about the free database supplied with Open Office version 2.
      (If you experienced Adabas with Star Office, ooBase is nothing like it!)
Some pages for programmers.
Using the parallel port of a Windows computer.


If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service.




Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!

Click here to visit editor's Sheepdog Software (tm) freeware, shareware pages.


And if you liked that, or want different things, here are some more pages from the editor of these tutorials....

Click here to visit the homepage of my biggest site.

Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?FrmAht" I added to that link causes your browser problems. Please let me know, if so?

Click here to visit editor's pages about using computers in Sensing and Control, e.g. weather logging.



To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed!


Valid HTML 4.01 Transitional Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org


Why does this page cause a script to run? Because of the Google panels, and the code for the search button. Why do I mention the script? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....