本节是通过外部中断实现按键检测的实战教程,并借助外部中断分析HAL中断处理流程

    开发环境:CubeMX+MDK5.27
    芯片型号:STM32F103ZET6
    时间:2020/07/15

    简介:本节讲具体讲解中断编程的步骤,以外部中断为例分析HAL库是如何处理中断的。

    中断编程的步骤:
    1.设置中断触发条件
    2.设置中断优先等级
    3.使能外设中断
    4.清除中断标志
    5.编写中断服务程序
    在这五个步骤中,前三个步骤可在CubeMX软件中完成配置,后两个步骤则可借助HAL库提供的函数完成。

    HAL库对中断的封装:
    1.在HAL库中统一规定了每个外设的中断服务函数为HAL_XXX_IRQHandler
    例如:串口的中断服务函数就是HAL_UART_IRQHandler、DMA的中断服务函数是HAL_DMA_IRQHandler
    定时器的中断服务函数就是HAL_TIM_IRQHandler。因此根据每个外设的名称,会有不同的中断服务函数,具体可以在stm32f1xx_it.c中查看。

    2.HAL库在中断服务函数HAL_XXX_IRQHandler中完成了中断标志的判断和清除,也就是说不需要用户自行编写判断中断是否发生的代码,这与标准库有很大区别,在标准库中,中断服务函数需要开发者自己编写判断是否发生中断的代码。

    3.HAL库讲中断中需要执行的操作以回调函数的形式提供给用户,开发者需要自行编写回调函数,在回调函数中编写的代码,会在产生响应的中断时执行。而在标准库中,开发者只需要在中断服务函数中编写相关代码,不需要编写回调函数。

    与中断相关的两个文件
    1.startup_stm32f103xe.s,这个.s结尾的文件是STM32的启动文件,在这个文件中可以看到很多以Handler结尾的函数,如图所示
    hd.png
    这些就是预先编写好的中断服务函数,但大多数都是死循环,目的只是为了初始化中断向量表。
    而中断函数后面的属性WEAK表示:如果该函数没有在其他文件中定义,则使用该函数,如果用户定义了该函数,那么使用用户定义的函数。

    2.stm32f1xx_it.c,这个文件存放在Application/User下,用于存放各个中断的中断服务函数,如果在使用CubeMX软件配置时,使能了某个外设的中断功能,那么在生成代码时,就会自动添加响应的外设中断服务函数到该文件中,如图是配置了USART1中断后,自动添加的内容
    u.png

    配置外部中断
    打开CubeMX软件,配置KEY1所在GPIO PE3为EXTI功能,如图所示
    KEY.png
    接下来配置PE3引脚外部中断功能如图
    ss.png
    此处配置GPIO mode为外部中断模式,触发方式选择下降沿触发(Falling edge trgger)
    GPIO Pull-up/Pull-down配置为Pull-up,表示默认情况下GPIO配有上拉电阻,即默认为高电平
    因为KEY1默认为高电平,当被按下后IO接地变为低电平,因此按键按下会产生一个下降沿。

    接下来,我们使能对应的外部中断线,如图
    ss.png

    再点击System Core下的NVIC外设,配置中断优先级,如图
    ss.png
    注:大多数情况下不必设置中断优先级,而直接使用由中断编号设置的默认中断优先级

    接着我们编写代码,实现按键控制LED1状态翻转
    在main.c的USER CODE BEGIN 4下添加回调函数**

    1. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    2. {
    3. if(GPIO_Pin == KEY1_EXTI_Pin)
    4. {
    5. HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
    6. }
    7. }

    编译工程,并烧录到开发板,按下按键1,LED1的状态就翻转一次。

    通过上述工程,分析HAL库外部中断处理流程:**
    1.中断跳转——跳转到该中断对应的中断服务函数,当引脚PE3上检测到下降沿时会触发中断,然后进入PE3产生的外部中断对应的中断服务函数EXTI3_IRQHandler

    2.执行中断服务函数——执行在stm32f1xx_it.c中对应的中断服务函数,如图
    irq.png
    执行中断服务函数EXTI3_IRQHandler,这个函数会调用外部中断通用处理函数HAL_GPIO_EXTI_IRQHandler

    3.执行外部中断通用处理函数HAL_GPIO_EXTI_IRQHandler,该函数代码如图
    irq.png
    该函数会先检测中断标志,然后清除中断标志,最后调用HAL_GPIO_EXTI_Callback回调函数完成具体的中断处理任务

    4.执行用户编写的回调函数HAL_GPIO_EXTI_Callback,在上述工程中,我们在main.c的USER CODE BEGIN 4下编写了外部中断的回调函数HAL_GPIO_EXTI_Callback并在其中调用HAL_GPIO_TogglePin改变LED1的状态。

    总结:**通过对外部中断的使用,我们了解到HAL库中断处理的流程——首先在软件中配置并使能外设的中断,接着当中断触发,会调用对应的中断服务函数,而中断服务函数中又会再调用HAL_XXX_IRQHandler处理各种外设的中断,完成中断标志的判断和清除,接着调用中断回调函数完成中断处理任务,而回调函数需要用户编写。与标准库相比,HAL库看似复杂实则是把过程更加流水线化,它只需要你编写回调函数即可,其余的判断中断是否发生以及清除中断标志都不需要用户来编写代码实现,而在标准库中,整个中断的处理都需要用户编写,连中断服务函数也需要用户自行添加到stm32f1xx_it.c中,你还需要编写判断中断是否发生的代码,以及具体的中断处理任务的代码。不过标准库因为资料丰富,可以直接COPY他人的现有工程,所以开发起来速度也还可以,但还是比不上HAL开发速度快。**