你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

使用stm32C542做的低功耗密码锁示例

[复制链接]
云淼 发布时间:2026-9-30 14:01

STM32C5 EEPROM Emulation 密码锁示例

本工程基于 STM32C542RCT6,使用片上 EDATA Flash 模拟 EEPROM,并实现通过 USART2 串口交互的 6 位密码锁。密码正确时点亮 PA5 上的 LD1,约 5 秒后熄灭并进入 Standby;密码保存在EDATA区域,断电不丢失。

1. 芯片与系统配置

  • MCU:STM32C542RCT6。
  • 时钟:HSE 24 MHz,经 PSIS 输出 144 MHz。
  • HCLK/PCLK1/PCLK2/PCLK3 均为 1 分频,Flash latency 为 4 WS。
  • 使用 STM32C5 HAL/LL、CMSIS、EEPROM Emulation v2.1.0。
  • 构建:CMake + Ninja,预设为 debug_GCC_STM32C542RCT6。

mx_system_init() 依次初始化 HAL、NVIC、ICACHE、RCC、PWR、USART2、GPIO、TIM1、FLASH 和 CRC;关键初始化失败时 main() 返回 -1。

2. 外设设置

2.1 外设配置总览

外设/模块 关键配置 引脚/资源 主要用途
RCC HSE 24 MHz,PSIS/SYSCLK 144 MHz;AHB/APB 均 1 分频 系统时钟 为 CPU 和外设提供时钟
ICACHE 启用,HAL_ICACHE_IT_NONE 芯片内部 提高代码访问效率
USART2 115200、8N1、无流控、TX/RX PA2/PA3,AF7 串口提示、密码输入
LPDMA1_CH0 USART2 TX,内存到外设,字节宽度 USART2 TX 请求 DMA 发送支持
LPDMA1_CH1 USART2 RX,外设到内存,字节宽度 USART2 RX 请求 DMA 接收支持
GPIO 低速推挽输出,无上下拉 PA5/LD1 开锁状态指示
TIM1 预分频 14399,周期 0x1387,更新中断 TIM1_UPD,通道 3 LED 控制和开锁计时
PWR PVD、Flash 低功耗、Wakeup Pin 4 Wakeup Pin 4,高电平有效 Standby 唤醒
FLASH EDATA Flash 接口 FLASH_EDATA_BASE EEPROM 仿真数据存储
CRC 16 bit,多项式 0x109B,初值 0xFFFFFFFF CRC 外设 EEPROM 数据完整性校验
DWT 开启 CYCCNT Cortex-M 内部 统计 CPU 周期

上表是当前工程的配置速查,下面分别说明各外设的初始化方式及其在应用中的作用。

USART2 与 LPDMA1

USART2 用作密码锁终端:

参数 配置
TX/RX PA2/PA3,AF7
波特率 115200
数据格式 8N1,无硬件流控
方向 TX/RX
过采样 16 倍

LPDMA1_CH0 用于 USART2 TX(内存到外设),LPDMA1_CH1 用于 USART2 RX(外设到内存),均为字节传输并启用中断。工程另有 1024 字节环形发送队列和 UART_DMA_Send(),但当前 printf() 最终经 __io_putchar() 调用阻塞式 HAL_UART_Transmit();getchar() 也通过 __io_getchar() 阻塞接收。

GPIO、LED 与 TIM1

PA5 配置为低速推挽、无上下拉输出,LD1 高电平有效。由于 LED_PWM_MODE=1,LED 控制还会使用 TIM1 通道 3 输出比较。

TIM1 配置为内部时钟、向上计数,预分频 14399,周期 0x1387(4999),启用更新中断,优先级为抢占 0、子优先级 0。更新回调会:

  1. 调用 bsp_led_callback() 翻转 LD1;
  2. 调用 open_door_cunter_callback() 累计开锁计时;
  3. 计数达到 120 后进入 Standby。

PWR、低功耗与唤醒

mx_pwr.c 开启 PVD(EXTI line 16、上升沿)、Flash low-power mode 和 Wakeup Pin 4。Wakeup Pin 4 为高电平有效、无上下拉;同时保留 JTAG I/O(PA13、PA14、PA15、PB4)。

