☰
零知ESP32--4×4 矩阵键盘智能密码锁
2026/10/9 12:05:48 网站建设 项目流程

项目概述

本项目是一套基于 ESP32 的双通道智能密码锁:门锁侧用 4×4 矩阵键盘本地输入密码,手机侧通过低功耗蓝牙(BLE)远程开锁。锁舌由 SG90 舵机带动,ST7789 彩屏显示中文状态,无源蜂鸣器给出按键与结果提示。

固件以有限状态机组织界面与业务:上电欢迎 → 锁定待机 → 输密 / 改密 / 菜单 / 记录 / 访客 → 开锁成功与自动上锁 → 防暴力破解锁定。主密码与开锁记录写入 ESP32 片内 NVS(Flash),断电后仍保留。手机可用浏览器打开tools/ble_test.html,或按docs/app-inventor.md用 MIT App Inventor 自制 App。设备广播名为SmartLock。

适用场景是课程设计与功能演示:强调可复现的硬件、可拆分的代码和可操作的协议,而不是商用级加密门锁。


项目亮点

  • 双通道开锁:本地键盘与 BLE 远程共用同一套校验与锁定策略,访客另有 6 位一次性密码(24 小时有效、用过即废)。
  • 中文图形界面:自生成 16×16 点阵字库(FontCN.h),锁屏、倒计时、菜单、记录、访客密码均在 240×240 屏上完成,不必依赖串口。
  • 防暴力破解:连续 5 次错误进入锁定,初始 30 秒,再次触发时间加倍,最长 300 秒;剩余次数与倒计时同步推到屏幕和手机。
  • 记录可追溯:最近 64 条事件(本地 / 远程 / 访客,开锁、失败、上锁、生成访客密码)环形写入 NVS,屏幕分页浏览,手机可拉取并导出 CSV。
  • 低功耗取向:CPU 80 MHz、仅开 BLE、发射功率 −3 dBm、空闲约 20 秒关屏、舵机到位后断开 PWM,适合演示供电。
  • 模块化固件:键盘、蜂鸣器、舵机、安全、显示、蓝牙、日志各自独立头文件,主文件只负责状态机与协议分发。
  • 手机友好协议:16-bit UUID(FFF0/FFF1/FFF2),命令为短 ASCII 文本,兼顾网页 Web Bluetooth 与 App Inventor。

项目难点及解决方案

1. 输出脚选错导致舵机、蜂鸣器“完全没反应”
ESP32 的 GPIO34~39 只能输入,不能输出 PWM。早期若接到 34/35,现象是程序在跑、屏幕正常,锁和声音却毫无动作。解决办法:舵机固定 GPIO21、蜂鸣器 GPIO22,并在config.h用编译期#error拦住再次误用。

2. 键盘列脚与屏幕 SPI 冲突
ST7789 走 VSPI(时钟 18、MOSI 23)。若键盘占用 GPIO19(MISO)或 GPIO5(部分板卡默认 CS),会出现花屏、键值乱跳或上电异常。列脚改到 27、14、16、17,避开 VSPI 占用脚。

3. ST7789 旋转后画面左移、右侧留白
240×240 模组内部 CGRAM 往往带偏移。setRotation(4)时若colstart不对,有效像素会偏出可视区。正确做法是在 TFT_eSPI 的ST7789_Rotation.h中,240×240 的 rotation 4 分支设colstart = 80; rowstart = 0(并开启CGRAM_OFFSET)。该类库里colstart为私有成员,无法用子类可靠改写,必须改驱动头文件。

4. 倒计时全屏重绘导致闪烁
开锁 8 秒倒计时与锁定倒计时若每秒fillScreen,闪烁明显。显示层增加脏标记:界面切换全刷,倒计时仅markPartial(),只重画数字行。

5. 屏幕没有现成中文字库
TFT_eSPI 默认不含本项目文案。用tools/gen_font.py从黑体截取所需汉字,生成FontCN.h点阵,显示层按 UTF-8 查表绘制。

