"""
智能门禁系统 - Wokwi仿真版本
Smart Access Control System - Wokwi Simulation
ESP32 + MicroPython
硬件模块:
- LCD1602 I2C显示屏
- 4x4矩阵键盘
- 有源蜂鸣器
- 继电器模块 (门锁控制)
- RGB LED (状态指示)
- 按钮 (模拟RFID刷卡)
"""
from machine import Pin, I2C, PWM
import time
# ==================== 硬件配置 ====================
# I2C配置 (LCD1602)
I2C_SDA = 21
I2C_SCL = 22
LCD_ADDR = 0x27
# 4x4矩阵键盘引脚
KEYPAD_ROWS = [13, 12, 14, 27] # R1-R4
KEYPAD_COLS = [26, 25, 33, 32] # C1-C4
# 输出设备引脚
BUZZER_PIN = 15 # 蜂鸣器
RELAY_PIN = 4 # 继电器 (门锁)
LED_RED = 16 # 红色LED (拒绝)
LED_GREEN = 17 # 绿色LED (允许)
LED_BLUE = 5 # 蓝色LED (待机)
# 模拟RFID的按钮
RFID_BTN1 = 18 # 模拟卡1 (有效卡)
RFID_BTN2 = 19 # 模拟卡2 (无效卡)
# ==================== LCD驱动 ====================
class LCD_I2C:
"""LCD1602 I2C驱动类"""
# LCD命令
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_FUNCTIONSET = 0x20
LCD_SETDDRAMADDR = 0x80
# 控制位
LCD_BACKLIGHT = 0x08
ENABLE = 0x04
RS = 0x01
def __init__(self, i2c, addr=0x27):
self.i2c = i2c
self.addr = addr
self.backlight = self.LCD_BACKLIGHT
self._init_lcd()
def _init_lcd(self):
"""初始化LCD"""
time.sleep_ms(50)
# 初始化序列
for _ in range(3):
self._write_4bits(0x30)
time.sleep_ms(5)
self._write_4bits(0x20) # 4位模式
# 功能设置: 4位, 2行, 5x8
self._write_cmd(0x28)
# 显示控制: 开显示, 关光标
self._write_cmd(0x0C)
# 清屏
self.clear()
# 输入模式
self._write_cmd(0x06)
def _write_4bits(self, data):
"""写4位数据"""
self.i2c.writeto(self.addr, bytes([data | self.backlight]))
self._pulse_enable(data)
def _pulse_enable(self, data):
"""产生使能脉冲"""
self.i2c.writeto(self.addr, bytes([data | self.ENABLE | self.backlight]))
time.sleep_us(1)
self.i2c.writeto(self.addr, bytes([data & ~self.ENABLE | self.backlight]))
time.sleep_us(50)
def _write_cmd(self, cmd):
"""写命令"""
self._write_4bits(cmd & 0xF0)
self._write_4bits((cmd << 4) & 0xF0)
def _write_char(self, char):
"""写字符"""
data = ord(char) if isinstance(char, str) else char
self._write_4bits(self.RS | (data & 0xF0))
self._write_4bits(self.RS | ((data << 4) & 0xF0))
def clear(self):
"""清屏"""
self._write_cmd(self.LCD_CLEARDISPLAY)
time.sleep_ms(2)
def set_cursor(self, col, row):
"""设置光标位置"""
addr = col + (0x40 if row else 0x00)
self._write_cmd(self.LCD_SETDDRAMADDR | addr)
def print(self, text, row=0, col=0):
"""显示文本"""
self.set_cursor(col, row)
for char in text[:16-col]:
self._write_char(char)
def display_message(self, line1="", line2=""):
"""显示两行信息"""
self.clear()
if line1:
self.print(line1.center(16), row=0)
if line2:
self.print(line2.center(16), row=1)
# ==================== 键盘驱动 ====================
class Keypad:
"""4x4矩阵键盘驱动类"""
KEYS = [
['1', '2', '3', 'A'],
['4', '5', '6', 'B'],
['7', '8', '9', 'C'],
['*', '0', '#', 'D']
]
def __init__(self, row_pins, col_pins):
# 列作为输出 (低电平扫描)
self.cols = [Pin(p, Pin.OUT, value=1) for p in col_pins]
# 行作为输入 (上拉)
self.rows = [Pin(p, Pin.IN, Pin.PULL_UP) for p in row_pins]
self._last_key = None
self._last_time = 0
def scan(self):
"""扫描键盘,返回按下的键"""
for col_idx, col in enumerate(self.cols):
col.value(0) # 拉低当前列
for row_idx, row in enumerate(self.rows):
if row.value() == 0: # 检测到按键
col.value(1)
# 消抖
now = time.ticks_ms()
key = self.KEYS[row_idx][col_idx]
if key != self._last_key or time.ticks_diff(now, self._last_time) > 300:
self._last_key = key
self._last_time = now
# 等待按键释放
while row.value() == 0:
time.sleep_ms(10)
return key
col.value(1) # 恢复高电平
return None
def read_password(self, length=4, lcd=None, timeout=30):
"""
读取密码输入
Args:
length: 密码长度
lcd: LCD显示对象
timeout: 超时时间(秒)
Returns:
(成功, 密码)
"""
password = ""
start = time.time()
if lcd:
lcd.print("Enter Password:", row=0)
lcd.print("", row=1)
while True:
# 超时检查
if time.time() - start > timeout:
return False, ""
key = self.scan()
if key is None:
time.sleep_ms(50)
continue
if key == '*': # 清除
password = ""
if lcd:
lcd.print(" ", row=1)
elif key == '#': # 确认
if password:
return True, password
elif key.isdigit():
if len(password) < length:
password += key
if lcd:
lcd.print('*' * len(password), row=1)
if len(password) == length:
time.sleep_ms(300)
return True, password
return False, ""
# ==================== 蜂鸣器驱动 ====================
class Buzzer:
"""蜂鸣器控制类"""
def __init__(self, pin):
self.pin = Pin(pin, Pin.OUT, value=0)
def beep(self, duration=0.1):
"""蜂鸣一次"""
self.pin.value(1)
time.sleep(duration)
self.pin.value(0)
def beep_times(self, times=2, on_time=0.1, off_time=0.1):
"""蜂鸣多次"""
for i in range(times):
self.beep(on_time)
if i < times - 1:
time.sleep(off_time)
def success_sound(self):
"""成功提示音"""
self.beep(0.1)
def error_sound(self):
"""错误提示音"""
self.beep_times(2, 0.2, 0.1)
def key_sound(self):
"""按键提示音"""
self.beep(0.02)
# ==================== 门锁控制 ====================
class DoorLock:
"""门锁控制类 (继电器驱动)"""
def __init__(self, pin, active_low=True):
self.pin = Pin(pin, Pin.OUT)
self.active_low = active_low
self.lock()
def lock(self):
"""锁定"""
self.pin.value(1 if self.active_low else 0)
print("[LOCK] Door locked")
def unlock(self, duration=5):
"""解锁"""
self.pin.value(0 if self.active_low else 1)
print(f"[LOCK] Door unlocked for {duration}s")
time.sleep(duration)
self.lock()
# ==================== LED状态指示 ====================
class StatusLED:
"""状态指示LED控制类"""
def __init__(self, red_pin, green_pin, blue_pin):
self.red = Pin(red_pin, Pin.OUT, value=0)
self.green = Pin(green_pin, Pin.OUT, value=0)
self.blue = Pin(blue_pin, Pin.OUT, value=0)
def off(self):
"""全部熄灭"""
self.red.value(0)
self.green.value(0)
self.blue.value(0)
def standby(self):
"""待机状态 (蓝色)"""
self.off()
self.blue.value(1)
def success(self):
"""成功状态 (绿色)"""
self.off()
self.green.value(1)
def error(self):
"""错误状态 (红色)"""
self.off()
self.red.value(1)
def processing(self):
"""处理中 (黄色 = 红+绿)"""
self.off()
self.red.value(1)
self.green.value(1)
# ==================== 模拟RFID ====================
class SimulatedRFID:
"""模拟RFID读卡器 (使用按钮模拟)"""
# 模拟的卡号
CARDS = {
'btn1': 'A1B2C3D4', # 有效卡
'btn2': 'INVALID01' # 无效卡
}
def __init__(self, btn1_pin, btn2_pin):
self.btn1 = Pin(btn1_pin, Pin.IN, Pin.PULL_UP)
self.btn2 = Pin(btn2_pin, Pin.IN, Pin.PULL_UP)
def read_card(self):
"""读取卡片 (检测按钮)"""
if self.btn1.value() == 0:
time.sleep_ms(50) # 消抖
if self.btn1.value() == 0:
while self.btn1.value() == 0:
time.sleep_ms(10)
return self.CARDS['btn1']
if self.btn2.value() == 0:
time.sleep_ms(50)
if self.btn2.value() == 0:
while self.btn2.value() == 0:
time.sleep_ms(10)
return self.CARDS['btn2']
return None
# ==================== 用户数据库 (模拟) ====================
class UserDatabase:
"""模拟用户数据库"""
def __init__(self):
# 预设用户数据
self.users = {
# RFID卡号 -> 用户信息
'A1B2C3D4': {'name': 'Zhang San', 'role': 'admin', 'pin': '1234'},
'E5F6G7H8': {'name': 'Li Si', 'role': 'user', 'pin': '5678'},
}
# PIN码 -> 用户信息
self.pins = {
'1234': {'name': 'Zhang San', 'role': 'admin'},
'5678': {'name': 'Li Si', 'role': 'user'},
'0000': {'name': 'Guest', 'role': 'guest'},
}
def verify_rfid(self, card_id):
"""验证RFID卡"""
if card_id in self.users:
return True, self.users[card_id]
return False, None
def verify_pin(self, pin):
"""验证PIN码"""
if pin in self.pins:
return True, self.pins[pin]
return False, None
# ==================== 主控制器 ====================
class AccessController:
"""门禁主控制器"""
# 认证模式
MODE_IDLE = 0
MODE_RFID = 1
MODE_PIN = 2
def __init__(self):
print("=" * 40)
print("Smart Access Control System")
print("Wokwi Simulation Version")
print("=" * 40)
# 初始化I2C和LCD
self.i2c = I2C(0, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL), freq=400000)
self.lcd = LCD_I2C(self.i2c, LCD_ADDR)
# 初始化其他模块
self.keypad = Keypad(KEYPAD_ROWS, KEYPAD_COLS)
self.buzzer = Buzzer(BUZZER_PIN)
self.door = DoorLock(RELAY_PIN)
self.led = StatusLED(LED_RED, LED_GREEN, LED_BLUE)
self.rfid = SimulatedRFID(RFID_BTN1, RFID_BTN2)
self.db = UserDatabase()
self.mode = self.MODE_IDLE
print("[INIT] All modules initialized")
def show_welcome(self):
"""显示欢迎界面"""
self.lcd.display_message("Smart Access", "System Ready")
self.led.standby()
def grant_access(self, user_info):
"""允许访问"""
name = user_info.get('name', 'User')
print(f"[ACCESS] Granted: {name}")
self.lcd.display_message("Access Granted", name)
self.led.success()
self.buzzer.success_sound()
# 开门
self.door.unlock(5)
# 恢复待机
self.show_welcome()
def deny_access(self, reason="Invalid"):
"""拒绝访问"""
print(f"[ACCESS] Denied: {reason}")
self.lcd.display_message("Access Denied", reason)
self.led.error()
self.buzzer.error_sound()
time.sleep(2)
self.show_welcome()
def handle_rfid(self, card_id):
"""处理RFID刷卡"""
print(f"[RFID] Card detected: {card_id}")
self.lcd.display_message("Reading Card...", card_id[:8])
self.led.processing()
self.buzzer.beep(0.05)
time.sleep(0.5)
# 验证卡片
valid, user = self.db.verify_rfid(card_id)
if valid:
self.grant_access(user)
else:
self.deny_access("Unknown Card")
def handle_pin_mode(self):
"""处理PIN码输入模式"""
print("[MODE] PIN input mode")
self.lcd.display_message("Enter Password:", "")
self.led.processing()
# 读取密码
success, pin = self.keypad.read_password(4, self.lcd, timeout=30)
if success:
valid, user = self.db.verify_pin(pin)
if valid:
self.grant_access(user)
else:
self.deny_access("Wrong PIN")
else:
self.lcd.display_message("Input Timeout", "")
time.sleep(1)
self.show_welcome()
def run(self):
"""主循环"""
self.show_welcome()
print("[READY] System running...")
print("Press 0-9=PIN, *=clear, #=confirm, B=RFID")
password = ''
while True:
key = self.keypad.scan()
if key:
self.buzzer.key_sound()
if key.isdigit():
if len(password) < 4:
password += key
self.lcd.display_message('Enter Password:', '*' * len(password))
self.led.processing()
print(f'[KEY] Input: {"*" * len(password)}')
if len(password) == 4:
time.sleep_ms(300)
valid, user = self.db.verify_pin(password)
password = ''
if valid:
self.grant_access(user)
else:
self.deny_access('Wrong PIN')
elif key == '*':
password = ''
self.lcd.display_message('Cleared', '')
time.sleep_ms(500)
self.show_welcome()
elif key == '#':
if password:
valid, user = self.db.verify_pin(password)
password = ''
if valid:
self.grant_access(user)
else:
self.deny_access('Wrong PIN')
else:
self.show_welcome()
elif key == 'A':
password = ''
self.lcd.display_message('Enter Password:', '')
self.led.processing()
elif key == 'B':
password = ''
self.lcd.display_message('Swipe Card', 'or press button')
self.led.standby()
elif key == 'D':
password = ''
self.lcd.display_message('System Status', 'Online OK')
time.sleep(2)
self.show_welcome()
card_id = self.rfid.read_card()
if card_id:
password = ''
self.handle_rfid(card_id)
time.sleep_ms(50)
# ==================== 程序入口 ====================
def main():
"""主函数"""
try:
controller = AccessController()
controller.run()
except KeyboardInterrupt:
print("\n[EXIT] System shutdown")
except Exception as e:
print(f"[ERROR] {e}")
# 启动
main()
LCD1602 Display (I2C)
4x4 Keypad
Buzzer
Relay (Door Lock)
Status LEDs
Simulate RFID Cards