enter_standby() 会保存密码,清除 Wakeup Pin 4 和上次电源模式标志,然后调用 HAL_PWR_EnterStandbyMode()。主流程为:

mx_system_init -> App_Init -> 检查 Wakeup Pin 4
                               ├─ 已唤醒:App_Run -> 开锁 -> Standby
                               └─ 未唤醒:直接进入 Standby

FLASH、CRC 与 DWT

FLASH 由 mx_flash.c 初始化并提供给 EEPROM 仿真层。CRC 参数为:16 bit、多项式 0x109B、初始值 0xFFFFFFFF,输入和输出均不反转。CRC 用于仿真数据帧完整性校验。

sys_DWT.c 开启 DWT CYCCNT,App_Init() 用它统计初始化提示输出的 CPU 周期;DWT 不参与密码校验或存储。

3. 工程结构

3.1 工程文件结构图

Project08_EEPROM_emulation/
├─ main.c / main.h                           入口、系统初始化和主循环
├─ Application/
│  ├─ app/
│  │  ├─ app.c / app.h                       密码锁业务逻辑、低功耗流程
│  │  └─ callbacks.c / callbacks.h            UART/TIM 等 HAL 回调分发
│  ├─ bsp/
│  │  ├─ bsp_uart.c / bsp_uart.h              USART2 输出和 DMA 发送队列
│  │  ├─ bsp_led.c / bsp_led.h                LD1 控制
│  │  └─ bsp_BTN.c / bsp_BTN.h                按键消抖和事件识别
│  └─ tool/
│     ├─ sys_Data_Flash.c / sys_Data_Flash.h  EEPROM 读写二次封装
│     └─ sys_DWT.c / sys_DWT.h                DWT 周期计数
├─ generated/
│  ├─ hal/                                    RCC/PWR/GPIO/UART/TIM/FLASH/CRC 初始化
│  └─ utilities/                              EEPROM 配置和初始化入口
├─ utilities/
│  ├─ eeprom_emulation/                       EEPROM 核心、FLITF 算法、Flash/CRC 接口
│  └─ syscalls/                               printf/getchar 底层重定向
├─ stm32c5xx_drivers/                         STM32C5 HAL/LL 驱动
├─ arch/cmsis/                                 CMSIS 内核和设备支持
├─ user_modifiable/                            启动文件、链接脚本、构建上下文
├─ build/                                      CMake/Ninja 构建输出(本地生成)
├─ CMakeLists.txt / CMakePresets.json          构建配置
└─ Project08_EEPROM_emulation.ioc2             STM32CubeMX2 工程配置

生成代码负责芯片和外设初始化;Application 负责板级封装和业务逻辑;utilities/eeprom_emulation 提供通用 Flash EEPROM 仿真;sys_Data_Flash 提供业务层按虚拟地址读写的简单接口。

4. EEPROM Emulation 配置

配置文件:generated/utilities/eeprom_emul_conf.h。

宏 当前值 含义
EE_ALGO_FLITF 1 使用 FLITF 算法
EE_FRAME_LINE_SIZE 8 数据线大小 8 字节
EE_START_PAGE_ADDRESS 0x09000000 仿真页起始地址
EE_FLASH_BASE_ADDRESS FLASH_EDATA_BASE 使用 EDATA Flash
EE_FLASH_PAGE_SIZE FLASH_EDATA_PAGE_SIZE EDATA 页大小
EE_NB_OF_VARIABLES 1000 虚拟变量总数
EE_GUARD_PAGES_NUMBER 1 保护页数量
EE_CYCLES_NUMBER 1 仿真周期数

当前组合为 FLITF + EDATA + CRC;NVM、ECC 和模板接口虽在工程中保留,但未被当前配置选用。

初始化链路:

App_Init
  -> sys_Data_Flash_Init
     -> mx_eeprom_emulation_init
        -> 获取 mx_flash_gethandle / mx_crc_gethandle
        -> EE_Init(&mx_ee_object, EE_CONDITIONAL_ERASE)

EE_Init() 初始化 Flash/CRC 接口并恢复仿真页状态。EE_CONDITIONAL_ERASE 只在需要时擦除页面。FLITF 算法把变量记录追加到活动页,空间不足时搬移有效记录、擦除旧页并继续使用,用于模拟 EEPROM 更新并降低单页磨损。