6. BLE 回调与主循环并发
手机写入发生在蓝牙协议栈任务中。用临界区把命令拷入缓冲,主循环takeCommand()再处理,避免在回调里驱动舵机、写 NVS、刷屏。

7. 记录要断电仍在,又没有 RTC
事件以打包结构体环形存 NVS;时间戳用累计秒(开机后累加,重启后接上次末条),屏幕显示为MM:SS。这不是墙钟时间,但能保证离线后再上电仍能翻看历史。


一、硬件系统部分

1.1 硬件清单

序号名称规格 / 说明数量
1零知ESP32 开发板3.3 V 逻辑,需引出 5 V 给舵机1
2零知ESP32 扩展板有引出接口,方便接线1
3ST7789 彩屏240×240,SPI;VCC 接 3.3 V1
44×4 矩阵键盘硬按键1
5SG90 舵机信号可接 3.3 V PWM,电源必须 5 V1
6无源蜂鸣器默认固件BUZZER_PASSIVE=1;有源需改宏1

1.2 接线方案

屏幕引脚写在 TFT_eSPI 的User_Setup中,固件不再重复定义。其余外设集中在SmartLock/config.h。

键盘、舵机、蜂鸣器

键盘金属面朝下、按键朝操作者时,排针从左到右一般为C1 C2 C3 C4 R1 R2 R3 R4。

器件线序ESP32
键盘行 R1~R4行输出GPIO32、33、25、26
键盘列 C1~C4列上拉输入GPIO27、14、16、17
SG90 橙 / 黄PWM 信号GPIO21
SG90 红电源5 V
SG90 棕地GND(必须与 ESP32 共地)
蜂鸣器信号PWM / 电平GPIO22
蜂鸣器地地GND

接线要点:

  1. 舵机不要接 3.3 V,电流不足会拖垮芯片,表现为复位或舵机抽动。
  2. 列线不要用 GPIO19、GPIO5,避免与 VSPI 冲突。
  3. 舵机、蜂鸣器不要用 GPIO34~39。
  4. 数字乱序时对调行/列线,或改KeypadScan.h中的map表。

1.3 硬件连接图

数据流:键盘 / BLE 产生“开锁或上锁”请求 → 主循环校验 → 舵机转到解锁角或锁定角 → 屏幕与蜂鸣器反馈 → 事件写入 NVS,并经 BLE Notify 回传手机。

1.4 实物连接图


二、软件架构设计

固件是单任务循环,外加 BLE 协议栈任务。业务全部在loop()中串行执行,模块之间通过对象方法交互,不使用操作系统队列。

手机 App / 网页 4×4 键盘 │ │ │ 写 FFF1 │ 行扫列读 ▼ ▼ BleLock::onWrite KeypadScan::read │ │ └────────┬────────────┘ ▼ SmartLock.ino 状态机 handleBleCommand / handleKey │ ┌───────────┼────────────┬─────────────┐ ▼ ▼ ▼ ▼ Security ServoLock Buzzer EventLog (NVS 密码) (LEDC PWM) (LEDC 音调) (NVS 环形) │ ▼ DisplayUI ← UiModel(每圈填充,按脏标记刷新)

核心状态(Mode)包括:Splash、Locked、Input、Fail、Success、Unlocked、Lockout、改密三步、Info、Logs、GuestView、Notice。显示层用平行的UiScreen枚举,由mapScreen()映射,避免 UI 直接依赖业务枚举。

2.1 系统初始化

setup()按依赖顺序启动外设,避免未初始化就刷屏或发蓝牙:

  1. setCpuFrequencyMhz(80):降频减功耗。
  2. 串口 115200,打印SmartLock boot,便于确认固件已跑起来。
  3. ui.begin():TFT 初始化、setRotation(4)、清屏。
  4. keypad.begin():行脚输出高、列脚上拉输入。
  5. buzzer.begin():无源则配置 LEDC,占空比先置 0。
  6. servoLock.begin():转到锁定角,延时后断开 PWM。
  7. eventLog.begin():从 NVS 命名空间evlog恢复环形缓冲与序号。
  8. security.begin():从smartlock读主密码与访客密码;非法长度则写入默认1234。
  9. ble.begin():设备名SmartLock,服务FFF0,写特征FFF1,通知特征FFF2,开始广播。
  10. 记录启动时刻,清空密码缓冲,标记全屏重绘。

