如果中断使用delay函数中断里的HAL_Delay()要等系统时基 tick 增加而这个 tick 往往依赖 SysTick 中断。当前中断没退出时SysTick 可能进不来于是HAL_Delay()一直等程序就卡住了。这更像是中断里阻塞等待结果把给它计时的人也堵住了。所以应该怎么办中断里只做短、小、快的事不要在中断里做HAL_Delay()长时间循环复杂计算串口长打印大量业务逻辑那业务逻辑写在哪里一般分两层1中断里只做“事件登记”比如置一个标志位记录当前时间记录哪个按键来了极简单地翻一个状态中断里适合做的是这种“快进快出”的事。2主循环while(1)里做真正业务处理比如消抖判断长按短按切换 LED刷界面发串口状态机处理所以大部分情况下真正业务逻辑更推荐写在main的while(1)里。最推荐的模式这种按键外部中断标准思路是中断里只告诉主循环“有一个按键事件来了。”比如volatileuint8_tkey6_event0;voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_5){key6_event1;}}主循环里再真正处理while(1){if(key6_event1){key6_event0;HAL_Delay(20);// 消抖放这里不放中断里if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_5)GPIO_PIN_RESET){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);}}HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);HAL_Delay(500);}那中断里能不能直接写业务可以但要满足一个条件这个业务必须非常短、非常快、不阻塞。比如这种就可以voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_5){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);}}因为它只是翻转一个引脚动作非常快。所以到底怎么选情况1逻辑特别简单比如按一下翻转一个 LED可以直接写在中断里。情况2逻辑稍微复杂比如要消抖要判断长按短按要做延时要串口输出要修改多个状态就不要全塞中断里应该中断里置标志主循环里处理业务可以记一个经验法则中断里做“通知”while(1)里做“处理”为什么主循环更适合做业务因为主循环里可以安全用HAL_Delay可以慢慢判断状态不会长时间占住中断不容易影响别的外设响应而中断里如果写太多会带来这些问题卡住别的中断响应变差调试困难出现这次这种“看起来死锁”的现象例子1volatileuint8_tkey6_pressed0;voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_5){key6_pressed1;}}intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();while(1){if(key6_pressed1){key6_pressed0;HAL_Delay(20);// 消抖放主循环if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_5)GPIO_PIN_RESET){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);}}HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);HAL_Delay(500);}}小结中断里不做阻塞延时不做重业务中断里只置标志主循环里处理业务。
【嵌入式】外部中断的学习小坑记录
如果中断使用delay函数中断里的HAL_Delay()要等系统时基 tick 增加而这个 tick 往往依赖 SysTick 中断。当前中断没退出时SysTick 可能进不来于是HAL_Delay()一直等程序就卡住了。这更像是中断里阻塞等待结果把给它计时的人也堵住了。所以应该怎么办中断里只做短、小、快的事不要在中断里做HAL_Delay()长时间循环复杂计算串口长打印大量业务逻辑那业务逻辑写在哪里一般分两层1中断里只做“事件登记”比如置一个标志位记录当前时间记录哪个按键来了极简单地翻一个状态中断里适合做的是这种“快进快出”的事。2主循环while(1)里做真正业务处理比如消抖判断长按短按切换 LED刷界面发串口状态机处理所以大部分情况下真正业务逻辑更推荐写在main的while(1)里。最推荐的模式这种按键外部中断标准思路是中断里只告诉主循环“有一个按键事件来了。”比如volatileuint8_tkey6_event0;voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_5){key6_event1;}}主循环里再真正处理while(1){if(key6_event1){key6_event0;HAL_Delay(20);// 消抖放这里不放中断里if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_5)GPIO_PIN_RESET){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);}}HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);HAL_Delay(500);}那中断里能不能直接写业务可以但要满足一个条件这个业务必须非常短、非常快、不阻塞。比如这种就可以voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_5){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);}}因为它只是翻转一个引脚动作非常快。所以到底怎么选情况1逻辑特别简单比如按一下翻转一个 LED可以直接写在中断里。情况2逻辑稍微复杂比如要消抖要判断长按短按要做延时要串口输出要修改多个状态就不要全塞中断里应该中断里置标志主循环里处理业务可以记一个经验法则中断里做“通知”while(1)里做“处理”为什么主循环更适合做业务因为主循环里可以安全用HAL_Delay可以慢慢判断状态不会长时间占住中断不容易影响别的外设响应而中断里如果写太多会带来这些问题卡住别的中断响应变差调试困难出现这次这种“看起来死锁”的现象例子1volatileuint8_tkey6_pressed0;voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_5){key6_pressed1;}}intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();while(1){if(key6_pressed1){key6_pressed0;HAL_Delay(20);// 消抖放主循环if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_5)GPIO_PIN_RESET){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);}}HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);HAL_Delay(500);}}小结中断里不做阻塞延时不做重业务中断里只置标志主循环里处理业务。