Learn to code

ARDUINO & CODES

Previous Post
Understanding global and local variables for Arduino
Next Post
Understanding strings in Arduino

Creating a password protected lock with a keypad, relay, and display for Arduino

in Arduino Project

In this tutorial, you will learn how to create a password protected lock with a keypad, relay, TM1637 display and an Arduino Uno Board.

We will use a user input from the keypad to determine of the correct code is entered. If the users input is matches with one of the codes the relay module will turn on. If an incorrect code has entered the relay will turn off and the 12v solenoid lock will close. The code that is entered will be displayed on the TM1637 Display.

What you will need to know?

Before continuing with this guide, you may want to check out any topics from the list below that sound unfamiliar.

Parts you will need

Arduino Uno Rev3 Arduino Uno Rev3 × 1
Dupont Wires Dupont Wires × 17
DC Barrel Jack DC Barrel Jack × 1
5v Relay 5v Relay × 1
12v Solenoid Lock 12v Solenoid Lock × 1
TM1637 4-digit 7-segment display TM1637 4-digit 7-segment display × 1
Keypad Keypad × 1

Arduinoplatform is a participant in several affiliate programs. This means that I will earn a commision if you buy a product from the affiliated websites through clicking on the links provided above.

Keypad 3 x 4

The buttons of each keypad are arranged in rows and columns. The keypad that we are using has 4 rows and 3 columns. Beneath each key is a switch. Each switch is connected with the other switches in the row.  Each row and columns should be connected to the Arduino. In total, we have 7 pins that we are going to connect.

TM1637 Display

Most displays require a lot of connection pins. That is quite complex and does not leave much space for other sensors or modules to connect with the Arduino Board. The TM1637 display module only uses four pins. Two pins are required for the power connections and the other two are used to control display.

A 7-segment display contain individually addressable LEDs. The segments are labeled from A to G. To be able to set the LEDs you should know which segment corresponds to which letter. The image shows how the display segments are labeled.

BreadBoard Layout

Wire Connections

5v RelayArduino Board
VCC5V Pin
GNDGND Pin
In PinPin3
COM OutputGND DC Jack
NO OutputVCC Solenoid
TM1637 4-digit displayArduino Board
VCC3.3v Pin
GNDGND Pin
CLK A0 Pin
DIOA1 Pin
3x4 Matrix KeypadArduino Board
Pins 1 till 7Pin 7 till 13

The Code

// ArduinoPlatform code for creating 
// a door lock with keypad and relay
// 4-digit 7-segment LED Display library, download from https://github.com/avishorp/TM1637
#include <TM1637Display.h>
// Keypad library
#include <Keypad.h>

// CONSTANTS
// Define the characters on the keypad layout
const char keys[4][3] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
// Row pins of keypad
const byte keypadRowPins[4] = {13, 12, 11, 10};
// Column pins of keypad
const byte keypadColPins[3] = {9, 8, 7};
// Pins which the relay modules are connected to, you can add 
const byte relayPins[] = {3};
// Clock pin for the TM1637 display
const byte displayClockPin = A0;
// Data pin for the  TM1637 display
const byte displayDataPin = A1;

// GLOBALS
// Create a keypad input class from definitions above
Keypad keypad = Keypad( makeKeymap(keys), keypadRowPins, keypadColPins, 4, 3 );
// Create a display object
TM1637Display display(displayClockPin, displayDataPin);
// Here we store the entered code
char data[] = "    ";
// Record the position/sequence of the keys pressed
int sequenceNum = 0;

// Updates the display to show the current code entered by the user
void updateDisplay(){
  // Initialise a new blank display array
  uint8_t displayData[] = { 0, 0, 0, 0 };
  // Loop over each character in the code
  for(int i=0; i<(sizeof(data)/sizeof(data[0])); i++){ if(data[i] >= '0' && data[i] <= '9') {
      displayData[i] = display.encodeDigit((int)data[i] - 48);
    }
    // For the * character, display a single line in the middle of the digit display
    else if(data[i] == '*'){
      displayData[i] = 0b01000000;
    }
    // For the # character, display parallel lines at the top and bottom of the digit
    else if(data[i] == '#'){
      displayData[i] = 0b00001001;
    }
  }
  // Pass the data array to the display
  display.setSegments(displayData);
}

// Flash the current value of the display on and off
void flashDisplay(){
  // Define an "empty" array (i.e. all segments off)
  uint8_t OFF[] = { 0, 0, 0, 0 };
  // Toggle between the current value and the empty value
  for(int i=0; i<4; i++){
    delay(250);
    display.setSegments(OFF); 
    delay(250);
    updateDisplay();
  }
}

