"""
==========================================================
Password Lock System — Raspberry Pi Pico (MicroPython)
LCD SDA -> GP4 SCL -> GP5 (I2C addr 0x27)
Keypad rows -> GP10(R1) GP11(R2) GP12(R3) GP13(R4)
Keypad cols -> GP14(C1) GP15(C2) GP16(C3)
diagram.json keys="123X456X789XC0EX" columns="3"
Wokwi internal grid is always 4-wide; X = hidden dummy col4
Displayed keypad: Code LAYOUT (only cols 0-2 used):
1 2 3 [X hidden] ['1','2','3']
4 5 6 [X hidden] ['4','5','6']
7 8 9 [X hidden] ['7','8','9']
C 0 E [X hidden] ['C','0','E']
C = Backspace (delete last char)
E = Enter (check password)
==========================================================
"""
from machine import Pin, SoftI2C
import time
# ── MicroPython-safe pad (str.ljust not in v1.22) ─────────────────────────
def pad(text, width=16):
s = str(text)[:width]
while len(s) < width:
s += " "
return s
# ── I2C LCD driver (PCF8574 backpack) ─────────────────────────────────────
class I2cLcd:
LCD_CHR = 1
LCD_CMD = 0
LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0
LCD_BL = 0x08
ENABLE = 0b00000100
def __init__(self, i2c, addr=0x27):
self.i2c = i2c
self.addr = addr
self.buf = bytearray(1)
time.sleep_ms(50)
self._write4(0x03); time.sleep_ms(5)
self._write4(0x03); time.sleep_ms(1)
self._write4(0x03)
self._write4(0x02)
self.send(0x28, self.LCD_CMD)
self.send(0x0C, self.LCD_CMD)
self.send(0x06, self.LCD_CMD)
self.clear()
def _strobe(self, data):
self.buf[0] = data | self.ENABLE | self.LCD_BL
self.i2c.writeto(self.addr, self.buf)
time.sleep_us(500)
self.buf[0] = (data & ~self.ENABLE) | self.LCD_BL
self.i2c.writeto(self.addr, self.buf)
time.sleep_us(100)
def _write4(self, data):
b = (data << 4) | self.LCD_BL
self.buf[0] = b
self.i2c.writeto(self.addr, self.buf)
self._strobe(b)
def send(self, data, mode):
hi = mode | (data & 0xF0) | self.LCD_BL
lo = mode | ((data << 4) & 0xF0) | self.LCD_BL
self.i2c.writeto(self.addr, bytes([hi])); self._strobe(hi)
self.i2c.writeto(self.addr, bytes([lo])); self._strobe(lo)
def clear(self):
self.send(0x01, self.LCD_CMD)
time.sleep_ms(3)
def move(self, row, col):
self.send([self.LCD_LINE_1, self.LCD_LINE_2][row] + col, self.LCD_CMD)
def write(self, text):
for ch in str(text):
self.send(ord(ch), self.LCD_CHR)
def print_line(self, row, text):
self.move(row, 0)
self.write(pad(text, 16))
# ── Keypad driver ─────────────────────────────────────────────────────────
class Keypad:
def __init__(self, row_pins, col_pins, layout):
self.rows = [Pin(p, Pin.OUT) for p in row_pins]
self.cols = [Pin(p, Pin.IN, Pin.PULL_DOWN) for p in col_pins]
self.layout = layout
for rp in self.rows:
rp.low()
def scan(self):
for r, rp in enumerate(self.rows):
rp.high()
time.sleep_us(10)
for c, cp in enumerate(self.cols):
if cp.value():
rp.low()
return self.layout[r][c]
rp.low()
return None
# ── Hardware init ─────────────────────────────────────────────────────────
i2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=100_000)
lcd = I2cLcd(i2c, addr=0x27)
# Only 3 columns wired (C1-C3), so layout has 3 cols only.
# The 4th col (X dummy) is never connected so never fires.
LAYOUT = [
['1', '2', '3'], # R1 GP10
['4', '5', '6'], # R2 GP11
['7', '8', '9'], # R3 GP12
['C', '0', 'E'], # R4 GP13 C=Backspace E=Enter
]
keypad = Keypad(
row_pins=[10, 11, 12, 13],
col_pins=[14, 15, 16],
layout=LAYOUT
)
# ── Password ──────────────────────────────────────────────────────────────
SECRET = "1234" # <-- change your password here
MAX_LEN = 16
# ── State ─────────────────────────────────────────────────────────────────
typed = ""
last_key = None
result_shown = False
# ── UI ────────────────────────────────────────────────────────────────────
def show_idle():
lcd.print_line(0, "Enter Password:")
lcd.print_line(1, "")
def show_typing():
stars = ""
for _ in range(len(typed)):
stars += "*"
lcd.print_line(1, stars)
def show_granted():
lcd.print_line(0, " ACCESS GRANTED ")
lcd.print_line(1, " Welcome! :D ")
def show_denied():
lcd.print_line(0, " ACCESS DENIED ")
lcd.print_line(1, " Wrong Password ")
# ── Boot ──────────────────────────────────────────────────────────────────
lcd.print_line(0, " Lock System ")
lcd.print_line(1, " Pico + LCD ")
time.sleep(2)
show_idle()
# ── Main loop ─────────────────────────────────────────────────────────────
while True:
key = keypad.scan()
if key and key != last_key:
last_key = key
if result_shown:
typed = ""
result_shown = False
show_idle()
elif key == 'C':
if len(typed) > 0:
typed = typed[:-1]
if len(typed) == 0:
show_idle()
else:
show_typing()
elif key == 'E':
if typed == SECRET:
show_granted()
else:
show_denied()
typed = ""
result_shown = True
else:
if len(typed) < MAX_LEN:
typed += key
show_typing()
elif not key:
last_key = None
time.sleep_ms(50)