Public post

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

· Subscription Projects

This premium tutorial will teach you how to combine a keypad, a TM1637 4-digit 7-segment display, a relay, a solenoid lock, and an Arduino Uno.

This premium tutorial will teach you how to combine a keypad, a TM1637 4-digit 7-segment display, a relay, a solenoid lock, and an Arduino Uno.

The display shows the input from the keypad,  a Pincode. If the user enters the correct code, the solenoid lock unlocks.

The tutorial explains the code in detail, so you should have no problems modifying it to suit your needs. The code allows you to add multiple passwords. The passwords are predefined in the code.

Wiring diagrams are included in this tutorial. The tutorial starts with a breadboard layout that shows all the connections. This breadboard layout is explained in 3 sections. Each module connection is explained.

If you are new to Arduino, please visit the below tutorials before continuing.

Materials you will need

Component Number
Arduino Uno Rev3 1x
Jumper Wires 17x
Breadboard 400 points 1x
DC Barrel Jack 1x
5V Relay 1x
12V Solenoid Lock 1x
TM1637 4-digit 7-segment Display 1x
Keypad 1x

Breadboard Layout

TM163 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 the display.

A 7-segment display contains 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.

TM1367 Wire connection

TM1637 4-digit displayArduino Board
VCC3.3v Pin
GNDGND Pin
CLKA0 Pin
DIOA1 Pin

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 column should be connected to the Arduino Board. In total, we have 7 pins that we are going to connect.

Arduino detects which button is pressed on the keypad by detecting the row and columns pin that is detected to the button.

Keypad wire connections

3x4 Matrix KeypadArduino Board
Pins 1 till 7Pin 7 till 13

Relay Module

The relay module gives you the ability to separate two different circuits with different voltages. In the breadboard layout, the solenoid lock is separate from the Arduino Board with a relay module. The  Arduino Board controls the relay. When the relay is activated, a HIGH signal is sent to the module. The 12 volts circuit is “activated.” This allows us to control the solenoid lock with a different voltage circuit (12V) with the 5V circuit from the Arduino Board. For the wire connection of the relay module with the Arduino Board, it is important to decide whether you want the relay to act as normally closed or as normally open.

  • COM: common pin
  • NC (Normally Closed): the normally closed configuration is used when you want the relay to be closed by default, meaning the current is flowing unless you send a signal from the Arduino to the relay module to open the circuit and stop the current.
  • NO (Normally Open): the normally open configuration works the other way around: the relay is always open, so the circuit is broken unless you send a signal from the Arduino to close the circuit.

Relay wire connections

5v RelayArduino Board
VCC5V Pin
GNDGND Pin
In PinPin3
COM OutputGND DC Jack
NO OutputVCC Solenoid

Solenoid Lock

The Arduino Board controls the solenoid lock. As stated above, the board sends a signal to the relay module that turns the solenoid on and off. The lock works only with electricity, so the lock cannot be opened or closed in case of power failure.

Solenoid Wire connections

12V SolenoidRelay / Power Supply
VCC SolenoidNO Output relay
GND solenoidGND DC Power supply

The Code

The code that in this article is a paid part of the website. For only 10 dollars, you will be able to see and use the code. Most of the articles are free. However, the premium articles enable me to take time off my job and write more articles.

Furthermore, if there are any questions regarding adjustment, feel free to ask them in the comment section.

In summary, this premium code controls a solenoid lock by entering the correct password with a keypad (code is displayed on a TM1367 Display).

/*
   Password Lock with TM1637

   You can set a number of predefined codes that can be used for further action.
   using the keypad. the input is displayed on a 4-digit LED display.
   If the user inputs matches one of the known codes, a relay module is turned on
   or off accordingly.

   Demonstrates:
   - Keypad input
   - TM1637 4-digitdeb LED display
   - Relay module
*/

