Skip to content

April 7, 2013

1

Keypad Security Door Lock

I just finished my Keypad Security Lock project a week or so ago, which I’ve been working on and off with a break in the middle for the past few weeks now. Held together with sticky pads and hookup wire, I present my latest creation:

(excuse the shoddy camera angles, it’s tricky to hold the camera and type when the keypad is on the other side of the door!)

Components:
ATmega 328P
Strip board
ABS housing
Full rotation servo (why did I get a full rotation one…)
Reed switch and magnet pair (to accommodate for the decision above)
3×4 matrixed keypad
240v -> 0.7A 5v mains transformer
ribbon cable, hookup wire, resistors, etc.


So, the software side is actually pretty straightforward. I’m using a matrix keypad, so I just use a scanning method to set the columns high, and check if any input is high, and infer which key is pressed depending on which output/input pair is high. You can see that in the source code
Beyond that, it’s just some PWM to change the speed and direction of the servo, an array to store the password, a bit of serial debugging using a serial class I made for an earlier project, and some reed switch feedback.
The overall program is essentially “check the sequence of input buttons is correct, if so turn the servo for 170ms” while it’s unlocked and “do the same but only turn the servo the other way until the reed switch is active, then stop” when it’s in the locked state. I do plan to add on-the-fly password changing so when my housemates figure out the password I can change it without taking it apart. But I have to take it apart to add that feature because I didn’t make a programming port!

The hardware side was an absolute pain. The ABS box needed to house the servo, so I had to cut out a hole using just a strip board track cutter because I left all my tools at home (I’m currently at my house at Uni). I ended up cutting a rough rectangle by making numerous holes, then sanding it down to make it look acceptable. The hardest part was hooking up to the pre-existing lock, which I could not modify because I’m renting this house and didn’t really want to fix it back up when I moved out/got tired of this lock. So, I opted for hookup wire (I know…) and looped it around the grub screw on the shaft of the lock. It actually worked surprisingly well, and I could thread it through the servos arm holes. On top of this, I needed to ensure the lock didn’t turn too much (because the lock eventually goes over a “click” which requires too much force than the servo can handle to go back over), and that the servo could turn the lock enough wherever it was positioned. Oh and the reed switch needed to be positioned enough so that the timed reversal/unlocking of the door was just right (trial and error!). I really should have bought a standard 270 degrees servo, so I could choose the angle and not have to worry about feedback.
Surprisingly, the switches were happy without debouncing. Perhaps that’s done in the keypad, it isn’t really specified in the datasheet.

All the components were purchased from Rapid Online. I’d recommend them.

Source code (warning, very rushed and messy):


/*

 * KeypadSerial.cpp

 *

 * Created: 28/02/2013 01:46:59

 *

 */ 



#define F_CPU 16000000UL

#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)


#define CODELEN 4
#define SFW 50
#define SBW 400

#include <avr/io.h>
#include <util/delay.h>
#include <stdarg.h>
#include <stdio.h>
#include "serial.h"


int code[] = {1, 2, 3, 4};
int input[CODELEN];
int curnum = 0;
bool locked = false;


void ServoSpeed(int speed)
{
	if (speed == 0)
	{
		set_input(DDRB, PB1);	//lazy way, make the pin an input
		return;
	}

	set_output(DDRB, PB1);
	OCR1A = speed;
	return;
}



void ServoInit()
{
	//Configure TIMER1
	TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);        //non-inverted PWM
	TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10); //prescaler = 64, mode = fast PWM

	ICR1=4999;  //FPWM=50Hz (period = 20ms)

	DDRB |= (1<<PB1);   //make the PWM pin an output
	ServoSpeed(0);

}

void Unlock()
{
	ServoSpeed(SBW);
        //wait until the reed is triggered,
        //indicating the lock is at the home position
	while ( !(PINC & (1<<PC4)) );
	ServoSpeed(0);
}


void Lock()
{
	ServoSpeed(SFW);
	_delay_ms(180);
	ServoSpeed(0);
}



int GetKeypad(void)

{
	//reset the columns (just in case)
	output_low(PORTD, PD6);
	output_low(PORTD, PD7);
	output_low(PORTB, PB0);

	output_high(PORTD, PD6);	//set column 1 high

	_delay_ms(1);				//wait for this to fully take effect

	if (PINC & (1<<PC5))
	{
		return 10;
	}
	else if(PINC & (1<<PC3))
	{
		return 4;
	}
	else if (PINC & (1<<PC2))
	{
		return 7;
	}
	else if (PINC & (1<<PC1))
	{
		return 1;
	}

	output_low(PORTD, PD6);		//set column 1 low
	output_high(PORTD, PD7);	//set col 2 high

	_delay_ms(1);				//wait for this to take effect

	if (PINC & (1<<PC5))
	{
		return 0;
	}
	else if(PINC & (1<<PC3))
	{
		return 5;
	}
	else if (PINC & (1<<PC2))
	{
		return 8;
	}
	else if (PINC & (1<<PC1))
	{
		return 2;
	}
	

	output_low(PORTD, PD7);		//set col 2 low

	output_high(PORTB, PB0);	//set col 3 high

	_delay_ms(1);				//wait for this to take effect

	if (PINC & (1<<PC5))
	{
		return 11;
	}
	else if(PINC & (1<<PC3))
	{
		return 6;
	}
	else if (PINC & (1<<PC2))
	{
		return 9;
	}
	else if (PINC & (1<<PC1))
	{
		return 3;
	}

	output_low(PORTB, PB0);

	return -1;
}



void CheckCode(int input)
{
	if (input == code[curnum])
	{
		curnum++;
		if (curnum >= CODELEN)
		{
			//unlock
			if (locked)
			{
				Unlock();
				locked = false;
				Serial::WriteString("Unlocked!");
			}
			else
			{
				Lock();
				locked = true;
				Serial::WriteString("Locked!");
			}
			curnum = 0;
		}
	}
	else
	{
		curnum = 0;
		Serial::WriteString("Password failed");
	}
}

int main(void)
{

	DDRD |= 0xFF;		//set PORT D to output mode
	DDRB |= 0xFF;		//set PORT B to output mode
	DDRC &= ~(0xFF);	//set PORT C to input mode
	//TCCR1B |= (1 << WGM12);
	ServoInit();
	Serial::Init();
	Serial::WriteString("Initialized\n\r");
	while(1)
	{
		int keypressed = GetKeypad();
		if (keypressed != -1)
		{
			while (GetKeypad() == keypressed);	//hold while the button is pressed
		}

		if (keypressed != -1)
		{
			CheckCode(keypressed);
		}
	}
}
0+
Read more from Electronics, Programming

Share your thoughts, post a comment.

(required)
(required)

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

Fork me on GitHub