2026 ADI机器控制设计竞赛 - 基于ADMT4000模块设计的多圈密码转盘锁
该项目使用了ADMT4000 传感器+esp32 S3,实现了多圈密码转盘锁的设计,它的主要功能为:通过旋转带有磁铁的旋钮,ADMT4000 传感器实时捕捉绝对位置信息。主控芯片 **ESP32-S3** 对采集的数据进行解算,内部运行一个严谨的状态机,判断用户的旋转方向、转动圈数以及停止位置的刻度值。只有当用户严格按照预设的“方向 - 圈数 - 刻度”序列操作时,系统才会判定解锁成功,并通过WS2812灯和串口消息给予反馈。。
标签
嵌入式系统
测试
ADMT4000
Dijudicator
更新2026-05-11
5

2026 ADI机器控制设计竞赛 - 基于ADMT4000模块设计的多圈密码转盘锁

1. 所选任务介绍

本次项目任务名称为“多圈密码转盘锁”。核心目标是利用高精密多圈绝对值磁编码器 ADMT4000,模拟传统机械保险箱的拨盘解锁机制。与传统单圈角度传感器不同,本任务要求系统能够识别用户手动旋转的“圈数”和“最终角度”,通过预设的复杂序列(如:顺时针转 2 圈至刻度 5,再逆时针转 3 圈至刻度 8 等)来完成解锁。

系统需具备以下关键特性:

  • 多维输入识别:同时检测旋转方向、转动圈数(最高 46 圈)及停止位置的刻度值(0-9)。
  • 状态保持:具备断电记忆功能,意外断电或重启后,仍能保持当前的锁定/解锁状态及解锁进度。
  • 实时反馈:通过串口实时显示操作数据,并可选配 LED 提供视觉反馈。
  • 安全逻辑:输入错误立即重置,解锁后大幅度转动自动重新上锁。

2. 项目描述

本项目设计并实现了一套智能电子机械锁系统。系统摒弃了传统的矩阵键盘或触摸输入,转而采用更符合机械美学的“旋转拨盘”交互方式。

用户通过旋转带有磁铁的旋钮,ADMT4000 传感器实时捕捉绝对位置信息。主控芯片 ESP32-S3 对采集的数据进行解算,内部运行一个严谨的状态机,判断用户的旋转方向、转动圈数以及停止位置的刻度值。只有当用户严格按照预设的“方向 - 圈数 - 刻度”序列操作时,系统才会判定解锁成功,并通过WS2812灯和串口消息给予反馈。

若中途操作错误(如方向反了、圈数不够、微调时回退过多),系统将立即重置进度并要求从头开始。此外,项目引入了 非易失性存储(NVS),确保了锁具状态在掉电后不丢失,极大地提升了系统的实用性和安全性,完美复刻了真实保险箱的操作体验。

3. 简短的硬件介绍

本项目硬件架构简洁高效,主要包含以下核心组件:

  • 主控模块:ESP32-S3 开发板
    • 双核高性能 MCU,内置 Wi-Fi/蓝牙。
    • 拥有丰富的 GPIO 资源和完善的 peripherals(如 SPI, NVS, LED Strip 驱动),足以支撑复杂的逻辑运算、浮点计算和多任务处理。
  • 角度传感器:ADMT4000 多圈磁编码器
    • 核心器件。基于各向异性磁阻(AMR)技术,无需电池即可记录多达 46 圈 的旋转历史。
    • 通过 SPI 接口 通信,提供 高精度分辨率和高精度的圈数计数,是本项目实现“密码拨盘”功能的关键。
  • 反馈指示:WS2812B 可编程 RGB LED 灯
    • 用于直观展示系统状态:
      • 蓝色常亮:表示锁定状态。
      • 绿色常亮:表示解锁成功。
      • 红色闪烁:提示操作错误或重置。
      • 黄绿交替:提示步骤完成或微调中。
  • 其他组件
    • 径向永磁体:安装于旋钮内部,作为传感器的信号源。
    • 电源与连接:usb+杜邦线连接。