// Libraries used
// 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
const byte keypadRowPins[4] = {7, 8, 9, 10};
// Column pins
const byte keypadColPins[3] = {11, 12, 13};
// Pins which the relay modules are connected to
const byte relayPins[] = {3};
// Clock pin for the display
const byte displayClockPin = A0;
// Data pin for the 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, specifying pin parameters (Clock pin, Data pin)
TM1637Display display(displayClockPin, displayDataPin);
// Record the code which the user has entered
char data[] = "    ";
// What position through the code is being entered?
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++) { 
  // Digits can be displayed directly using the encodeDigit() function
  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

  Serial.begin(9600);

  // Set brightness
  display.setBrightness(4);

  // Initialise relay pins
  for (int i = 0; i < 1; i++) {
    digitalWrite(relayPins[i], LOW);
    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
      if (strcmp(data, "1000") == 0) {
        digitalWrite(relayPins[0], HIGH);
        delay(2000);
      }
      else if (strcmp(data, "1001") == 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

First of all, the code uses a couple of libraries.

To install the libraries, you can download the TM1367 Display library as a .zip from GitHub here and the Keypad library here. Next, go to Sketch > Include Library > Add .ZIP Library… in the Arduino IDE.

// Libraries used
// 4-digit 7-segment LED Display library, download from
// https://github.com/avishorp/TM1637
#include "TM1637Display.h"
// Keypad library
#include "Keypad.h"

Define Constants

We will use constant and global variables in this sketch. The constant variables will not change in the sketch. The pins are used for connecting the different modules and defining the layout of the keypad.

The first constant const char keys[4][3] defines an array of 4 rows and three columns. It is called a multidimensional array. It is a representation of the keypad layout.

As a note, you can adjust this but remember the layout of your keypad. Remember to change the number of rows and columns if you have a different keypad.

The row pins and column pins are defined next. Take a close look at the breadboard layout and the pin layout of your keypad.

After the constants of the keypad are defined, the relay pin is defined. const byte relayPins[] = {3}; . The relay variable is an array that allows you to add relays quite easily.

Next, the clock and data pin of the display are defined. The clock pin goes to A0 while the data pin goes to A1.

// 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
const byte keypadRowPins[4] = {7, 8, 9, 10};
// Column pins
const byte keypadColPins[3] = {11, 12, 13};
// Pins which the relay modules are connected to
const byte relayPins[] = {3};
// Clock pin for the display
const byte displayClockPin = A0;
// Data pin for the display
const byte displayDataPin = A1;

Define Globals

To capture what digit is pressed on the keypad, a global object is created, Keypad, which uses the constant variables described above.

Next, the Display library is defined,

Thirdly, a data array is defined, char data [] = ”    “; It is an array of char characters. There are 4 spaces added between the ”    “. This array holds the input, password, from the keypad. The input is recorded into a character array since the input can be non-numeric. Therefore you cannot define this as an integer variable, which holds only numbers.

As the input from the keypad is received one at a time, the counter sequenceNum is used to know the input’s position. So, when the user enters the first input the counter is set to 1. When the second input is entered the counter will be 2. The counter will continue until the code recognizes a 4-digit character.

// GLOBALS
// Create a keypad input class from definitions above
Keypad keypad = Keypad( makeKeymap(keys), keypadRowPins, keypadColPins, 4, 3 );
// Create a display object, specifying pin parameters (Clock pin, Data pin)
TM1637Display display(displayClockPin, displayDataPin);
// Record the code which the user has entered
char data[] = "    ";
// What position through the code is being entered?
int sequenceNum = 0;

To be able to send the 4 character code to the display some modifications are needed. Remember, we are using a 7-segment display with a keypad. On the keypad above, there is also an Asterix key and a hashtag key. If the user enters that character, it would not be easy to display that using a 7-segment display.

Updatedisplay function

Firstly a function is created called updateDisplay. As stated above, the input cannot be sent directly to the display. So we are creating a new array called displayData. This will hold the data that CAN be sent to the display.

Next, the code loops over the data array (that holds the raw input) and adds 1 to the counter if the loop is over. If the data array values are a digit, 0 – 9, that value is directly sent to the display using the encodeDigit function. Remember, everything in the data array is an ASCCI number.

Take a close look at the following code. You see that the number ‘0’ and ‘9’ have single quotes around it. This is because they represent the number 0 and the number 9. The numbers in the data array are stored as characters from the ASCII table. If you look at the ASCII table, the number 0 is in ASCII 48. Therefore, to get the digit number 0, 48 should be subtracted from the ASCII value.

In case that the value in the data array is an Asterix, the middle line of the LED segment is activated by sending “0b01000000”. The 7-segment display consists of 7 segments that can be activated individually. In order to activate a segment, you send a 1 to the display and to deactivate a segment, you sent a 0. To activate segment A the last character should be 1 “0b00000001”. To activate segment B your second last 0 should be 1 “0b0000010”.

For the hashtag symbol, we are turning on segment A and D (not B and C) by sending “0b00001001”. This will give two horizontal lines at the top and bottom of the display.

After every value is ready for the display, the data is sent with the code display.setSegments(displayData);

The above code seems a bit complicated but necessary since it converts the input from the keypad into “display ready” data.

// 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++) { 
  // Digits can be displayed directly using the encodeDigit() function
  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 Display function

If you enter the wrong code, the display will flash. The function void flashDisplay() does that. Again, an array is declared that holds can hold 4 digits. In order to have a blank display, segments should be turned off, you can send an empty array by using the character 0.

If the function flashDisplay() is called on, the display will toggle between the currently entered 4-digits and the blank array with a small delay between them.

// 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();
  }
}

Setup Part

The setup part of the code is quite simple. Since we already defined the constructors at the beginning of the sketch for the display and the keypad.

The brightness of the display is defined. You can use numbers 1 till 7. 7 will be the highest brightness.

We also initialize the relay output pins. Since we are only using 1 relay, the for loop seems a bit too much. However, when you decide to use more relays, adjusting the code will be much easier.

// Initial setup
void setup() {
  // Initialise serial communication

  Serial.begin(9600);

  // Set brightness
  display.setBrightness(4);

  // Initialise relay pins
  for (int i = 0; i < 1; i++) {
    digitalWrite(relayPins[i], LOW);
    pinMode(relayPins[i], OUTPUT);
  }
}

Main Part

In the main part of the code, the first thing to do is to ask the keypad class whatever is pressed on the keypad and store that in a character variable called key.

If “key” returns true, a key is pressed on the keypad, which we sent over to serial communication.

Then the value of the pressed key is set on the position in the data array according to the counter, sequenceNum.

Next, the counter is incremented with 1, so the next time a key is pressed the second value of the data array is set.

If the counter reaches the value 4 (4 digit code is entered on the keypad), the 4 digits are sent to the Serial monitor. Then it is time to do something based on the code that was entered.

This is the part where you can change the password or code and change what will happen if the correct code is entered.

The code below compares the 4 character array that the user entered with the string “1000”. The function strcmp compares two strings of data. Since we are comparing a string of characters double quotes are used.

if (strcmp(data, “1000”) == 0)

If the password is 1001 the relay pin will be set low. Thus, controlling the relay by using a password.  After a correct password/code is entered a delay is added.

If none of the codes matches, the code will flash the display as described earlier.

// 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
      if (strcmp(data, "1000") == 0) {
        digitalWrite(relayPins[0], HIGH);
        delay(2000);
      }
      else if (strcmp(data, "1001") == 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();
      }

Reset everything

Finally, after everything is done we are going to “reset” everything. The memset function replaces the data array with 0’s.

It takes all the data, then decides what to replace it with (in our case 0), and then decides the number to be set to a new value. The number of elements is off course 4 and can be calculated using sizeof(data).

After clearing the data array, the display is updated again.

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

      // Update the display
      updateDisplay();

That’s it! Thanks for purchasing this premium article. If there are any questions, please leave them in the comments, and I will respond to them accordingly.

That’s it! Thanks for following along with this project.

Become a member

You just read a free post but there are 2 member-only posts that you don't currently have access to.

Subscribe for $14.99 monthly or $99.99 yearly.

Become a member

Comments

Comments are for members only.
Please become a member or sign in to join the conversation!

You've successfully subscribed to ArduinoPlatform
Welcome! You are now a ArduinoPlatform subscriber.
Welcome back! You've successfully signed in.
Success! You are now a paying member and have access to all content.
Success! Your billing info is updated.
Billing info update failed.