外部中断EXTI

单片机执行原理(暂时看不懂没事)

从抽象上看,==处理器系统==是一台能运算数据、操控内部状态、处理外部事件并与外部设备通信的机器。它的一切能力都依赖于代码,而代码由“指令”和“数据”构成;指令决定“做什么”,数据决定“用什么做”。

这些指令与数据都存放在==存储器==中。存储器按地址顺序编排,像在 C 语言里用指针访问内存那样可以被直接访问。它既能存放可执行的指令,也能保存运行时的数据;其中一部分地址被保留映射为寄存器空间,用于连接和控制外部设备,例如通信模块、调试组件或附加存储器。处理器通过访问存储器取回指令编码与数据,配合内部电路完成运算与状态更新,并将结果输出到外部世界。

然而,世界并不总按既定节拍运行。如果——我只是说如果——外部突然发生了意想不到的事件,带来了出乎意料的信息,处理器该如何即时应对?这便引出了下面要讲的核心机制——==中断==。它允许外部事件“打断”当前执行,转入专门的处理流程,以最快的方式给出响应。

怎样理解中断

清晨,工位灯亮起,白板上写着今天的主计划:加工云台支架→装配底盘→校准电机→联调发射机构(主程序/主循环)。lzc戴上手套拧上扭矩扳手,流程稳步推进:测量、钻孔、攻丝、装配(顺序执行)。

忽然,对讲机里传来“场地紧急停机!”(中断源,且为高优先级中断)。lzc立刻在工单上记下当前步骤、扭矩值与零件编号,等于给任务夹上书签(保存现场/入栈),小跑去测试场地,开始快速处置(进入==中断服务程序==/ISR)。他处理完问题在记录表上把这次警报打勾(清中断标志),随后回到工位按“书签”继续拧完那一颗螺丝(出栈返回/恢复现场)。

不一会儿,手机弹出取件码:定制齿轮到了(中断源,低优先级中断)。lzc暂停一下去门口签收、入库并贴标签(ISR只做关键动作),把“尺寸复检与啮合测试”留回主流程再做(回到主程序/主循环)。

签收途中,裁判系统终端又报警:某车小陀螺疯转(中断源,更高优先级中断),直接打断了刚才的快递流程(优先级与嵌套/NVIC)。lzc立刻赶到场边,用毯子将车逼停,随后把这件事压力给电控(清中断标志),再返回把快递流程收尾(出栈返回/恢复现场),最终回到装配主线(主程序/主循环)。

下午联调时,供弹扳机偶尔“连动两下”误报(抖动干扰)。lzc没有在ISR里大动干戈,只记录一次事件并清标志(ISR要短小+清中断标志),随后压力电控在主流程里加电容与软件滤波(去抖动),把“更换按钮/优化线束”安排成后续任务(主程序/主循环处理耗时工作)。

准备做关键总装扭矩前,他把手机与IM系统设为“仅安全员和测试台可打断”(屏蔽/使能中断),避免低优先级事务干扰;完工后再恢复正常通知(重新使能中断)。

一句话收束:机械组的一天,就是单片机中断的现场版——主计划稳步推进(主程序/主循环),突发情况按轻重插队(优先级与嵌套/NVIC);先记书签(保存现场/入栈),快进快出处理(ISR要点+清中断标志),再回到正事(出栈返回/恢复现场);必要时开“勿扰”(屏蔽/使能中断),偶发抖动就滤掉(去抖动)。

void Mech_Init(void);
void NVIC_Config(void);

void Assemble_Gimbal(void);
void Assemble_Chassis(void);
void Calibrate_Motors(void);



int main(void)
{
    Mech_Init();      // 机械组资源初始化(工装、工具、日志、台架…)
    NVIC_Config();    // 配置中断优先级与使能(仅示意)

    while (1)
    {
        Assemble_Gimbal();    // 装配/调校云台
        Assemble_Chassis();   // 装配底盘
        Calibrate_Motors();   // 校准电机

    }
}

void EmergencyStop_IRQHandler(void);   // 急停(高优先级)
void Alert_IRQHandler(void);       // 小陀螺异常
void PackageArrived_IRQHandler(void);  // 快递到货(低优先级)

工程配置

内容:完成使用按键控制LED的状态

在上次配置的基础上:

•根据原理图或PCB图,找到开发板上按键开关对应的单片机引脚。本系列教程STM32CubeMX基础实验采用的开发板中,按键开关对应的引脚为PB3

•将PB3设置为外部中断3号通道

•检测模式选择下降沿

•输入模式选择上拉输入,用于维持平时的高电平

•使能嵌套中断向量控制器

中断的两种优先级默认配置即可

屏幕截图 2025-10-12 105443

屏幕截图 2025-10-11 231853

硬件连接:

IMG20251011231335

代码讲解

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //中断回调函数
{
    switch(GPIO_Pin)
    {
        case KEY_Pin://检测是哪一个引脚发生了外部中断
            HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
            break;
        default:
            break;
    }
}
/* USER CODE END 4 */

虚函数VS实函数

屏幕截图 2025-10-12 105920

__weak

•本质上是一个宏定义

•实际上的文本对应是编译指令attribute((weak))

虚函数

•有虚函数指令__weak的函数声明

•虚函数可以有很多个

实函数

•没有虚函数指令__weak的函数声明,也就是普通的函数,都是实函数

•实函数至多有一个,多了会编译报错(如果是C++可以兼容函数重载)

•如果实函数存在,则用实函数

•如果实函数不存在,则随机选取一个幸运的虚函数(对我们而言是随机的,但对于编译器而言,也是有一定规则选取的)

程序流程

屏幕截图2025-10-12 111840

/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f1xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles EXTI line3 interrupt.
  */
void EXTI3_IRQHandler(void)//
{
  /* USER CODE BEGIN EXTI3_IRQn 0 */

  /* USER CODE END EXTI3_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(KEY_Pin); 处理外部中断线(EXTI)的 HAL 函数,在cubemx中配置后生成的,不是我们编写的
  /* USER CODE BEGIN EXTI3_IRQn 1 */

  /* USER CODE END EXTI3_IRQn 1 */
}
/**
  * @brief  This function handles EXTI interrupt request.
  * @param  GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)//检查是否发生外部中断,调用中断回调函数
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)//获取是否触发中断
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);//清除中断标志位
    HAL_GPIO_EXTI_Callback(GPIO_Pin);//调用中断回调函数
  }
}
/**
  * @brief  EXTI line detection callbacks.
  * @param  GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //虚函数,需要重新定义
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//自己实现的实函数
{
    switch(GPIO_Pin)
    {
        case KEY_Pin:
            HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
            break;
        default:
            break;
    }
}

前三段代码都不是自己要写的,都是在CubeMX中配置完就可以直接生成出来的配置代码。

Copyright © RM苍穹战队 all right reserved,powered by Gitbook该文件修订时间: 2025-11-05 23:12:57

results matching ""

    No results matching ""