The original example code is a bad implementation of how to handle a PIN, and adding the printing of the key when a digit position is correct makes it even worse.
As a bad actor I would love this implementation since I can easily "guess" the code by just pressing all the keys.
i.e. simply pressing 1 through 9 three times is guaranteed to unlock the device.
It could be less depending on the PIN.
This is because there is no reset / penalty for guessing an incorrect button.
Adding the printing of the key on the LCD when correct makes it even worse.
Since as you "guess" each position correctly along the way the key will show up until you have fully guessed the code.
The logic for handling this must be different and more extensive.
My garage keypad uses # as an ending to indicate that the PIN has been entered.
i.e. you press the buttons for the PIN code and press # when done.
It looks as the previous 4 buttons pressed before the # to see what PIN you typed in.
i.e. you could type a million buttons/digits and nothing will happen, but when you press the # it uses the last 4 button presses for the PIN.
But if using a fixed number of digits you also could also just check the PIN on the Nth digit entered.
I would also not hard code the PIN in software as that makes it hard to change.
I would store it in EEPROM.
i.e. you could have a "factory default" in code but the user can override it with their own pin stored in EEPROM.
You can use the LCD backlight as feedback.
IMO, this project like all software should be designed up front before any coding starts.
You need to figure out how you want it to work - FIRST.
i.e. define how you want it work.
This requires no coding ability, no coding skills, or any software or hardware since it just defining the high level functionality of how it should work.
i.e. just brain work and writing things down at this point.
Then think of the logic to make that happen - still no coding skills h/w or s/w needed.
Work through all the scenarios like what happens when each button is pressed and what happens when the incorrect buttons are pressed.
What type of user feedback to provide on the LCD.
Then and only then, attempt to start writing the code to implement it.
This includes figuring out things like how the user interface works,
i.e. how to enter the PIN, how to provide feedback on the LCD, and if desired, how to change the PIN.
There are many things you must decide.
The main things being how secure you want this to be and how configurable you want/need it to be, and user feedback when entering things.
-
how many digits? Is it fixed or can it vary like be 3 or 4 digits or more?
Keeping it a fixed number like 4 is easier to implement.
-
How to terminate entering the PIN?
It could be automatic if the number of digits is fixed.
i.e. after entering the Nth digit, it checks it.
if the PIN is correct it does what it needs to do, or starts over with the 1st digit.
This option is fairly easy to implement. Que up the buttons and automatically check all of them once the proper number has been entered.
Or treat the PIN as an actual integer number and create the number as the user types in the digits.
Or it could require telling it you have entered the PIN by doing something like pressing a key like #. But then you must figure out how to handle things when they type more than the number of buttons. i.e. does it start over or does it rotate through the PIN positions queued up or does it shift the PIN buttons in the que to allow using the most recent N buttons.
And what type of user feedback if any when they have exceeded the total number of expected PIN digits.
-
LCD backlight control.
With an i2c LCD you can also can control the backlight.
You could have a timeout that turns off the backlight to preserve the life of the backlight save power that triggers after a certain amount of time with no button pressed.
-
User feedback
Lots of options here.
You need to figure out how you want to use the display.
Perhaps you print '*' for each button press.
If using backlight control you can use that for feedback as well.
How to provide feedback if any for correct or incorrect button presses.
The most secure is only provide feedback when something is pressed but no feedback when a button is correct or incorrect for the PIN until entering the final PIN position.
-
how / when to lock back.
i.e. should it lock back based on some amount of time, or does the user have to do something to lock.
If the user has to do something to lock it, should the user enter the unlock PIN when doing the lock sequence?
On some safes you enter the open/unlock PIN each time you lock the safe.
This is a fairly simple way to have a user configurable PIN that is built in by design.
While this is good for some use cases like a safe, it may not work well for other use cases.
-
Should the PIN be changeable from the keypad?
This depends how the PIN works since if a PIN is entered to lock the device, it becomes changeable by design.
If it is fixed pin that can be modified, then there would need to be a sequence to enter the existing pin to allow changing the pin. And then there must be a way to set the PIN back the "factory default" that is hard coded in the source code.
like pressing some combination of * or # to enter a PIN change mode.
I would suggesting spending some time thinking about how you want your system to work and then when you have a design, come back to code implementation.
--- bill