STM32L0xx复位引脚能否生成升降沿事件?实现短按复位长按恢复出厂设置
实现STM32L0xx复位引脚短按复位、长按加载出厂设置的方案
硬件电路设计
- 给复位按键增加一路GPIO采样:将复位按键的一端同时连接到
NRST引脚和一个普通GPIO(比如PA0) NRST引脚通过10kΩ上拉电阻连接到VDD,保证常态为高电平- 采样GPIO同样通过10kΩ上拉电阻连接到VDD,配置为输入模式
- 按键另一端接地,按下时同时拉低
NRST和采样GPIO
软件实现逻辑
1. 复位前的长按检测
在系统初始化最早期执行简洁的检测逻辑:
- 初始化采样GPIO为上拉输入模式
- 记录按键按下的起始时间,持续检测GPIO电平
- 若低电平持续超过2秒(长按阈值),则往**后备寄存器(BKP)**写入特定标记(如
0x12345678),随后手动触发系统复位 - 若为短按,硬件
NRST会直接触发复位,检测循环被打断
2. 复位后的初始化判断
系统重启后优先执行标记检查:
- 读取后备寄存器中的标记值
- 若标记存在:执行出厂设置加载逻辑(恢复Flash默认参数、重置配置变量等),随后清除标记
- 若标记不存在:进入常规初始化流程,正常启动系统
关键注意事项
- 后备寄存器(BKP)在硬件复位后不会丢失数据,适合存储标记;使用前需开启PWR时钟并解锁后备区域
- STM32L0的硬件复位要求
NRST低电平至少持续20ms,长按阈值需远大于该值(如2秒),避免误判 - 采样GPIO的检测逻辑要尽可能简洁,确保短按时能正常触发硬件复位
代码示例片段
写入出厂复位标记
#include "stm32l0xx_hal.h" void Set_Factory_Reset_Mark(void) { __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); // 解锁后备区域 HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, 0x12345678); // 写入标记到后备寄存器0 HAL_PWR_DisableBkUpAccess(); // 锁定后备区域 }
检查并处理标记
uint32_t Check_Factory_Reset_Mark(void) { __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); uint32_t mark = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0); HAL_PWR_DisableBkUpAccess(); return mark == 0x12345678 ? 1 : 0; } // 主函数入口 int main(void) { // 先执行长按检测 GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); uint32_t press_start = HAL_GetTick(); while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) { if(HAL_GetTick() - press_start >= 2000) { Set_Factory_Reset_Mark(); while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET); HAL_NVIC_SystemReset(); } } // 常规初始化 HAL_Init(); SystemClock_Config(); if(Check_Factory_Reset_Mark()) { Load_Factory_Defaults(); // 执行出厂设置加载 HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, 0x00000000); // 清除标记 } MX_GPIO_Init(); // 其他模块初始化... while(1) { // 主循环逻辑 } }
内容的提问来源于stack exchange,提问作者Daniel Nik
相关产品推荐
相关产品推荐