业务层使用虚拟地址 1~6 保存密码的 6 个 ASCII 字节:

sys_Data_Flash_Write(1, password, 6);
sys_Data_Flash_Read(1, password, 6);

封装层实际逐字节调用 EE_WriteVariable8bits() 和 EE_ReadVariable8bits()。当写入返回 EE_INFO_CLEANUP_REQUIRED 时调用 EE_CleanUp() 回收旧页。

密码生命周期:

  1. RAM 初始密码为123456;
  2. App_Init() 初始化仿真后读取虚拟地址 1~6;
  3. 首次使用没有有效记录时打印读取错误,但默认数组仍可继续使用;
  4. 修改密码先只更新 RAM;
  5. 进入 Standby 前由enter_standby() 写回地址 1~6;
  6. 下次唤醒或复位时重新读取。

修改变量数量、起始地址、周期数或页配置后,应重新生成工程,并确认链接脚本、EDATA 区域和仿真页范围不冲突;虚拟地址必须位于 1~EE_NB_OF_VARIABLES。

5. 密码锁使用流程

5.1 上电与唤醒

  1. USART2 连接串口终端:115200、8N1、无流控;
  2. 下载并复位程序;
  3. 终端打印功能说明、默认密码和改密提示;
  4. 初始化后系统进入 Standby;
  5. 对 Wakeup Pin 4 施加配置的有效高电平,唤醒系统。

5.2 正常开锁

唤醒后执行 open_locked():

  1. 启动 TIM1 更新中断;
  2. 输入1 或其他字符选择显示方式:1 明文回显,其他字符隐藏为*;
  3. 输入 6 位当前密码并回车;
  4. 密码正确:打印成功信息、点亮 LD1,保持约 5 秒;
  5. 密码错误:打印失败信息并关闭 LD1;
  6. 打印待机提示并进入 Standby。

代码固定读取 6 次 getchar(),再清理换行;建议严格输入 6 个字符后回车,不要加入空格或额外字符。

5.3 修改密码

输入特殊密码 000000 进入改密:

  1. 输入000000;
  2. 输入新的 6 位密码;
  3. 新密码不能为000000;
  4. 再次输入新密码确认;
  5. 两次一致时打印Password is updated! 并更新 RAM;
  6. 随后进入 Standby 时写入 EEPROM 仿真区;
  7. 两次不一致时打印Password is not updated!,原密码不变。

修改成功不会立即单独写 Flash,而是在后续 enter_standby() 中保存;若保存前掉电,仍使用 Flash 中的原密码。

6. 构建与下载

cmake --preset debug_GCC_STM32C542RCT6
cmake --build --preset debug_GCC_STM32C542RCT6

已有构建目录时:

cmake --build build/debug_GCC_STM32C542RCT6

ELF 输出为 build/debug_GCC_STM32C542RCT6/Project08_EEPROM_emulation.elf。烧录后打开 USART2 终端即可测试。

7. 关键文件

文件 作用
main.c 初始化、唤醒判断、主循环
Application/app/app.c 密码校验、改密、开锁、Standby
Application/tool/sys_Data_Flash.c EEPROM 读写封装
generated/utilities/eeprom_emul_conf.h EEPROM 参数
generated/utilities/mx_eeprom_emulation_app.c EE_Init() 入口
utilities/eeprom_emulation/core/ 仿真核心和算法
utilities/eeprom_emulation/interface_flash/ EDATA Flash 接口
utilities/eeprom_emulation/interface_crc/ CRC 接口
generated/hal/mx_usart2.c USART2/LPDMA1
generated/hal/mx_tim1.c TIM1/更新中断
generated/hal/mx_pwr.c Standby/Wakeup 配置
utilities/syscalls/syscalls.c printf/getchar 重定向

8. 优化建议

