Microcontroller based Electronic Lock from Priyank Bolia on Vimeo.
/*----------------------------------------------------------------
-------------------------- HEADER FILES --------------------------
-----------------------------------------------------------------*/
#include <avr/io.h>
#include <string.h>
#include <avr/interrupt.h>
#include <util/delay.h>
/*----------------------------------------------------------------
------------------- DEFINITIONS ----------------------------------
-----------------------------------------------------------------*/
#define DATA_DDR DDRA // ENTER THE PORT WHICH CONTROLS
#define DATA_PORT PORTA // THE DATA PINS D0 TO D7
#define CONTROL_DDR DDRD // ENTER THE PORT WHICH CONTROLS
#define CONTROL_PORT PORTD // THE CONTROL PINS
#define Enable 2 // CoNNECTION OF ENABLE TO PIN OF ABOVE PORT
#define RS 0 // CoNNECTION OF RegisterSelect TO PIN OF ABOVE PORT
#define RW 1 // CoNNECTION OF Read/~Write TO PIN OF ABOVE PORT
#define CONTROL_MASK 0X07 // CHANGE THIS VALUE CONSIDERING THE PINS ABOVE AS HIGH
#define KB_PORT_OUT PORTB //Keypad Port
#define KB_PORT_DDR DDRB //Data Direction Register
#define KB_PORT_IN PINB //Keypad Port Pins
#define col1 PB0 //Column1 PortA.0
#define col2 PB1 //Column2 PortA.1
#define col3 PB2 //Column3 PortA.2
#define col4 PB3 //Column4 PortA.3
#define TRUE 1
#define FALSE 0
/*----------------------------------------------------------------
----------------------CONTROL BITS OF LCD ------------------------
-----------------------------------------------------------------*/
#define Set_Enable CONTROL_PORT |=_BV(Enable) // THE MACROS HERE ARE
#define Clear_Enable CONTROL_PORT &=~_BV(Enable) // SELF EXPLANATORY
#define Write_Lcd CONTROL_PORT &=~_BV(RW) //
#define Read_Lcd CONTROL_PORT |=_BV(RW) //
#define Select_InstructionRegister CONTROL_PORT &=~_BV(RS) //
#define Select_DataRegister CONTROL_PORT |=_BV(RS) //
#define Data_Lcd(b) DATA_PORT=b //
#define delay(b) _delay_ms(b) //
/*----------------------------------------------------------------
----------------------FUNCTION DECLARATIONS ----------------------
-----------------------------------------------------------------*/
void Init_Ports(void); // Initialize Ports, for selecting input output pins in the MCU
void Init_Lcd(void); // Initialize LCD, for starting and clearing LCD screen
void Lcd_Send(unsigned char a);// For sending a character to the LCD
void GotoNextLine(void); // For printing characters on the next line in the LCD
void GotoFirstLine(void); // For printing characters on the first line in the LCD
void ClearDisplay(void); // For clearing LCD
void key_init();
unsigned char get_key();
/*----------------------------------------------------------------
----------------------MAIN FUNCTION-------------------------------
-----------------------------------------------------------------*/
int main()
{
int len,len1,len2,len3,len4,len5,len6;
char str1[] = "Welcome Priyank!"; // String to be printed in 1st line
char str2[] = "Enter PIN: "; // String to be printed in 2st line
char str3[] = "This is invalid"; // String to be printed in 1st line
char str4[] = "PIN, try again."; // String to be printed in 2nd line
char str5[] = "Welcome Home!"; // String to be printed in 1st line
char str6[] = "Have a nice day."; // String to be printed in 2nd line
unsigned char keyval; //A variable
len1=strlen(str1);
len2=strlen(str2);
len3=strlen(str3);
len4=strlen(str4);
len5=strlen(str5);
len6=strlen(str6);
Init_Ports();
Init_Lcd();
key_init();
while(1)
{
for (len=0;len<len1;len++) // Printing the first string
Lcd_Send(str1[len]);
GotoNextLine(); // Go to new line
for (len=0;len<len2;len++) // Printing the 2nd string
Lcd_Send(str2[len]);
int index = 0;
unsigned char PIN[4];
while(index < 4)
{
keyval = get_key();
if(keyval != 'X')
{
PIN[index] = keyval;
Lcd_Send('*');
index++;
}
}
if(PIN[0] == '1' && PIN[1] == '5' && PIN[2] == '7' && PIN[3] == 'F')
break;
ClearDisplay(); // Go to new line
for (len=0;len<len3;len++) // Printing the first string
Lcd_Send(str3[len]);
GotoNextLine(); // Go to new line
for (len=0;len<len4;len++) // Printing the 2nd string
Lcd_Send(str4[len]);
delay(1000);
ClearDisplay(); // Go to new line
}
ClearDisplay(); // Go to new line
for (len=0;len<len5;len++) // Printing the first string
Lcd_Send(str5[len]);
GotoNextLine(); // Go to new line
for (len=0;len<len6;len++) // Printing the 2nd string
Lcd_Send(str6[len]);
DDRC = 0xFF; //Key-board port, higher nibble - input, lower nibble - output
PORTC = 0xFF; //pull-up enabled for higher nibble
}
/*----------------------------------------------------------------
------------------SEND A CHARACTER TO LCD-------------------------
-----------------------------------------------------------------*/
void Lcd_Send(unsigned char a)
{
Select_DataRegister; // Declares information that follows as data and not instruction
Write_Lcd; // Declared information is to be written
Data_Lcd(a); // Send the character passed to the function to LCD to write
Set_Enable; // Sets enable,
delay(5); // and then
Clear_Enable; // Clears it,
delay(5); // to be ready for next character.
}
/*----------------------------------------------------------------
-----------------FUNCTIONS TO INITIALIZE PORTS--------------------
-----------------------------------------------------------------*/
void Init_Ports(void)
{
DATA_DDR=0XFF; // Setting data port for output
CONTROL_DDR=CONTROL_MASK; // Setting selected pins of control port for output
CONTROL_PORT&=~(_BV(Enable)|_BV(RS )|_BV(RW)); // Setting values to 0 at start
}
/*----------------------------------------------------------------
-------------------FUNCTION TO INITIATE LCD ----------------------
-----------------------------------------------------------------*/
void Init_Lcd(void)
{
char init[10];
int i;
init[0] = 0x01; // Initializes the display
init[1] = 0x38; // 8 - Bit Operation, 2 Line Display,5*8 Dot Character Font
init[2] = 0x0e; // Turns on display and cursor
init[3] = 0x06; // Entry Mode Set
init[4] = 0x80; // Sets DDRAM address to beginning of screen
Select_InstructionRegister;
Write_Lcd;
delay(15);
for(i=0;i<5;i++)
{
Data_Lcd(init[i]);
Set_Enable;
delay(5);
Clear_Enable;
delay(5);
}
}
/*----------------------------------------------------------------
-------------FUNCTION TO GOTO NEXT LINE IN LCD -------------------
-----------------------------------------------------------------*/
void GotoNextLine(void)
{
delay(5);
Select_InstructionRegister; // Declares information to follow as instruction
Data_Lcd(0xc0); // Code to go to next line of LCD
Set_Enable; // -- Enable cycle --
delay(5); // | |
Clear_Enable; // | |
delay(5); // -- --
}
/*----------------------------------------------------------------
----------------FUNCTION TO FIRST LINE IN LCD --------------------
-----------------------------------------------------------------*/
void GotoFirstLine(void)
{
delay(5);
Select_InstructionRegister; // Declares information to follow as instruction
Data_Lcd(0x80); // Code to go to next line of LCD
Set_Enable; // -- Enable cycle --
delay(5); // | |
Clear_Enable; // | |
delay(5); // -- --
}
/*----------------------------------------------------------------
------------------FUNCTION TO CLEAR LCD --------------------------
-----------------------------------------------------------------*/
void ClearDisplay(void)
{
delay(5);
Select_InstructionRegister; // Declares information to follow as instruction
Data_Lcd(0x01); // Code to go to next line of LCD
Set_Enable; // -- Enable cycle --
delay(5); // | |
Clear_Enable; // | |
delay(5); // -- --
}
void key_init(){
KB_PORT_DDR = 0x0F;
KB_PORT_OUT = 0xFF;
//stop errant interrupts until set up
cli(); //disable all interrupts
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}
unsigned char get_key(){
unsigned char upperNibble, keyCode, keyPressed, i;
while(1)
{
upperNibble = 0xff;
for(i=0; i<4; i++)
{
delay(1);
KB_PORT_OUT = ~(0x01 << i);
delay(1); //delay for port o/p settling
upperNibble = KB_PORT_IN | 0x0f;
if (upperNibble != 0xff)
{
delay(20); //key debouncing delay
upperNibble = KB_PORT_IN | 0x0f;
if(upperNibble == 0xff) goto OUT;
keyCode = (upperNibble & 0xf0) | (0x0f & ~(0x01 << i));
while (upperNibble != 0xff)
upperNibble = KB_PORT_IN | 0x0f;
delay(20); //key debouncing delay
switch (keyCode) //generating key character to display on LCD
{
case (0xee): keyPressed = '0';
break;
case (0xde): keyPressed = '1';
break;
case (0xbe): keyPressed = '2';
break;
case (0x7e): keyPressed = '3';
break;
case (0xed): keyPressed = '4';
break;
case (0xdd): keyPressed = '5';
break;
case (0xbd): keyPressed = '6';
break;
case (0x7d): keyPressed = '7';
break;
case (0xeb): keyPressed = '8';
break;
case (0xdb): keyPressed = '9';
break;
case (0xbb): keyPressed = 'A';
break;
case (0x7b): keyPressed = 'B';
break;
case (0xe7): keyPressed = 'C';
break;
case (0xd7): keyPressed = 'D';
break;
case (0xb7): keyPressed = 'E';
break;
case (0x77): keyPressed = 'F';
break;
default : keyPressed = 'X';
}//end of switch
return keyPressed;
OUT:;
}//end of if
}//end of for
}//end of while(1)
}
-------------------------- HEADER FILES --------------------------
-----------------------------------------------------------------*/
#include <avr/io.h>
#include <string.h>
#include <avr/interrupt.h>
#include <util/delay.h>
/*----------------------------------------------------------------
------------------- DEFINITIONS ----------------------------------
-----------------------------------------------------------------*/
#define DATA_DDR DDRA // ENTER THE PORT WHICH CONTROLS
#define DATA_PORT PORTA // THE DATA PINS D0 TO D7
#define CONTROL_DDR DDRD // ENTER THE PORT WHICH CONTROLS
#define CONTROL_PORT PORTD // THE CONTROL PINS
#define Enable 2 // CoNNECTION OF ENABLE TO PIN OF ABOVE PORT
#define RS 0 // CoNNECTION OF RegisterSelect TO PIN OF ABOVE PORT
#define RW 1 // CoNNECTION OF Read/~Write TO PIN OF ABOVE PORT
#define CONTROL_MASK 0X07 // CHANGE THIS VALUE CONSIDERING THE PINS ABOVE AS HIGH
#define KB_PORT_OUT PORTB //Keypad Port
#define KB_PORT_DDR DDRB //Data Direction Register
#define KB_PORT_IN PINB //Keypad Port Pins
#define col1 PB0 //Column1 PortA.0
#define col2 PB1 //Column2 PortA.1
#define col3 PB2 //Column3 PortA.2
#define col4 PB3 //Column4 PortA.3
#define TRUE 1
#define FALSE 0
/*----------------------------------------------------------------
----------------------CONTROL BITS OF LCD ------------------------
-----------------------------------------------------------------*/
#define Set_Enable CONTROL_PORT |=_BV(Enable) // THE MACROS HERE ARE
#define Clear_Enable CONTROL_PORT &=~_BV(Enable) // SELF EXPLANATORY
#define Write_Lcd CONTROL_PORT &=~_BV(RW) //
#define Read_Lcd CONTROL_PORT |=_BV(RW) //
#define Select_InstructionRegister CONTROL_PORT &=~_BV(RS) //
#define Select_DataRegister CONTROL_PORT |=_BV(RS) //
#define Data_Lcd(b) DATA_PORT=b //
#define delay(b) _delay_ms(b) //
/*----------------------------------------------------------------
----------------------FUNCTION DECLARATIONS ----------------------
-----------------------------------------------------------------*/
void Init_Ports(void); // Initialize Ports, for selecting input output pins in the MCU
void Init_Lcd(void); // Initialize LCD, for starting and clearing LCD screen
void Lcd_Send(unsigned char a);// For sending a character to the LCD
void GotoNextLine(void); // For printing characters on the next line in the LCD
void GotoFirstLine(void); // For printing characters on the first line in the LCD
void ClearDisplay(void); // For clearing LCD
void key_init();
unsigned char get_key();
/*----------------------------------------------------------------
----------------------MAIN FUNCTION-------------------------------
-----------------------------------------------------------------*/
int main()
{
int len,len1,len2,len3,len4,len5,len6;
char str1[] = "Welcome Priyank!"; // String to be printed in 1st line
char str2[] = "Enter PIN: "; // String to be printed in 2st line
char str3[] = "This is invalid"; // String to be printed in 1st line
char str4[] = "PIN, try again."; // String to be printed in 2nd line
char str5[] = "Welcome Home!"; // String to be printed in 1st line
char str6[] = "Have a nice day."; // String to be printed in 2nd line
unsigned char keyval; //A variable
len1=strlen(str1);
len2=strlen(str2);
len3=strlen(str3);
len4=strlen(str4);
len5=strlen(str5);
len6=strlen(str6);
Init_Ports();
Init_Lcd();
key_init();
while(1)
{
for (len=0;len<len1;len++) // Printing the first string
Lcd_Send(str1[len]);
GotoNextLine(); // Go to new line
for (len=0;len<len2;len++) // Printing the 2nd string
Lcd_Send(str2[len]);
int index = 0;
unsigned char PIN[4];
while(index < 4)
{
keyval = get_key();
if(keyval != 'X')
{
PIN[index] = keyval;
Lcd_Send('*');
index++;
}
}
if(PIN[0] == '1' && PIN[1] == '5' && PIN[2] == '7' && PIN[3] == 'F')
break;
ClearDisplay(); // Go to new line
for (len=0;len<len3;len++) // Printing the first string
Lcd_Send(str3[len]);
GotoNextLine(); // Go to new line
for (len=0;len<len4;len++) // Printing the 2nd string
Lcd_Send(str4[len]);
delay(1000);
ClearDisplay(); // Go to new line
}
ClearDisplay(); // Go to new line
for (len=0;len<len5;len++) // Printing the first string
Lcd_Send(str5[len]);
GotoNextLine(); // Go to new line
for (len=0;len<len6;len++) // Printing the 2nd string
Lcd_Send(str6[len]);
DDRC = 0xFF; //Key-board port, higher nibble - input, lower nibble - output
PORTC = 0xFF; //pull-up enabled for higher nibble
}
/*----------------------------------------------------------------
------------------SEND A CHARACTER TO LCD-------------------------
-----------------------------------------------------------------*/
void Lcd_Send(unsigned char a)
{
Select_DataRegister; // Declares information that follows as data and not instruction
Write_Lcd; // Declared information is to be written
Data_Lcd(a); // Send the character passed to the function to LCD to write
Set_Enable; // Sets enable,
delay(5); // and then
Clear_Enable; // Clears it,
delay(5); // to be ready for next character.
}
/*----------------------------------------------------------------
-----------------FUNCTIONS TO INITIALIZE PORTS--------------------
-----------------------------------------------------------------*/
void Init_Ports(void)
{
DATA_DDR=0XFF; // Setting data port for output
CONTROL_DDR=CONTROL_MASK; // Setting selected pins of control port for output
CONTROL_PORT&=~(_BV(Enable)|_BV(RS )|_BV(RW)); // Setting values to 0 at start
}
/*----------------------------------------------------------------
-------------------FUNCTION TO INITIATE LCD ----------------------
-----------------------------------------------------------------*/
void Init_Lcd(void)
{
char init[10];
int i;
init[0] = 0x01; // Initializes the display
init[1] = 0x38; // 8 - Bit Operation, 2 Line Display,5*8 Dot Character Font
init[2] = 0x0e; // Turns on display and cursor
init[3] = 0x06; // Entry Mode Set
init[4] = 0x80; // Sets DDRAM address to beginning of screen
Select_InstructionRegister;
Write_Lcd;
delay(15);
for(i=0;i<5;i++)
{
Data_Lcd(init[i]);
Set_Enable;
delay(5);
Clear_Enable;
delay(5);
}
}
/*----------------------------------------------------------------
-------------FUNCTION TO GOTO NEXT LINE IN LCD -------------------
-----------------------------------------------------------------*/
void GotoNextLine(void)
{
delay(5);
Select_InstructionRegister; // Declares information to follow as instruction
Data_Lcd(0xc0); // Code to go to next line of LCD
Set_Enable; // -- Enable cycle --
delay(5); // | |
Clear_Enable; // | |
delay(5); // -- --
}
/*----------------------------------------------------------------
----------------FUNCTION TO FIRST LINE IN LCD --------------------
-----------------------------------------------------------------*/
void GotoFirstLine(void)
{
delay(5);
Select_InstructionRegister; // Declares information to follow as instruction
Data_Lcd(0x80); // Code to go to next line of LCD
Set_Enable; // -- Enable cycle --
delay(5); // | |
Clear_Enable; // | |
delay(5); // -- --
}
/*----------------------------------------------------------------
------------------FUNCTION TO CLEAR LCD --------------------------
-----------------------------------------------------------------*/
void ClearDisplay(void)
{
delay(5);
Select_InstructionRegister; // Declares information to follow as instruction
Data_Lcd(0x01); // Code to go to next line of LCD
Set_Enable; // -- Enable cycle --
delay(5); // | |
Clear_Enable; // | |
delay(5); // -- --
}
void key_init(){
KB_PORT_DDR = 0x0F;
KB_PORT_OUT = 0xFF;
//stop errant interrupts until set up
cli(); //disable all interrupts
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}
unsigned char get_key(){
unsigned char upperNibble, keyCode, keyPressed, i;
while(1)
{
upperNibble = 0xff;
for(i=0; i<4; i++)
{
delay(1);
KB_PORT_OUT = ~(0x01 << i);
delay(1); //delay for port o/p settling
upperNibble = KB_PORT_IN | 0x0f;
if (upperNibble != 0xff)
{
delay(20); //key debouncing delay
upperNibble = KB_PORT_IN | 0x0f;
if(upperNibble == 0xff) goto OUT;
keyCode = (upperNibble & 0xf0) | (0x0f & ~(0x01 << i));
while (upperNibble != 0xff)
upperNibble = KB_PORT_IN | 0x0f;
delay(20); //key debouncing delay
switch (keyCode) //generating key character to display on LCD
{
case (0xee): keyPressed = '0';
break;
case (0xde): keyPressed = '1';
break;
case (0xbe): keyPressed = '2';
break;
case (0x7e): keyPressed = '3';
break;
case (0xed): keyPressed = '4';
break;
case (0xdd): keyPressed = '5';
break;
case (0xbd): keyPressed = '6';
break;
case (0x7d): keyPressed = '7';
break;
case (0xeb): keyPressed = '8';
break;
case (0xdb): keyPressed = '9';
break;
case (0xbb): keyPressed = 'A';
break;
case (0x7b): keyPressed = 'B';
break;
case (0xe7): keyPressed = 'C';
break;
case (0xd7): keyPressed = 'D';
break;
case (0xb7): keyPressed = 'E';
break;
case (0x77): keyPressed = 'F';
break;
default : keyPressed = 'X';
}//end of switch
return keyPressed;
OUT:;
}//end of if
}//end of for
}//end of while(1)
}
This code is based on the examples at: