Simple Arduino PIN lock with LCD Display


I thought it would be fun to build something that looked like a smart lock for a door. With an Arduino Uno, three buttons being 1, 2 and 3 along with a buzzer, some LED diodes and a microservo I was able to make a simple mechanism that can both grant- and deny access. The servo will rotate on a valid PIN and keep an angle for X seconds (See gif underneath). Furthermore, if the PIN code is incorrect the servo won't rotate.

Here's a gif of the system in action.


Starting out with recreating the project I will be using TinkerCad to illustrate some of the parts. We can start out with the attachment of the three buttons to a breadboard, along with some LED diodes to indicate a button being pressed.


From there we can add the buzzer (Piezo speaker in this image) and one more LED diode which will both activate when the PIN code is correct. This is when the system should grant access and the servo rotate.


Now we can connect the servo to the breadboard.


The only things that are left now is to connect the LCD display and breadboard to the Arduino Uno. Let's start with the LCD display. I am using the L2C LCD display, which has basically 3 ports to connect.


The yellow wire here will be connected to ground. The red wire connects to the power. Green wire will be connected to A4 on the Arduino Uno, and the black wire will be connected to A5. Now, the only thing that's left is to connect the breadboard to the Arduino. This by connecting the power sides of the breadboard to 5V and the ground sides to the GND.

Now that the system is connect, we need to code to get it working. First off all, we need to include a library called Liquid Crystal, which can be downloaded here (Using version 1.3.4 here). From there we need to use a I2C Scanner to identify the I2C device address (I am using 0x27 here). Here's a video of the installment of this. Furthermore, we will need to include Wire.h and add the LCD paramteres for the I2C device.

We will also need to include the Servo.h library. This is for the servo.
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Servo.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); 
From there we can add the buttons, led pin, buzzer and servo pins as displayed on the images above.
// ----------- BUTTONS -------------------
int buttonPin1 = 13;
int buttonPin2 = 12;
int buttonPin3 = 11;
// ----------- LED PIN -------------------
int ledPin = 10;
// ----------- BUZZER PIN ----------------
int buzzerPin = 9;
// ----------- SERVO PIN -----------------
int servoPin = 7;
 Now we can initialize the servo and set the angle equal to zero.
Servo lock_servo;

int servoAngle = 0;
From there we will need a few variables for the whole system.
int keyseq = 0;
int lock = 0;
int code = 0;
int unlock_code = 36; // Password for buttons to unlock

const int size = 3;
Basically we will be using keyseq as the amount of buttons that are pressed. With that we can say that if keyseq = size, then we could check if it's the right sequence. Furthermore, the variable lock will be displaying a binary signal. 0 when locked and 1 for when it's open. The code variable will be the temporary code that should match unlock_code to open.

Moving on to the setup.
void setup() {
  lcd.begin(16, 2);
  
  Serial.begin(9600);
  lock_servo.attach(servoPin);

  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
  pinMode(ledPin, OUTPUT);
}
This is where we set up the whole system. We start the lcd display and define the servo, button pins and led pins. As well as initializing the serial monitor to be read on 9600 baud. Moving onto the void loop().
void loop() {

  digitalWrite(ledPin, LOW);
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("ENTER PIN...");
  lcd.setCursor(0, 1);
  delay(100);
First we are setting the LED diode that indicates wether access is granted or not to zero (low). This because it should light up (Be set to high) only when access is granted. Then we clear the LCD display and set the position for the text startup text we want displayed on the LCD, in this case we can use "ENTER PIN..." as the text.

From there we will basically have two routes to go. One where the lock = 0 and one where we need to check if lock is equal to 1. We can start out with the state when lock is equal to 0.
if(lock == 0){
    if(digitalRead(buttonPin1) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("ONE");   

      code = (code + 1) * 3;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
    if(digitalRead(buttonPin2) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("TWO");  

      code = (code + 1) * 2;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
    if(digitalRead(buttonPin3) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("THREE");

      code = (code + 1) * 4;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
  }
What's first happening here is that we're checking for which button that is pressed. From there we go in to a if-statement to do some operations. Let's take the example with the first button.
if(digitalRead(buttonPin1) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("ONE");   

      code = (code + 1) * 3;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
First of all, we clear the lcd Display and print out "ONE" instead on the first column and row. This because the first button was pressed. Then we set code equal to (code + 1) * 3, and add one up on the keyseq. There's really no apparant reason for why the code combination should be set to this. Because it could be done in other ways. But, with the sequence being (code + 1) * 3 for the first button, the second button being (code + 1) * 2 and finally the third button being (code + 1) * 4. The code will be equal to unlock_code set to 36 with the pressing of button 1, 2 and 3 in that order.

When the keyseq is finally equal to size (3) the program moves into two more options. One being that the code is correct and the other being that the code is incorrect. Let's first look at what happens if the code is equal to the unlock_code.
if(keyseq == size){
    if(unlock_code == code){
      lock = 1;
      
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("ACCESS UNLOCKED!");
      digitalWrite(ledPin, HIGH);
      tone(buzzerPin, 1000, 1500);

      lock = 0;
      code = 0;
      keyseq = 0;

      lock_servo.write(45);
      delay(1000);

      delay(15000);
      lcd.clear();
      lock_servo.write(90);
    }
So if the code = unlock_code then lock should be set to 1. While the servo will rotate and "open". This with a message saying "ACCESS UNLCOKED!" and the buzzer and LED diode lighting up. A delay will also be set on when the servo should rotate back. At last, the system will be reset. Now for the other option, the code being incorrect.
else{
      Serial.println(code);
      Serial.println(keyseq);
      
      code = 0;
      lock = 0;
      keyseq = 0;
      
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("INVALID CODE!");
      digitalWrite(ledPin, LOW);
      tone(buzzerPin, 500, 1000);
      delay(1500);
      lcd.clear();     
    }
 For this part we're just throwing an else-statement. Reseting the system and displaying a text saying "INVALID CODE!", while the buzzer beeps and the LED diode stays low.

The full code for the project:
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Servo.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); 

// ----------- BUTTONS -------------------
int buttonPin1 = 13;
int buttonPin2 = 12;
int buttonPin3 = 11;
// ----------- LED PIN -------------------
int ledPin = 10;
// ----------- BUZZER PIN ----------------
int buzzerPin = 9;
// ----------- SERVO PIN -----------------
int servoPin = 7;

Servo lock_servo;

int servoAngle = 0;

int keyseq = 0;
int lock = 0;
int code = 0;
int unlock_code = 36; // Password for buttons to unlock

const int size = 3;

void setup() {
  lcd.begin(16, 2);
  
  Serial.begin(9600);
  lock_servo.attach(servoPin);

  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {

  digitalWrite(ledPin, LOW);
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("ENTER PIN...");
  lcd.setCursor(0, 1);
  delay(100);
    
  if(lock == 0){
    if(digitalRead(buttonPin1) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("ONE");   

      code = (code + 1) * 3;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
    if(digitalRead(buttonPin2) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("TWO");  

      code = (code + 1) * 2;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
    if(digitalRead(buttonPin3) == HIGH){
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("THREE");

      code = (code + 1) * 4;
      keyseq = keyseq + 1;
      delay(1500);

      Serial.println(keyseq);
    }
  }
  if(keyseq == size){
    if(unlock_code == code){
      lock = 1;
      
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("ACCESS UNLOCKED!");
      digitalWrite(ledPin, HIGH);
      tone(buzzerPin, 1000, 1500);

      lock = 0;
      code = 0;
      keyseq = 0;

      lock_servo.write(45);
      delay(1000);

      delay(15000);
      lcd.clear();
      lock_servo.write(90);
    }
    else{
      Serial.println(code);
      Serial.println(keyseq);
      
      code = 0;
      lock = 0;
      keyseq = 0;
      
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("INVALID CODE!");
      digitalWrite(ledPin, LOW);
      tone(buzzerPin, 500, 1000);
      delay(1500);
      lcd.clear();     
    }
  }
}

Comments

Popular posts from this blog

Vigenère cipher encryption with C++

Minimum Spanning Trees (MST)