“嵌入式开发遇上诡异Bug,你咋翻盘的?”
嵌入式开发里,Bug总冒得莫名其妙,栈溢出、指针跑飞啥都有。你们碰过啥玄学Bug?是靠打印日志磨出来的,还是调试器硬刚?快来吹吹你的翻盘神技,或者吐槽哪次Bug整得想退行!
其实在嵌入式里开发会遇到很多的BUG,而且还是那种找不到原因或者很难排查的现象,下面我来分享一下,我曾经遇到过的嵌入式开发遇到的一下比较不好弄的BUG和处理办法。
现象:产品是扫地机,设备运行一段时间后突然死机,重启后又能正常工作一段时间,但问题会反复出现,而且有时不会出现,有时会出现。
想到的解决的办法
1、一开始以为是代码逻辑问题,疯狂加日志,拼命的打断点,想看看程序到底卡在哪一步。结果发现,每次崩溃前,日志里都有一个定时器超时的记录,但这个定时器明明设置了合理的超时时间。
2、使用灯来查看现象在哪一步出现问题时,对应 的灯哪个就会亮。
仔细检查了定时器的配置代码,发现没有问题。当我用调试器单步跟踪时,发现定时器的中断服务函数里竟然有一个耗时很长的操作,然后一直在累加,而且有时还影响看门狗工作,而且中断里的时间蛮长。
后面经过自己的分析嵌入式系统的中断服务函数应该尽量简短,不能有耗时操作。因为中断服务函数会阻塞其他中断,如果处理时间过长,就可能导致系统崩溃。这个Bug就是因为定时器中断服务函数工作时间很长,导致系统响应不及时,最终崩溃,导致有时来不及清狗。
最后把看门狗在进行定时器和中断时先清,然后把中断里的配置精简,没有必要的就移到外面,最终解决了问题。
代码
// 全局变量与宏定义
volatile uint8_t timer_flag = 0; // 中断触发标志
#define WDT_TIMEOUT_MS 1000 // 看门狗超时时间
#define TASK_INTERVAL_MS 100 // 主任务执行间隔
// 精简后的定时器中断服务函数
void TIM2_IRQHandler(void) {
if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET) {
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); // 清除中断标志
// 仅做必要操作:设置标志位,耗时操作移至主循环
timer_flag = 1;
// 在中断中安全清狗(需确保清狗时间 < WDT超时时间)
HAL_IWDG_Refresh(&hiwdg);
}
}
// 主循环任务处理
void process_main_tasks(void) {
static uint32_t last_task_time = 0;
uint32_t now = HAL_GetTick();
if (timer_flag) {
timer_flag = 0;
// 执行实际耗时操作(原中断中的内容)
// 例如:传感器数据采集、复杂计算等
// ...
}
// 主循环清狗(双重保护)
if (now - last_task_time >= TASK_INTERVAL_MS) {
HAL_IWDG_Refresh(&hiwdg);
last_task_time = now;
}
}
// 初始化函数
void system_init(void) {
HAL_Init();
MX_TIM2_Init(); // 初始化定时器(1ms中断)
MX_IWDG_Init(); // 初始化独立看门狗(超时1s)
HAL_TIM_Base_Start_IT(&htim2);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
解释一下
定时器周期:
根据需求调整定时器中断周期,1ms用于高频控制,10ms用于数据采集。
看门狗超时:
保证 看门狗大于主循环最大可能阻塞时间多少MS的任务周期。
中断优先级:
设置定时器中断优先级高于其他非关键中断,但低于看门狗的优先级。
|