上电后先停留在欢迎页SPLASH_MS(2200 ms),再进入锁定待机。

2.2 主循环逻辑

loop()每一圈完成六件事,顺序固定:

  1. BLE 维护:ble.loop()在断开后重新开始广播。
  2. 取命令:有写入则handleBleCommand()(状态查询、上锁、日志、访客、纯数字开锁、U:/C:)。
  3. 取按键:有键则handleKey(),按当前mode解释0-9 * # A B C D。
  4. 定时状态迁移:欢迎超时进锁定;失败/成功/提示页到时切走;锁定倒计时结束恢复待机;开锁满 8 秒自动上锁;输密超过 15 秒清空并返回锁定。
  5. 休眠与心跳:无操作满 20 秒且不在锁定中/已开锁/记录/访客等关键页时关屏;约每 400 ms 给倒计时页局部刷新;已连接时约每秒主动OK:STATUS:…。
  6. 渲染:fillModel()汇总密码掩码、剩余次数、倒计时、日志四行、访客码等,交给ui.render()。仅脏标记为真时才画。

自动上锁路径会转舵机、响锁定音、记一条上锁事件、通知OK:LOCKED,并弹出「已自动上锁」。蓝牙连上瞬间会OK:READY并立刻推一次状态,方便 App 刷新剩余次数。


三、代码拆分讲解

工程入口是SmartLock/SmartLock.ino,其余均为头文件模块,便于课程按文件讲解。

文件职责
config.h引脚、舵机角度、蜂鸣器类型与音调、密码策略、BLE UUID、界面色、编译期引脚检查
KeypadScan.h自行扫描 4×4,去抖并等松手,不依赖第三方 Keypad 库
Buzzer.h无源 PWM 音调 / 有源高低电平;点击、成功三音、失败、报警、上锁
ServoLock.h50 Hz、0.5~2.5 ms 脉宽映射 0~180°;到位可detach
Security.h主密码 NVS、失败计数与分级锁定、访客码生成/核销/过期
EventLog.h64 条环形日志、序号连续、格式化屏幕行与 BLE 行
DisplayUI.h中文绘制、状态栏、锁形图标、局部倒计时、睡眠命令
FontCN.h点阵字库(由tools/gen_font.py生成)
BleLock.hGATT 服务、写回调入队、Notify、断开再广播
SmartLock.ino状态机、开锁/上锁、键盘与 BLE 协议、UiModel 组装

3.1 键盘模块

逐行拉低,读列是否为低。确认按下后等待释放再返回字符,避免连发。键位表与实体键盘一致时,A上锁、B改密、C菜单、D清空才与说明书相符。

3.2 安全模块

verify()成功清零失败次数;失败累加,满 5 次按LOCKOUT_BASE_SEC << level进入锁定(封顶 300 秒)。改密必须旧密码正确,错误同样计入失败。访客码用esp_random()生成 6 位数字且避开主密码;consumeGuest()成功后置已用并写 NVS。注意:访客剩余时间以本次开机的millis()起算,重启后若密码尚未使用会重新按 24 小时计算。

3.3 日志模块