4. 方案框图 + 设计思路

4.1 方案框图

4.2 设计思路

系统上电后,首先初始化 SPI 总线与 ADMT4000 通信,读取故障寄存器确保传感器工作正常。随后从 NVS 加载上次保存的锁状态(是否已解锁、当前进行到第几步、解锁参考圈数)。

主循环中,程序以约 20ms 的频率轮询 ADMT4000 的绝对角度寄存器(0x03)和单圈角度寄存器(0x05),执行以下逻辑:

  1. 状态机管理:系统维护一个 current_step 变量。对于每一步,定义了两个关键参数:min_turns(最小转动圈数及方向)和 target_scale(目标刻度 0-9)。
  2. 过程检测
    • 圈数阶段:实时计算当前圈数相对于起始点的差值,判断是否满足方向和圈数要求。
    • 微调阶段:一旦圈数达标,进入“微调模式”,等待用户将角度对准目标刻度。
  3. 防误触与重置:在微调过程中,若检测到反向转动超过阈值,视为操作失误,立即调用重置函数清零所有进度。
  4. 解锁与重锁
    • 所有步骤完成后,标记为解锁状态,记录当前总圈数作为“参考点 (g_unlock_reference_turns)”。
    • 在解锁状态下,若检测到相对于参考点的转动超过半圈(0.5 圈),则自动重新上锁,模拟真实保险箱的关闭机制。
  5. 持久化:每完成一步或状态改变,立即写入 NVS 保存,确保断电不丢状态。

5. 原理图、PCB 设计

由于本项目侧重于算法验证与原型开发,硬件连接采用模块化插接方式,未专门设计 PCB。

硬件连接表

ESP32-S3 GPIO

ADMT4000 引脚

功能说明

GPIO_8

CS

片选信号

GPIO_15

MOSI

主机输出 (Master Out Slave In)

GPIO_17

MISO

主机输入 (Master In Slave Out)

GPIO_16

SCK

时钟信号

GPIO_18

COIL_RESET

线圈复位控制

GPIO_48

DIN

WS2812 LED 灯数据输入

3.3V / GND

VCC / GND

电源供电

这种连接方式灵活便捷,便于调试 SPI 通信时序和排查硬件故障。实际应用中可将其集成至小型 PCB 以缩小体积。

6. 软件流程图 + 调试软件说明 + 关键代码说明

6.1 软件流程简述

  1. 初始化:启动 NVS,加载历史状态,初始化 SPI 和 LED。
  2. 数据显示:根据当前状态(锁定/解锁/步骤中)打印提示信息。
  3. 数据采集:读取 ADMT4000 原始数据,转换为浮点型圈数(Turns)和刻度(Scale 0.0-9.9)。
  4. 逻辑判断
    • 若已解锁:监测转动幅度,若 |Current - Reference| > 0.5 圈,则执行 lock_lock()
    • 若锁定中:比对当前转动量与目标步长。
      • 圈数未够:持续监测方向和增量,若反向转动过大则重置。
      • 圈数已够:进入刻度比对,若误差 < 0.08 则进入下一步。
  5. 状态更新:每完成一步或状态改变,写入 NVS 保存。
  6. 循环延时:短暂延时后进入下一轮循环。

6.2 调试软件说明

使用 ESP-IDF 自带的 idf.py monitor 串口监视工具(波特率 115200)。

  • 动态仪表盘:代码利用 ANSI 转义码实现终端界面的局部刷新。show_real_time_status 函数实时显示“当前步骤”、“已转圈数”、“剩余圈数”、“当前刻度”及“误差值”,提供了类似仪表盘的调试体验,无需滚动查看历史日志。
  • 状态日志:关键事件(解锁成功、错误重置、NVS 读写)均通过 ESP_LOGI 输出带标签的日志。

6.3 关键代码深度解析

A. 多圈角度到“密码盘刻度”的映射算法

