三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

STM32 门禁系统:看门狗设计与管理员菜单退出刷卡失效问题的解决

STM32 门禁系统:看门狗设计与管理员菜单退出刷卡失效问题的解决

STM32 门禁系统:看门狗设计与管理员菜单退出刷卡失效问题的解决

问题

智能门禁系统基本功能完成后,遇到了两个关键问题:

  1. 看门狗无法正常工作:IWDG 初始化卡死在 PVU 位等待,WWDG 超时时间太短不适用

  2. 管理员卡退出后刷不了卡:刷卡进入管理员菜单,按 ESC 退出后无法再次刷卡


一、看门狗方案选型与实现

方案对比

方案 结果 原因
IWDG ❌ 无法启动 LSI 时钟不稳定,PVU 位长期为 1
WWDG ❌ 超时太短 最大约 40ms,无法满足 ESP 初始化(30s)
软件看门狗 ✅ 成功 使用 TIM2 中断 + 软复位,超时可调

软件看门狗实现

核心思想:定时器中断检查喂狗标志,超时则执行 NVIC_SystemReset()

main.c 全局变量

TIM_HandleTypeDef htim2;
volatile uint8_t wdg_feed_flag = 0;

定时器初始化(1秒超时)

void MX_TIM2_Init(void)
{__HAL_RCC_TIM2_CLK_ENABLE();htim2.Instance = TIM2;htim2.Init.Prescaler = 7200 - 1;htim2.Init.Period = 10000 - 1;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_Base_Init(&htim2);HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);HAL_TIM_Base_Start_IT(&htim2);
}

中断回调

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM2) {if (wdg_feed_flag == 0) {NVIC_SystemReset(); // 超时复位} else {wdg_feed_flag = 0;}}
}

空闲任务喂狗

void StartDefaultTask(void const * argument)
{for(;;) {wdg_feed_flag = 1;osDelay(200);}
}

stm32f1xx_it.c 中断入口

void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim2);
}

关键点:启动顺序很重要——先喂一次狗再启动定时器,否则系统会在 FreeRTOS 启动前触发复位。

wdg_feed_flag = 1;
MX_TIM2_Init();
MX_FREERTOS_Init();
osKernelStart();

二、管理员卡退出后刷卡失效问题

问题现象

  • 密码进入管理员界面 → 退出 → ✅ 正常刷卡

  • 刷卡进入管理员界面 → 退出 → ❌ 无法刷卡

根因分析

调用链对比

密码进入:

Regular_User() → Regular_Admin() → 退出后返回 Regular_User 循环

刷卡进入(原始代码):

Uid_Read() → Regular_Admin() → 退出后 break → 退出 Uid_Read

问题Uid_Read 中管理员卡分支使用了 break 退出循环,导致 RC522 状态未正确恢复,且无法再次进入读卡流程。

解决方案

1. 在管理员菜单 ESC 退出时复位 RC522

// AdminOperation.c - Regular_Admin
else if (KEY_ESC == key){RC522_Reset();RC522_AntennaOn();return;
}

2. 在 Uid_Read 管理员卡分支添加 break 并让循环继续

else if(read_Admin == current || read_Admin_New1 == current){OLED_Clear();Regular_Admin();break; // 退出循环,让 StartRC522Task 继续
}

3. StartRC522Task 成功读卡后复位 RC522

if (RC522_ReadCardID(user_uid) == MI_OK) {Uid_Read();RC522_Halt();RC522_Reset(); // 保证状态干净RC522_AntennaOn();
}

4. 消除 Regular_User 的递归调用(避免栈溢出和卡顿)

// 原代码(递归调用)
}else if (key == KEY_ESC){Regular_User();
}
// 改为返回
}else if (key == KEY_ESC){return;
}

5. 在 Uid_Read 循环中添加延时(避免忙等导致卡顿)

void Uid_Read(void)
{while(1) {if(RC522_ReadCardID(user_uid) == MI_OK) {// 处理卡片...break;}osDelay(10); // 让出 CPU}
}

三、最终效果

问题 解决方案 效果
看门狗无法启动 软件看门狗(TIM2 + 软复位) ✅ 1秒超时自动复位
管理员卡退出后刷卡失效 退出时复位 RC522 + Uid_Read 退出循环 ✅ 退出后可正常刷卡
系统卡顿 消除递归调用 + 添加 osDelay ✅ 响应流畅

四、关键经验

  1. IWDG 依赖 LSI,如果 LSI 不稳定,考虑软件看门狗替代方案

  2. 看门狗启动顺序:必须在系统稳定后启动,否则会陷入复位循环

  3. RC522 状态管理:每次退出关键操作时主动复位,保证下次读卡正常

  4. 避免递归调用:在嵌入式系统中递归会大量消耗栈空间,应使用循环 + return

  5. 任务循环必须让出 CPUwhile(1) 中必须有 osDelay 或阻塞等待

← 返回列表