from machine import Pin, PWM
import time
# ==================== 1. 矩阵键盘驱动 ====================
# https://wokwi.com/projects/462502953727465473
class Keypad4x4:
"""4x4矩阵键盘:逐行扫描,列输入上拉"""
KEYMAP = [
["1", "2", "3", "A"],
["4", "5", "6", "B"],
["7", "8", "9", "C"],
["*", "0", "#", "D"],
]
def __init__(self, row_pins, col_pins):
# 行线 = 输出(主动拉低扫描)
self.rows = [Pin(p, Pin.OUT) for p in row_pins]
# 列线 = 输入+上拉(平时高电平,按键按下被拉低)
self.cols = [Pin(p, Pin.IN, Pin.PULL_UP) for p in col_pins]
self._all_rows_high()
def _all_rows_high(self):
"""所有行置高电平(无效化状态)"""
for r in self.rows:
r.value(1)
def scan_once(self):
"""扫描一次,返回按键字符或None"""
for r_idx, r in enumerate(self.rows):
self._all_rows_high()
r.value(0) # 当前行拉低
time.sleep_ms(2) # 等待电平稳定
for c_idx, c in enumerate(self.cols):
if c.value() == 0: # 列线变低 = 按键按下
self._all_rows_high()
return self.KEYMAP[r_idx][c_idx]
self._all_rows_high()
return None
def wait_release(self):
"""等待所有按键释放"""
while True:
pressed = False
for r in self.rows:
self._all_rows_high()
r.value(0)
time.sleep_ms(1)
for c in self.cols:
if c.value() == 0:
pressed = True
break
if pressed:
break
self._all_rows_high()
if not pressed:
return
time.sleep_ms(10)
def read_key_event(keypad, debounce_ms=30):
"""读取一次有效按键:消抖 + 等待释放"""
k1 = keypad.scan_once()
if not k1:
return None
time.sleep_ms(debounce_ms) # 延时消抖(覆盖机械抖动5~20ms)
k2 = keypad.scan_once()
if k1 != k2:
return None # 两次不一致,判定为抖动
keypad.wait_release() # 等待手指抬起,防止重复触发
return k2
# ==================== 2. 声光反馈系统 ====================
class Feedback:
"""三色LED + 蜂鸣器反馈"""
def __init__(self):
self.led_g = Pin(25, Pin.OUT) # 绿灯:密码正确/通过
self.led_y = Pin(26, Pin.OUT) # 黄灯:输入中提示(核心!)
self.led_r = Pin(33, Pin.OUT) # 红灯:密码错误/拒绝
self.buzzer = PWM(Pin(14, Pin.OUT))
self.buzzer.duty(0) # 默认静音
def all_off(self):
self.led_g.off()
self.led_y.off()
self.led_r.off()
self.buzzer.duty(0)
def typing(self):
"""【黄灯】输入中闪一下:按数字键或*键时调用"""
self.led_y.on()
time.sleep_ms(60)
self.led_y.off()
def ok(self):
"""【绿灯+蜂鸣器】密码正确"""
self.all_off()
self.led_g.on()
self._beep(1000, 200)
time.sleep_ms(300)
self.led_g.off()
def deny(self):
"""【红灯+蜂鸣器】密码错误:响两声"""
self.all_off()
self.led_r.on()
for _ in range(2):
self._beep(800, 150)
time.sleep_ms(80)
time.sleep_ms(300)
self.led_r.off()
def _beep(self, freq, ms):
self.buzzer.freq(freq)
self.buzzer.duty(512)
time.sleep_ms(ms)
self.buzzer.duty(0)
# ==================== 3. 密码输入管理(本实验核心) ====================
class PasswordInput:
"""密码缓存器:支持输入、清空、提交、长度限制"""
def __init__(self, password="123456", max_len=6):
self.password = password # 预设正确密码
self.max_len = max_len # 最大长度限制(防超长)
self.buf = "" # 输入缓存字符串
def push(self, ch):
"""追加数字(受max_len限制,满后不再接收)"""
if len(self.buf) < self.max_len:
self.buf += ch
def clear(self):
"""* 键功能:清空缓存"""
self.buf = ""
def submit(self):
"""# 键功能:提交验证,验证后自动清空(安全设计)"""
ok = (self.buf == self.password)
self.buf = "" # 无论对错,验证后立即清空,防止残留
return ok
# ==================== 4. 主程序 ====================
print("=" * 50)
print("基础实验06:密码输入框与编辑规则")
print("* 键 = 清空 | # 键 = 确认 | 默认密码:123456")
print("=" * 50)
# 硬件初始化
ROW_PINS = [32, 4, 16, 17] # 键盘行线
COL_PINS = [0, 12, 2, 15] # 键盘列线
keypad = Keypad4x4(ROW_PINS, COL_PINS)
fb = Feedback()
pwd = PasswordInput(password="123456", max_len=6)
while True:
key = read_key_event(keypad)
if not key:
time.sleep_ms(10)
continue
# ---------- 按键处理逻辑 ----------
if key.isdigit(): # 【数字键】输入密码
pwd.push(key)
fb.typing() # 黄灯闪一下:提示"收到输入"
print("当前输入:", "*" * len(pwd.buf))
elif key == "*": # 【* 键】清空缓存
pwd.clear()
fb.typing() # 黄灯闪一下:提示"已清空"
print("--- 缓存已清空 ---")
elif key == "#": # 【# 键】提交验证
if pwd.submit():
print(">>> 密码正确 -> 开锁")
fb.ok() # 绿灯亮 + 蜂鸣器"嘀"一声
else:
print(">>> 密码错误 -> 拒绝")
fb.deny() # 红灯亮 + 蜂鸣器"嘀嘀"两声
else:
# A/B/C/D 键:本实验未使用,可扩展为管理员功能
print("忽略功能键:", key)