ADMT4000 输出的是连续的浮点圈数(例如 12.345 圈),而传统密码锁需要的是 0-9 的表盘刻度。核心转换函数 get_scale_from_turns 实现了这一逻辑,并引入了软件校准机制

float get_scale_from_turns(float turns) {
   // 1. 应用校准偏移:消除机械安装时的初始角度误差
   // g_scale_offset 是通过实验测得的常数,确保物理 0 位对应逻辑 0.0
   float corrected_turns = turns - g_scale_offset;
   
   // 2. 提取小数部分:只关心当前在第几圈的什么位置,不关心总圈数
   float fraction = corrected_turns - floorf(corrected_turns);
   
   // 3. 处理负数情况:C 语言的取整对于负数行为特殊,需强制归一化到 [0, 1)
   if (fraction < 0) fraction += 1.0f;
   
   // 4. 映射到 0-10 刻度:小数部分 * 10 即对应表盘刻度 (0.0 ~ 9.9)
   float scale = fraction * 10.0f;
   
   // 5. 边界保护:防止浮点误差导致 scale 等于 10.0
   if (scale >= 10.0f) scale -= 10.0f;
   if (scale < 0) scale += 10.0f;
   
   return scale;
}

技术亮点:该算法不仅完成了单位转换,还通过 g_scale_offset 变量解决了传感器安装无法绝对对齐物理零点的问题,无需调整硬件即可通过软件修正精度。

B. 基于状态机的密码验证逻辑

解锁过程被建模为一个严谨的状态机,核心在于区分“圈数验证阶段”和“刻度微调阶段”,并通过 g_turns_verified 标志位进行切换。

// 阶段一:圈数与方向验证
if (!g_turns_verified) {
   bool direction_ok = false;
   // 根据预设密码的正负值判断目标方向 (正:顺时针,负:逆时针)
   if (required_turns > 0) {
       if (total_delta >= required_turns) direction_ok = true;
  } else {
       if (total_delta <= required_turns) direction_ok = true;
  }
   
   if (direction_ok) {
       // 圈数达标,锁定峰值,进入微调模式
       g_turns_verified = true;
       g_peak_delta = total_delta;
       printf("\n[OK] 圈数达标!请微调对准刻度 %.0f...\n", target_scale);
  } else {
       // 错误检测:若在未达到目标前就向反方向转动超过阈值,视为作弊/误操作
       float wrong_dir_threshold = 0.5f;
       if ((required_turns > 0 && total_delta < -wrong_dir_threshold) ||
          (required_turns < 0 && total_delta > wrong_dir_threshold)) {
           reset_lock_progress(); // 立即重置所有进度
      }
  }
}
// 阶段二:刻度微调与防回退检测
else {
   float scale_diff = fabs(current_scale - target_scale);
   // 处理刻度跨越 0/10 边界的情况 (如从 9.9 到 0.1)
   if (scale_diff > 5.0f) scale_diff = 10.0f - scale_diff;
   
   if (scale_diff <= SCALE_TOLERANCE) {
       // 精度满足要求,判定本步成功
       g_current_step++;
       // ... (进入下一步或解锁)
  } else {
       // 防回退机制:在微调阶段,如果往回转动超过惩罚阈值,重置
       bool is_reversing = false;
       if (required_turns > 0) {
           if (total_delta < g_peak_delta - REVERSE_PENALTY_THRESHOLD) is_reversing = true;
      } else {
           if (total_delta > g_peak_delta + REVERSE_PENALTY_THRESHOLD) is_reversing = true;
      }
       
       if (is_reversing) {
           printf("\n[错误] 检测到回退!重置...\n");
           reset_lock_progress();
      }
  }
}

技术亮点

  1. 分段验证:先确认“转够了没”,再确认“停准了没”,符合人类操作保险箱的逻辑。
  2. 防回退惩罚:引入 REVERSE_PENALTY_THRESHOLD,允许用户手抖微调,但禁止大幅度的反向回转,有效防止暴力试探密码。
  3. 环形刻度处理:在计算刻度误差时,专门处理了 9.90.1 的跨零边界情况,确保算法在表盘首尾连接处的正确性。