结构体含序号、累计秒、来源、类型、成败。缓冲区满则丢掉最旧一条。formatLine供屏幕(如#001 00:12 本地开锁),formatBle供手机(OK:LOG:序号,时间,来源,动作,结果)。

3.4 显示模块

markDirty()全刷,markPartial()只更新倒计时。睡眠发送 ST7789 的DISPOFF+SLPIN,唤醒SLPOUT+DISPON。按键或 BLE 活动会activity()唤醒。

3.5 蓝牙模块

FFF1 支持 Write 与 Write Without Response,兼容部分手机 GATT。FFF2 带 2902 描述符以便订阅通知。命令最长约 47 字节。

主文件协议摘要:

  • 手机写:纯数字或U:密码开锁;L上锁;S状态;H倒日志;G/GQ/GX生成、查询、作废访客;C:旧:新改密。
  • 设备通知:OK:STATUS:LOCKED|UNLOCKED|LOCKOUT:剩余次数:锁定秒;OK:UNLOCKED:远程;OK:GUEST:ACTIVE:密码:剩余秒;以及ERR:WRONG等。

四、操作过程及数据展示

4.1 操作步骤

编译与烧录

  1. 用 零知派 打开SmartLock/SmartLock.ino。
  2. 开发板选 零知ESP32;上传后打开串口,应看到SmartLock boot。
  3. 有源蜂鸣器把BUZZER_PASSIVE改为0,无源蜂鸣器把BUZZER_PASSIVE改为1。锁舌方向反了则对调SERVO_ANGLE_LOCKED与SERVO_ANGLE_UNLOCKED。

本地开锁 / 上锁

  1. 屏幕显示锁定与「蓝牙未连接 / 已连接」。
  2. 输入 4~8 位数字,*删一位,#确认。正确则舵机转到开锁角,提示成功来源「本地」,进入已开锁页并显示剩余秒数。
  3. 满 8 秒自动上锁,或按A/#立即上锁。
  4. 输错会减剩余次数;5 次后进入锁定页,倒计时结束才能再试。

修改主密码(键盘)

锁定界面按B→ 旧密码#→ 新密码#→ 再输入一次#。两次不一致会提示并回到新密码步。旧密码错误计入失败次数。

菜单、记录、访客(键盘)

按键作用
C进入菜单
1开锁记录(*较旧页,D较新页,#返回菜单)
2访客页:再按2生成,D作废,#返回
D(输入页)清空已输入数字

手机开锁(推荐网页)

  1. 用支持 Web Bluetooth 的浏览器打开tools/ble_test.html,扫描并连接SmartLock。
  2. 输入主密码或访客码,点开锁;可一键上锁、刷新状态。
  3. 页面会解析OK:STATUS,显示门锁状态、剩余次数、锁定倒计时。
  4. 可生成 / 查询 / 作废访客密码,拉取记录并导出 CSV。

App Inventor 制作步骤见docs/app-inventor.md。Android 扫描 BLE 通常需打开定位并授予附近设备权限。

忘记密码:零知派工具菜单擦除 Flash 后重新烧录,主密码恢复为DEFAULT_PIN。只改代码里的默认值而不擦除NVS,不会覆盖已经存过的密码。

4.2 数据展示(屏幕与协议)

屏幕典型信息:顶部蓝牙状态;锁定页密码圆点(错误时变红);已开锁页自动上锁秒数;锁定页剩余秒;记录页每行#序号 MM:SS 来源动作;访客页 6 位数字与剩余时间。

串口:KEY: 5、BLE: 1234等,便于对照操作。

状态通知示例:OK:STATUS:LOCKED:5:0表示已锁定、还可试 5 次、未在惩罚锁定。OK:STATUS:UNLOCKED:5:0为已开锁。OK:STATUS:LOCKOUT:0:28为惩罚锁定还剩 28 秒。

日志 BLE 流:OK:LOG:BEGIN:条数→ 多条OK:LOG:…→OK:LOG:END。网页可将记录与通信日志分别导出 CSV。

4.3 演示视频

零知ESP32--4×4 矩阵键盘智能密码锁


五、技术原理

5.1 工作原理

矩阵键盘:行作输出、列作上拉输入。某一键按下时,对应列被拉到该行的低电平,扫描到「行 r、列 c」后查表得到字符。去抖延时约 25 ms,并等待释放,保证一次按键只产生一个事件。

舵机:50 Hz 周期 20 ms。脉宽约 0.5 ms 对应 0°、2.5 ms 对应 180°。固件默认锁定 0°、开锁 90°。转到目标角后断开 LEDC,引脚拉低,减轻抖动与功耗。

无源蜂鸣器:LEDC 输出方波,频率决定音调。有源蜂鸣器则只拉高/拉低,忽略频率宏。

密码校验:开锁时先看访客码是否匹配且未过期、未使用;再比主密码。访客优先,避免与主密码冲突时的歧义(生成时已尽量避开主密码)。失败写入日志并可能进入 lockout。

BLE GATT:手机对 FFF1 写入 UTF-8 文本;设备对 FFF2 Notify。未做配对加密,附近设备理论上可嗅探明文,仅适合教学。连接后固件周期性推送状态,网页用 1 秒轮询S也可达到同样效果。

NVS:Preferences命名空间smartlock存pin、gpin、gused;evlog存二进制环形数组、条数与序号。擦除整片 Flash 会清空二者。

显示局部刷新:已开锁与惩罚锁定页数字每约 0.4 s 变化一次。若屏幕未变且仅秒数变化,只重绘倒计时区域,避免整屏闪烁。

5.2 工作模式配置

全部策略在config.h,按演示需求修改后重新编译即可。

宏默认值含义
PIN_MIN_LEN/PIN_MAX_LEN4 / 8主密码长度
DEFAULT_PIN"1234"仅 NVS 为空或非法时写入
MAX_FAIL_ATTEMPTS5连续失败次数上限
LOCKOUT_BASE_SEC30首次锁定秒数
LOCKOUT_MAX_SEC300锁定上限
AUTO_RELOCK_SEC8开锁后自动上锁
INPUT_TIMEOUT_MS15000输密超时回锁定
DISPLAY_SLEEP_MS20000无操作关屏
LOG_CAP64日志容量
GUEST_PIN_LEN6访客密码位数
GUEST_TTL_MS24 小时访客有效期
CPU_FREQ_MHZ80CPU 频率
BLE_TX_POWER−3 dBm广播发射功率
BLE_DEVICE_NAMESmartLock扫描名称
SERVO_ANGLE_LOCKED/UNLOCKED0 / 90锁舌角度
SERVO_DETACH_AFTER_MOVE1到位断开 PWM
BUZZER_PASSIVE11 无源,0 有源
TFT_ROTATION4屏幕方向

BLE UUID 亦可在 App Inventor 中填短形式FFF0、FFF1、FFF2。改设备名后需重新烧录,手机端按新名称扫描。


六、常见问题指引

现象可能原因与处理
花屏、偏色TFT_eSPI 中开关TFT_INVERSION_ON;确认ST7789_DRIVER且宽高为 240。
旋转后画面左移、右侧空白打开CGRAM_OFFSET;rotation 4 的 240×240 分支使用colstart=80,不要改成 0。
键盘无响应或乱码检查排针左右顺序;确认列脚不是 19/5;GPIO5 被按住可能影响启动,可上电后再接键盘。
舵机抽动、ESP32 反复复位5 V 供电不足,改外部 5 V 并共地;勿用 3.3 V 供舵机。
舵机、蜂鸣器完全没反应禁止 GPIO34~39;改回 21 与 22。
有源蜂鸣器一直响或不响BUZZER_PASSIVE 0;低电平触发再设BUZZER_ACTIVE_HIGH 0。
手机搜不到串口须有SmartLock boot,建议用EDGE浏览器打开;开手机蓝牙与定位;本设备是 BLE,不能用经典蓝牙串口助手。
能连不能开锁UUID 改完整 128 位;写入 UTF-8 且utf16=false;App Inventor 的WriteStrings必须传列表;可先发纯数字密码。
改密后忘记密码擦除 Flash 再烧录,恢复DEFAULT_PIN。
只改了代码里的1234仍是旧密码密码已在 NVS,需擦除或用改密流程覆盖。
访客时限重启后变回 24 小时未使用的访客码会保留,计时基准在开机时重置。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询