8.1 优先修复的功能和可靠性问题

  1. 完善 EEPROM 错误处理:
    • 让sys_Data_Flash_Read/Write() 根据EE_INVALID_VIRTUALADDRESS、EE_ERROR_CORRUPTION、Flash 错误等返回真实状态;
    • App_Init() 读取失败时明确区分“首次使用”和“数据损坏”,必要时执行EE_Format() 或进入故障提示;
    • 写入密码后校验读回值,避免 Flash 编程失败仍被当作成功。
  2. 修正改密保存时机:当前改密成功后先修改 RAM,只有进入 Standby 前才写 Flash。建议改密成功后立即写入并读回校验,或者增加掉电保护状态,避免保存前掉电导致新密码丢失。
  3. 避免在中断中执行复杂业务:HAL_TIM_UpdateCallback() 只置位计时标志,在主循环中处理 Standby 和业务逻辑,减少中断执行时间。
  4. 统一返回值和参数校验:检查地址范围、长度是否为 6、空指针和 EEPROM 初始化状态,不要让底层失败最终仍返回SYS_DATA_FLASH_OK。

8.2 串口和交互优化

  1. 真正启用 UART DMA 发送:让_write() 调用UART_DMA_Send(),并处理环形缓冲区满的情况;这样连续printf() 不会逐字节阻塞 CPU。
  2. 增加接收状态机:目前getchar() 固定阻塞读取 6 个字符,建议改为中断/DMA 接收 + 行缓冲,支持退格、超时、回车结束和非法字符提示。
  3. 统一换行格式:串口输出统一使用\\r\\n,并为菜单、密码输入、结果和故障状态定义明确的提示文本。
  4. 加入输入超时和错误次数限制:长时间无输入时自动回到待机;连续输错达到阈值后锁定一段时间,降低暴力尝试风险。

8.3 低功耗与定时器优化

  1. 核对 Wakeup Pin 4 的实际引脚连接:README 和代码只能说明 HAL 的 Wakeup Pin 4 配置,硬件原理图仍需确认具体物理引脚和有效电平。
  2. 减少无意义的 TIM1 运行:仅在开锁交互或 LED 指示需要时启动 TIM1,进入待机前停止定时器并关闭无关时钟。
  3. 重新评估 LED 控制方式:若只需要常亮/熄灭,建议关闭LED_PWM_MODE,直接使用 GPIO,降低代码复杂度和功耗。
  4. 完善唤醒原因记录:进入待机前记录状态,唤醒后读取并打印唤醒源,便于区分首次上电、Wakeup Pin 唤醒和异常复位。

8.4 EEPROM 寿命与数据设计优化

  1. 只在数据变化时写入:写入前比较新旧密码,密码未变化时不产生新的 EEPROM 记录。
  2. 为密码增加版本、长度和校验字段:可将密码记录设计为结构体,例如magic + version + length + password + crc,便于升级和检测异常数据。
  3. 合理设置仿真容量:EE_NB_OF_VARIABLES=1000 远大于当前 6 个字节的需求;应根据实际变量数量、写入频率和寿命目标计算页数,避免占用不必要的 EDATA 空间。
  4. 明确格式化策略:量产产品不要随意启动时格式化;应提供受控的恢复出厂流程,防止误擦除密码。

8.5 安全性优化

  1. 不要明文保存密码:使用硬件安全能力、密钥派生后的摘要或加密存储;同时注意仅保存摘要时仍需支持密码验证。
  2. 删除或保护默认密码提示:当前默认密码和改密口令直接打印在串口上,只适合演示,不适合产品。
  3. 防止调试口泄露:量产时评估 JTAG/SWD、读保护、调试认证和 EDATA 访问权限。
  4. 增加安全擦除和恢复机制:密码重置应需要物理授权或受保护命令,不能只依靠公开的000000 特殊口令。

9. 注意事项

  • 密码以 ASCII 明文保存,没有加密;CRC 只提供完整性检查,不是安全存储。
  • 当前sys_Data_Flash_Read/Write() 对底层错误主要打印信息,量产代码应补充严格错误传播。
  • BTN_Scan() 当前未接入主循环或定时扫描;使用实体按键需要补充 GPIO、扫描周期及到Process_Button_Event() 的连接。
  • mx_*.c/.h 和eeprom_emul_conf.h 通常由 STM32CubeMX2 生成,修改配置应同步修改.ioc2/组件配置。
赞 收藏 评论0 发布时间:2026-9-30 14:01

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版