C. NVS 非易失性存储(断电记忆)

为了实现“断电后状态保持”,项目使用了 ESP32 的 NVS (Non-Volatile Storage) 分区。关键在于保存三个核心变量:unlocked (是否已解锁), step (当前进行到第几步), ref_turns (解锁时的参考圈数)。

void save_lock_state_to_nvs(bool unlocked, int step, float ref_turns) {
   nvs_handle_t nvs_handle;
   // 以读写模式打开命名空间
   esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
   if (err != ESP_OK) return;
   
   // 1. 保存布尔状态 (转为 uint8_t)
   nvs_set_u8(nvs_handle, NVS_KEY_UNLOCKED, unlocked ? 1 : 0);
   
   // 2. 保存当前步骤索引
   nvs_set_u8(nvs_handle, NVS_KEY_STEP, (uint8_t)step);
   
   // 3. 保存浮点数参考圈数 (使用 blob 类型存储 float)
   nvs_set_blob(nvs_handle, NVS_KEY_REF_TURNS, &ref_turns, sizeof(float));
   
   // 4. 提交事务,确保数据写入 Flash
   nvs_commit(nvs_handle);
   nvs_close(nvs_handle);
}

恢复逻辑:在 lock_task 启动初期,系统会调用 load_lock_state_from_nvs

  • 若读取到 unlocked=true,系统直接进入“监控重锁”模式,不再要求输入密码,直到转动幅度超过 RELOCK_THRESHOLD (0.5 圈)。
  • 若读取到 unlocked=falsestep > 0,系统会提示“继续第 X 步操作”,允许用户在断电后从中断处继续解锁,极大提升了用户体验。

D. 自动重锁机制(看门狗逻辑)

在解锁状态下,系统并非永久开放,而是监测相对于解锁时刻的累计转动量。

if (g_is_unlocked) {
   // 计算当前圈数与解锁时记录圈数的绝对差值
   float total_turn_distance = fabs(current_turns - g_unlock_reference_turns);
   
   // 更新上一次采样值用于瞬时速度计算 (可选)
   g_last_unlock_turns = current_turns;
   
   // 核心判断:若累计转动超过半圈 (0.5),判定为关门动作,触发重锁
   if (total_turn_distance > RELOCK_THRESHOLD) {
       printf("\n[自动锁定] 检测到累计转动%.3f圈 > %.1f圈,锁已重新锁定\n",
              total_turn_distance, RELOCK_THRESHOLD);
       lock_lock(); // 执行重锁流程:清零状态、保存 NVS、LED 报警
  }
}

技术亮点:此逻辑模拟了真实机械锁的“关门即上锁”特性。g_unlock_reference_turns 作为锚点,确保了即使用户在解锁后随意旋转,只要幅度不大(如在开门状态下微调),不会误触发重锁;一旦大幅度旋转(模拟关门),立即安全锁定。

E. 异常处理与系统复位

reset_lock_progress 函数是系统的“安全熔断机制”。当检测到方向错误、回退过多或超时等异常情况时调用。

void reset_lock_progress() {
   // 1. 软件状态清零
   g_current_step = 0;
   g_turns_verified = false;
   g_peak_delta = 0.0f;
   g_last_turns = -999.0f; // 设为无效值,迫使主循环在下一次重新捕获起始点
   
   // 2. 持久化清零:确保即使此时断电,重启后也是重置状态
   save_lock_state_to_nvs(g_is_unlocked, g_current_step, g_unlock_reference_turns);
   
   // 3. 硬件反馈:LED 红色闪烁报警
   for (int i = 0; i < 4; i++) {
       led_strip_set_pixel(led_strip, 0, 60, 0, 0); // Red
       led_strip_refresh(led_strip);
       vTaskDelay(150 / portTICK_PERIOD_MS);
       led_strip_set_pixel(led_strip, 0, 0, 0, 0);   // Off
       led_strip_refresh(led_strip);
       vTaskDelay(150 / portTICK_PERIOD_MS);
  }
}