// Initial setup
void setup() {
  // Initialise serial communication if required for debugging
    Serial.begin(9600);
  
    // Set brightness
  display.setBrightness(4);
  
  // Initialise relay pins
  for(int i=0; i<4; i++){
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

// Main Program Loop
void loop() {

  // Get the keypad input this frame
  char key = keypad.getKey();

  // Has a key been pressed?
  if (key){
    
      // Log it to the serial output
      Serial.println(key);
   
    // Set the current position of the code sequence to the key pressed
    data[sequenceNum] = key;
    // Increment the counter
    sequenceNum++;

    // Update the display to reflect the current sequence
    updateDisplay();

    // If the player has entered all 4 digits of a code
    if(sequenceNum == 4) {   
         
        Serial.print(F("Code entered: "));
        // Log the whole code to the serial output
        Serial.println(data);
      
      // Take action based on the code entered
      // You can add extra passwords and relaypins by just replicating the code below
      if(strcmp(data, "1234") == 0){
        digitalWrite(relayPins[0], HIGH);
        delay(2000);
      }
      else if(strcmp(data, "4321") == 0){
        digitalWrite(relayPins[0], LOW);
        delay(2000);
      }
      // If none of the conditions above have matched, it's an unknown code
      else {
        // FLash the display
        flashDisplay();
      }

      // Clear the data array
      memset(data, 0, sizeof(data));
      sequenceNum = 0;

      // Update the display
      updateDisplay();
    }
  }
}

 

Code Explanation

The code starts with including the library functions. Remember, to use the correct library or else you will get an error when you compile the code. You will use the keypad library and the library for the TM1637 display.

Constant / Global variables

Defining Pins

After the libraries are included. the keypad rows and columns are defined. Since we are using a 4 by 3 keypad we need to define an array that holds the values from the keypad. Since these will not change we are using constants. Furthermore, the pin that is attached to the relay is defined. Also, the pins that are connected to the display are defined.

Globals

In this section, we are using the libraries so that the keypad and the display will work.

Char array

This going to be the variable that stores the input from the keypad. Notice that the keypad has non-numerical input (hash, Asterix). Therefore we are not able to define it as an array with bytes or integers. It is important to note that the characters are stored as numbers in the char array. Therefore, if we want to arithmetic calculation with the char array, we need to use ASCII Chart. The ASCII chart shows us that the number 0 is in fact 48 in ASSCI language. This means that if we store the number 0 in the char array and access it in the code the number 48 will appear. Therefore, if you want to make calculations with the ASCII numbers you need to conduct 48 in your function. This will be shown later on.

// CONSTANTS
// Define the characters on the keypad layout
const char keys[4][3] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
// Row pins of keypad
const byte keypadRowPins[4] = {13, 12, 11, 10};
// Column pins of keypad
const byte keypadColPins[3] = {9, 8, 7};
// Pins which the relay modules are connected to, you can add 
const byte relayPins[] = {3};
// Clock pin for the TM1637 display
const byte displayClockPin = A0;
// Data pin for the  TM1637 display
const byte displayDataPin = A1;

// GLOBALS
// Create a keypad input class from definitions above
Keypad keypad = Keypad( makeKeymap(keys), keypadRowPins, keypadColPins, 4, 3 );
// Create a display object
TM1637Display display(displayClockPin, displayDataPin);
// Here we store the entered code
char data[] = "    ";
// Record the position/sequence of the keys pressed
int sequenceNum = 0;

 

UpdateDisplay

So the numbers are stored as characters and that’s where it is getting a bit complicated. The IF function checks whether or not the character that is pressed on the keypad contains a number. Remember, 0 – 9 is stored as a character and not a number. The IF function checks if the character 0 till 9 is stored in the char array. To be able to send it to the display we conduct 48 of the value of the character. Then we can send this as an integer to the display.

If the data is not a number but an asterisk or a hash symbol we need to display something else. Since these symbols cannot be displayed directly we need to come up with our own presentation.

The last part is to send the data to the display.

Incorrect value entered.

When an incorrect value is entered you might want to notify the user that it is incorrect. So flashing functions seem appropriate to let the user know that the code entered is wrong. 

// Updates the display to show the current code entered by the user
void updateDisplay(){
  // Initialise a new blank display array
  uint8_t displayData[] = { 0, 0, 0, 0 };
  // Loop over each character in the code
  for(int i=0; i<(sizeof(data)/sizeof(data[0])); i++){ if(data[i] >= '0' && data[i] <= '9') {
      displayData[i] = display.encodeDigit((int)data[i] - 48);
    }
    // For the * character, display a single line in the middle of the digit display
    else if(data[i] == '*'){
      displayData[i] = 0b01000000;
    }
    // For the # character, display parallel lines at the top and bottom of the digit
    else if(data[i] == '#'){
      displayData[i] = 0b00001001;
    }
  }
  // Pass the data array to the display
  display.setSegments(displayData);
}

FlashDisplay

If a user enters a 4 digit code will flash the display if the code is incorrect. A 4 digit array is created that represents the 4 digits in the display. These are defined as zero so that all of the segments will be set off.
A simple loop is created that is going to loop over four times. It will wait for a quarter of a second in every loop, set all the segments off, way again for a quarter of a second and then it is going to display the incorrect code that is entered by the user.

void countdown() {
  for(int i=1500; i>0; i--) {
    // showNumberDec is a function for displaying numeric values,
    display.showNumberDec(i, true, 4, 0);
    delay(80);
  }
}
void displayPlay() {
  display.setSegments(PLAY);
  delay(2000);
}
void displayDone() {
  display.setSegments(DONE);
  delay(2000);
}

Executing the code

When the code is first to run this part will be executed. Firstly, Serial Communication is started. The brightness of the 4 digit display is set. Furthermore, the output mode of the relay pins is initialized. The keypad outputs are already handled by the library functions.

// Initial setup
void setup() {
  // Initialise serial communication if required for debugging
    Serial.begin(9600);
  
    // Set brightness
  display.setBrightness(4);
  
  // Initialise relay pins
  for(int i=0; i<4; i++){
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

 

The first thing you are going to code is to ask the program for the key that is pressed by the user. We are going to store that in a character called key. If KEY returns TRUE, that means that any key on the keypad is pressed.

Then we will set the data array to the key that was pressed on the keypad. You will use sequenceNum to set the right key in the correct sequence in the char data array. So sequenceNum starts with 0 and after a key is pressed the sequenceNum value is added with 1 by the ++. So the value of the data array is set to the current key that is pressed that the current sequence number. After this sequenceNum is incremented with 1 so that the next time the key is pressed the second value in the data array is set and the third and the fourth.

The above is executed until sequenceNum reached a count of 4. Furthermore, the display is updated to reflect the current sequence of numbers.

When the user entered all four digits as a sequence will print this to the Serial Monitor.
You are arriving at the part where we decide what to do with the code entered by the user. The IF STATEMENT is followed by a function that compares strings. STRCMP compares the character array that is entered by the user to the numbers that are followed. In this case “1234”. If this is equal to zero it means that there is no difference between the character array with the input of the user and the password code “1234”. After that, we are going to set the relay pin to HIGH. 4321 is also a password that does something in the sketch. It will set the relay pin LOW. This example code can also be used to set multiple passwords with one keypad. In other words, 4321 will release the lock and the code 1234 will set the lock.

If a user enters something that does not match to IF STATEMENTS the display will flash by using an ELSE statement with the function flashDisplay.

The last thing we need to do after a player has entered a 4 digit code, is to reset the counter to zero and clear/reset the data array. This is necessary so that the user can reinter a new password. For the last time, we update the display to reflect the current value of the data

// Main Program Loop
void loop() {

  // Get the keypad input this frame
  char key = keypad.getKey();

  // Has a key been pressed?
  if (key){
    
      // Log it to the serial output
      Serial.println(key);
   
    // Set the current position of the code sequence to the key pressed
    data[sequenceNum] = key;
    // Increment the counter
    sequenceNum++;

    // Update the display to reflect the current sequence
    updateDisplay();

    // If the player has entered all 4 digits of a code
    if(sequenceNum == 4) {   
         
        Serial.print(F("Code entered: "));
        // Log the whole code to the serial output
        Serial.println(data);
      
      // Take action based on the code entered
      // You can add extra passwords and relaypins by just replicating the code below
      if(strcmp(data, "1234") == 0){
        digitalWrite(relayPins[0], HIGH);
        delay(2000);
      }
      else if(strcmp(data, "4321") == 0){
        digitalWrite(relayPins[0], LOW);
        delay(2000);
      }
      // If none of the conditions above have matched, it's an unknown code
      else {
        // FLash the display
        flashDisplay();
      }

      // Clear the data array
      memset(data, 0, sizeof(data));
      sequenceNum = 0;

      // Update the display
      updateDisplay();
    }
  }
}

In this tutorial I have demonstrated how to create a password door lock with a keypad, relay, TM1637 Display and an Arduino Uno Board.

I hope that you enjoyed reading the tutorial and fount is useful and informative. If you did please subscribe to my Instagram or Pinterest account found at the top of this page.

In any case that you have questions, feel free to ask them in the comments.

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed

Menu