【嵌入式】外部中断的学习小坑记录

如果中断使用delay函数:

中断里的 HAL_Delay() 要等系统时基 tick 增加;而这个 tick 往往依赖 SysTick 中断。当前中断没退出时,SysTick 可能进不来,于是 HAL_Delay() 一直等,程序就卡住了。

这更像是:

中断里阻塞等待,结果把给它计时的人也堵住了。


所以应该怎么办?

中断里只做短、小、快的事

不要在中断里做:

  • HAL_Delay()
  • 长时间循环
  • 复杂计算
  • 串口长打印
  • 大量业务逻辑

那业务逻辑写在哪里?

一般分两层:

1)中断里:只做"事件登记"

比如:

  • 置一个标志位
  • 记录当前时间
  • 记录哪个按键来了
  • 极简单地翻一个状态

中断里适合做的是这种"快进快出"的事。


2)主循环 while(1) 里:做真正业务处理

比如:

  • 消抖
  • 判断长按短按
  • 切换 LED
  • 刷界面
  • 发串口
  • 状态机处理

所以大部分情况下,真正业务逻辑更推荐写在 mainwhile(1)


最推荐的模式

这种按键外部中断,标准思路是:

中断里

只告诉主循环:

"有一个按键事件来了。"

比如:

c 复制代码
volatile uint8_t key6_event = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_5)
    {
        key6_event = 1;
    }
}

主循环里

再真正处理:

c 复制代码
while (1)
{
    if (key6_event == 1)
    {
        key6_event = 0;

        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);
}

那中断里能不能直接写业务?

可以,但要满足一个条件:

这个业务必须非常短、非常快、不阻塞

比如这种就可以:

c 复制代码
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_5)
    {
        HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
    }
}

因为它只是翻转一个引脚,动作非常快。


所以到底怎么选?

情况1:逻辑特别简单

比如:

  • 按一下翻转一个 LED

可以直接写在中断里。


情况2:逻辑稍微复杂

比如:

  • 要消抖
  • 要判断长按短按
  • 要做延时
  • 要串口输出
  • 要修改多个状态

就不要全塞中断里,应该:

  • 中断里置标志
  • 主循环里处理业务

可以记一个经验法则

中断里做:

"通知"

while(1) 里做:

"处理"


为什么主循环更适合做业务?

因为主循环里:

  • 可以安全用 HAL_Delay
  • 可以慢慢判断状态
  • 不会长时间占住中断
  • 不容易影响别的外设响应

而中断里如果写太多,会带来这些问题:

  • 卡住别的中断
  • 响应变差
  • 调试困难
  • 出现这次这种"看起来死锁"的现象

例子1

c 复制代码
volatile uint8_t key6_pressed = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_5)
    {
        key6_pressed = 1;
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    while (1)
    {
        if (key6_pressed == 1)
        {
            key6_pressed = 0;

            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);
    }
}

小结

中断里不做阻塞延时,不做重业务;中断里只置标志,主循环里处理业务。

相关推荐
单片机仿真设计5 分钟前
【proteus仿真】基于 STM32 快递运输避障小车设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
lhbweilai7 分钟前
工业互联网(二)——USB 设备编程(一)
单片机·嵌入式硬件
山岚的运维笔记33 分钟前
mysql 专业笔记 -- 第 1 章:MySQL 入门
运维·数据库·笔记·后端·学习·mysql·dba
G***技1 小时前
IB3-771嵌入式主板6 TOPS真实算力怎么用:从PyTorch到RKNN的量化落地
人工智能·嵌入式硬件
国科安芯1 小时前
低轨卫星姿轨控系统中抗辐射MCU的选型依据与工程实践
单片机·嵌入式硬件·算法·架构·系统安全·低轨卫星·抗辐射
小弥儿1 小时前
GitHub今日热榜 | 2026-09-01:迷你小模型登场
学习·microsoft·开源·github
国科安芯1 小时前
卫星电源管理系统中高可靠MCU的功耗特性与电源监控功能分析
人工智能·单片机·嵌入式硬件·mcu·安全·电源管理系统·抗辐射
高亦真1 小时前
今天是学习嵌入式的第33天
linux·学习·算法
在线考试系统推荐1 小时前
拆成多道小题,优考试“理解题“怎么用?
服务器·人工智能·学习
2301_802651082 小时前
linux系统的学习:网络
linux·网络·学习