模拟任务书
用 Touch 和按键构成二符号密码输入:Touch 表示 1,按键短按表示 0,按键长按确认。默认密码为 1011。连续三次错误后锁定 8 秒;正确后 GPIO21 输出高电平 5 秒并自动重新上锁。
- Touch 必须启动自校准并连续有效 50 ms 才接收。
- 密码长度允许 2–16 位,通过串口修改后写入 NVS。
- 锁定、解锁、输入和错误状态使用 RGB/蜂鸣器区分。
- 输入超过 16 位应清空并报错。
建议评分点
| 评分项 | 分值 |
|---|---|
| Touch 校准和抗误触 | 15 |
| 按键中断、短按与长按 | 15 |
| 二符号密码输入与验证 | 20 |
| 连续三错锁定 8 秒 | 15 |
| 解锁输出与自动上锁 | 10 |
| 密码修改及 NVS 保存 | 15 |
| 边界错误和状态提示 | 10 |
总分:100
直接使用
工程:arduino_pio/mock_08_touch_access。GPIO4 接导电片,按键接 GPIO15 与 GND,GPIO21 可接 LED 或驱动电路。
ENTER 1011
PASS 11001
ENTER 11001
LOCK
CLEAR
TOUCH CAL
STATUS主要修改:src/task_logic.cpp中的 appendBit()、verifyEntry() 和 tick()。
高概率变题
- 密码改为 Touch 短触/长触序列。
- 门禁改为布防/撤防或模式选择。
- 错误次数、锁定时间和解锁时间由串口设置。
- 要求掉电保存最后锁定状态或开门次数。
现场修改指南:密码值和长度必须成对
当前输入规则:按键短按输入 0,Touch 输入 1,长按确认;默认密码 1011,三错锁 8 秒,正确解锁 5 秒。现场只是改密码时,优先使用 PASS命令,不必改源码。
题目一句话对应哪里
| 题目关键词 | 函数/变量 | 作用 |
|---|---|---|
| 密码文本是否合法 | parseBits() | 只接受 2..16 位的 0/1 |
| 默认密码/解锁时间 | beginTask() | 设置 user1/user2/user4默认值 |
| 输入一位 | appendBit() | 把 0/1 加到当前输入末尾 |
| 核对密码/失败锁定 | verifyEntry() | 正确解锁,错误累计,达到次数进入 LOCKOUT |
| 按键/Touch 分别代表什么 | shortPress()、touchChanged() | 当前分别输入 0 和 1 |
| 确认 | longPress() | 调用 verifyEntry() |
| 自动上锁/锁定结束 | tick() | 比较截止时刻并控制输出 |
| 改密码 | command() | PASS设置并立即保存 |
变量翻译
| 代码 | 含义 |
|---|---|
user1 | 打包成整数的密码值,例如 1011 是 0b1011 |
user2 | 密码长度,例如 1011 长度是 4 |
user4 | 正确后保持解锁的毫秒数 |
entered_bits | 本次尚未确认的输入值 |
entered_length | 本次已经输入多少位 |
failed_attempts | 连续错误次数 |
state_deadline_ms | 自动上锁或错误锁定结束的时刻 |
最安全:不改代码也能改密码
| 现场要求 | 操作 |
|---|---|
| 密码改 11001 | PASS 11001,命令会立即保存 |
| 测试密码 | ENTER 11001 |
| 立即上锁 | LOCK |
| 清除输到一半的内容 | CLEAR |
| Touch 环境变化 | 无人触碰时执行 TOUCH CAL |
前导 0 陷阱:密码 0011 和 11 的整数值相同,但长度不同,所以必须同时保存 user1和 user2。
四种高概率变题:可直接照着改
示例 A:源码默认密码改为 11001
在 beginTask()中找到:
app.config().user1 = 0b1011;
app.config().user2 = 4;改为:
app.config().user1 = 0b11001;
app.config().user2 = 5;烧录后如果 NVS 已保存旧密码,新默认值不会覆盖有效配置。输入 FACTORY后,新默认值才会生效。
示例 B:交换输入,按键输入 1,Touch 输入 0
替换范围:完整替换三个输入回调;确认动作仍是长按。
void shortPress(contest::ContestApp &app) {
appendBit(app, 1);
}
void longPress(contest::ContestApp &app) {
verifyEntry(app);
}
void touchChanged(contest::ContestApp &app, bool active) {
if (active) appendBit(app, 0);
}同步修改:printHelp()中的 TOUCH=1、SHORT_BUTTON=0 也要交换,防止验收人员按错误规则输入。
示例 C:五次错误锁 15 秒,正确后解锁 10 秒
1. 在 beginTask()中把:
if (app.config().user4 == 0) app.config().user4 = 5000;改为:
if (app.config().user4 == 0) app.config().user4 = 10000;2. 在 verifyEntry()错误分支中把:
if (failed_attempts >= 3) {
app.setMode(LOCKOUT);
state_deadline_ms = millis() + 8000;
app.emit("ACCESS LOCKOUT MS=8000");
}改为:
if (failed_attempts >= 5) {
app.setMode(LOCKOUT);
state_deadline_ms = millis() + 15000;
app.emit("ACCESS LOCKOUT MS=15000");
}如果板子里已有旧的 user4=5000,修改默认值后要执行 FACTORY,否则仍使用旧保存值。
示例 D:正确后保持解锁,必须收到 LOCK 才重新上锁
修改范围:在 tick()开头删除下面整个自动上锁判断:
if (app.config().mode == UNLOCKED &&
static_cast<int32_t>(now_ms - state_deadline_ms) >= 0) {
app.setMode(LOCKED);
app.emit("ACCESS AUTO_LOCK");
}保留 LOCKOUT 到时恢复的第二个判断。串口 LOCK命令仍可强制上锁。
改完后的最短验收
- 先用
ENTER测试正确密码,再用实体 Touch/按键输入同一序列。 - 少一位、多一位和错误一位都必须拒绝,且每次确认后输入缓存清空。
- 连续输错到规定次数,锁定期间任何输入都应回复
ERR LOCKOUT。 - 等待锁定结束后再次输入正确密码,GPIO21 应按规定时间拉高。
- 修改密码并断电重启,使用新密码仍能解锁。
- 输入超过 16 位,必须清空并报错,不能覆盖内存。
不要改:parseBits()的长度保护和带符号截止时间比较。除非题目明确允许更长密码,否则不要把 16 位上限随意增大。