Project – Single button combination lock
Hello Readers
Time for something different - a single button combination lock. Allow me to explain…
Normally a combination lock would require the entry of a series of unique numbers in order to unlock something or start an action. For example:
A more contemporary type of lock could be controlled electronically, for example by a keypad where the user enters a series of digits to cause something to happen. Such as the keypad on this dodgy $30 safe from Officeworks:
As you can see there is a button for each digit. You would think that this would be a good idea – however people can watch you enter the digits, or users can be silly enough to write down the combination somewhere. In some cases the more cunning monkeys have even placed cameras that can observe keypads to record people entering the combination. There must be a better way. Possibly! However in the meanwhile you can consider my idea instead – just have one button. Only one button – and the combination is made up of the time that elapses between presses of the button. There are many uses for such an odd lock:
- A type of combination lock that controls an electric door strike, or activates a device of some sort;
- A way of testing mind-hand coordination for skill, or the base of a painfully frustrating game;
- Perhaps an interlock on motor vehicle to prevent drink driving. After a few drinks there’s no way you could get the timing right. Then again, after a double espresso or two you might have problems as well.
We measure the duration of time between each press of the button (in this case – delay 1~4). These delay times are then compared against values stored in the program that controls the lock. It is also prudent to allow for some tolerance in the user’s press delay – say plus or minus ten to fifteen percent. We are not concerned with the duration of each button press, however it is certainly feasible.
To create this piece of hardware is quite easy, and once again we will use the Arduino way of doing things. For prototyping and experimenting it is simple enough to create with a typical board such as a Uno or Eleven and a solderless breadboard – however to create a final product you could minimise it by using a bare-bones solution (as described here).
For demonstration purposes we have a normally-open button connected to digital pin 2 on our Arduino-compatible board using the 10k ohm pull down resistor as such:
The next thing to do is determine our delay time values. Our example will use five presses, so we measure four delays. With the following sketch, you can generate the delay data by pushing the button yourself – the sketch will return the delay times on the serial monitor (download).
/*
Single-button combination lock
Delay Time data generation sketch
*/
int count=0;
unsigned long a[]={0,0,0,0,0,0};
unsigned long del[]={0,0,0,0,0};
void setup()
{
pinMode(2, INPUT);
Serial.begin(115200);
Serial.println("Ready...");
}
void dataCapture()
{
a[count]=millis();
delay(500); // for button debounce, your value may differ
count++;
}
void displayData()
{
// calcualate delays between keypresses
del[0]=a[1]-a[0];
del[1]=a[2]-a[1];
del[2]=a[3]-a[2];
del[3]=a[4]-a[3];
// display delay data for use in combination lock sketch
for (int a=0; a<4; a++)
{
Serial.println();
Serial.print("Delay ");
Serial.print(a);
Serial.print(" use ");
Serial.print(del[a]);
Serial.println(" ms");
}
Serial.println("- - - - - - - - -");
count=0;
}
void loop()
{
if (digitalRead(2)==HIGH)
{
dataCapture();
}
if (count>4)
{
displayData();
}
}So what’s going on the this sketch? Each time the button is pressed a reading of millis() is taken and stored in an array. [More on millis() in the tutorial]. Once the button has been pressed five times, the difference in time between each press is calculated and stored in the array del[]. Note the use of a 500 ms delay in the function dataCapture(), this is to prevent the button bouncing and will need to be altered to suit your particular button. Finally the delay data is then displayed on the serial monitor. For example:
The example was an attempt to count one second between each press. This example also illustrates the need to incorporate some tolerance in the actual lock sketch. With a tolerance of +/- 10% and delay values of one second, the lock would activate. With 5% – no. Etcetera.
Now for the lock sketch. Again it measures the millis() value on each button press and after five presses calculates the duration between each press. Finally in the function checkCombination() the durations are compared against the stored delay values (generated using the first sketch) which are stored in the array del[]. In our example lock sketch we have values of one second between each button press. The tolerance is stored as a decimal fraction in the variable tolerance; for example to have a tolerance of ten percent, use 0.1.
/*
Single-button combination lock
*/
int count=0;
unsigned long a[]={0,0,0,0,0};
unsigned long b[]={0,0,0,0,0};
unsigned long del[]={1000,1000,1000,1000}; // these are the values obtained from running combilock1.pde
// delay between each button press is 1000 ms
float tolerance=.2;
void setup()
{
pinMode(2, INPUT);
Serial.begin(115200); // for testing purposes
Serial.println("Start"); // for testing purposes
}
void dataCapture()
{
a[count]=millis();
delay(500); // for button debounce, your value may differ
count++;
}
void checkCombination()
{
int compare=0;
count=0;
// calcualate delays between keypresses
b[0]=a[1]-a[0];
b[1]=a[2]-a[1];
b[2]=a[3]-a[2];
b[3]=a[4]-a[3];
// compare the button delay values
if (b[0]<=(del[0]*(1+tolerance)) && b[0]>=(del[0]*(1-tolerance))) { compare++; }
if (b[1]<=(del[1]*(1+tolerance)) && b[1]>=(del[1]*(1-tolerance))) { compare++; }
if (b[2]<=(del[2]*(1+tolerance)) && b[2]>=(del[2]*(1-tolerance))) { compare++; }
if (b[3]<=(del[3]*(1+tolerance)) && b[3]>=(del[3]*(1-tolerance))) { compare++; }
if (compare==4) { success(); }
if (compare!=4) { failure(); }
}
void success()
{
// contains code to run when combination successfully entered
Serial.println("Success!");
delay(5000);
Serial.println("- - - - -");
}
void failure()
{
// contains code to run when combination unsuccessfully entered
Serial.println("Failure!");
delay(5000);
Serial.println("- - - - -");
}
void loop()
{
if (digitalRead(2)==HIGH)
{
dataCapture();
}
if (count>4)
{
checkCombination();
}
}When choosing your time delays, ensure they are larger than the value used for button debounce (the delay() function call) in the dataCapture() function. Notice the two functions success() and failure() – these will contain the results of what happens when the user successfully enters the combination or does not.
If you are looking to control various types of circuitry or devices with this sketch, you may find the following of interest:
- To control relays to switch higher voltages or current, see this tutorial;
- To control circuitry that needs to be electrically isolated, see this about the theory of optocouplers, and some examples in use;
- To control some simple LEDs, perhaps revisit this tutorial;
- An example of an electric door strike can be found here.
Although there are four buttons on the board used in the video, only one is used. The board is a generic ‘button board‘ whose purpose is to make using buttons easier when prototyping.
As always, now it is up to you and your imagination to find something to control or get up to other shenanigans. If you have any suggestions with regards to our next article, leave a comment below and we’ll look into it. Furthermore, don’t be shy in pointing out errors or places that could use improvement. Why not follow us on twitter and facebook to keep up with new articles, news and other items of interest. Otherwise, have fun, stay safe, be good to each other – and make something!