技术亮点:不仅重置内存变量,还同步更新 Flash 中的 NVS 数据,并配合 LED 视觉反馈,形成了完整的“检测 - 执行 - 反馈”闭环,防止系统在错误状态下卡死。

7. 实物演示及说明

在实际演示中,将磁铁固定在旋钮中心,正对 ADMT4000 传感器表面(间距约 2-5mm)。

  • 上电初始:LED 呈蓝色呼吸状,串口显示“系统已锁定,请输入密码”,并列出第一步指令(如:顺时针 1.0 圈 -> 刻度 6)。

  • 操作过程:用户顺时针旋转旋钮。串口实时跳动显示“已转:+0.xx 圈”。当圈数超过 1.0 时,提示“圈数达标,请微调”。用户缓慢回旋至刻度 6.0 附近,当误差进入容许范围,LED 变为黄绿交替闪烁,串口提示“第 1 步完成”,并自动进入第 2 步指令。

  • 错误测试:若在第一步未完成时反向旋转,LED 立即快速闪烁红色,串口报错“检测到反向转动!重置”,进度归零。
  • 解锁成功:完成所有预设步骤后,LED 转为绿色常亮,串口打印“>>> 解锁成功! <<<”。

  • 断电测试:在解锁状态下断开电源再重新上电,系统依然保持绿色常亮,并提示“转动超过半圈将自动锁定”,验证了 NVS 存储的有效性。

8. 遇到的难点及解决方法

  • 难点一:刻度校准与机械误差
    • 问题:理论上的 0 刻度与实际传感器读数存在固定偏差,导致无法精确对准。
    • 解决:引入全局变量 g_scale_offset。在调试阶段,先读取传感器在物理 0 位的数值,计算出偏差量填入代码,实现了软件层面的精准校准,无需反复拆装硬件和复位。
  • 难点二:抖动与误判
    • 问题:用户在接近目标刻度时手抖,导致数值在阈值边缘跳变,引发状态反复切换。
    • 解决:增加了 SCALE_TOLERANCE(容差范围,设为 0.08)和 REVERSE_PENALTY_THRESHOLD(回退惩罚阈值)。只有当稳定处于容差范围内才判定成功;且允许微小的往复抖动,只有明显的反向大动作才触发重置。
  • 难点三:多圈数据的连续性处理
    • 问题:ADMT4000 输出的是绝对圈数,但在计算“相对转动量”时,若直接相减可能因噪声产生跳变。
    • 解决:在每一步开始时记录 g_step_start_turns 作为基准,后续所有计算均基于 current_turns - g_step_start_turns 的差值,有效隔离了绝对位置噪声的影响。
  • 难点四:刻度跨零计算
    • 问题:当目标刻度为 0 或 9 附近时,简单的减法会导致误差计算错误(如 9.9 到 0.1 的实际误差很小,但直接相减很大)。
    • 解决:在计算 scale_diff 时加入逻辑判断:if (scale_diff > 5.0f) scale_diff = 10.0f - scale_diff;,正确处理了圆环刻度的最短路径问题。

9. 对本次活动的心得体会

首先,传感器选型决定上限。ADMT4000 强大的多圈计数能力是实现复杂密码逻辑的基础,如果仅用普通电位器或单圈编码器,该项目将变得复杂。

其次,状态机思维至关重要。面对复杂的交互逻辑(方向、圈数、刻度、断电恢复、自动重锁),采用清晰的状态机模型(锁定、验证圈数、验证刻度、解锁、重锁)让代码结构井然有序,避免了大量的 if-else 嵌套陷阱,提高了代码的可读性和可维护性。

最后,感谢本次竞赛的主办方及 ADI ,提供了如此宝贵的实践平台和像 ADMT4000 这样新颖的元器件支持。


软硬件
电路图
附件下载
2026 ADI机器控制设计竞赛 - 基于ADMT4000模块设计的多圈密码转盘锁.zip
main.c
mima.c
mima.h
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号