MCU开发学习记录5 - 中断学习与实践(HAL库) - KEY实现EXTI中断 - STM32CubeMX

名词解释:

NVIC:​Nested Vectored Interrupt Controller
SCB:System Control Block
EXTI:External Interrupt/Event Controller
LSM:Light Sensor Module
CPU:Central Processing Unit
IRQ:Interrupt Request
ISR:Interrupt Service Routine
ISER:Interrupt Set Enable Registers
ICER:Interrupt Clear Enable Registers
ISPR:Interrupt Set Pending Registers
ICPR:Interrupt Clear Pending Registers
IABR:Interrupt Active Bit Registers
IPR:Interrupt - Priority Registers
ICSR:Interrupt Control and State Register
VTOR:Vector Table Offset Register
AIRCR:Application Interrupt / Reset Control Register
SHPR:System Handler Priority Registers
TBLBASE:Table Base Select Bit

IMR:Interrupt mask register
EMR:Event mask register
RTSR:Rising trigger selection register
FTSR:Falling trigger selection register
SWIER:Software interrupt event register

APB:Advanced Peripheral Bus

        本文将对中断的概念、NVIC的基础知识、EXTI的基础知识、STM32CubeMX生成EXIT的配置函数以及对生成EXIT的配置函数进行分析(包括结构体配置、相关寄存器配置)。最后针对于EXTI的功能,利用KEY输入引脚配置成EXIT,使LED0状态翻转进行实践。

        这部分不太好写,如果本文哪里有问题或者补充,欢迎在评论区指正。

1. 中断

1.1 什么是中断?

        中断(Interrupt)​ 是计算机或嵌入式系统中一种事件驱动的响应机制。当发生需要立即处理的紧急事件(如硬件信号、软件请求或异常)时,CPU ​暂停当前任务,​转去执行特定的处理程序,完成后恢复原任务。中断是实现实时性、多任务协作和高效资源利用的核心技术。

        The Cortex -M processors have a number of programmable registers for managing
interrupts and exceptions. Most of these registers are inside the NVIC and System
Control Block (SCB).

1.2 中断工作流程

  1. 外设 ->> 中断控制器:发送中断请求(IRQ)
  2. 中断控制器 ->> CPU:通知有中断待处理
  3. CPU ->> CPU:完成当前指令,保存上下文(压栈)
  4. CPU ->> 中断控制器:获取中断向量号
  5. 中断控制器 ->> CPU:返回中断服务程序(ISR)地址
  6. CPU ->> 内存(ISR):跳转执行ISR
  7. 内存(ISR) ->> 外设:处理事件(如读取数据)
  8. 内存(ISR) ->> 中断控制器:清除中断标志
  9. CPU ->> CPU:恢复上下文(弹栈)
  10. CPU ->> 原任务:继续执行被中断的代码

1.3 中断补充知识

1.3.1 MCU reset,中断?

  1. 所有中断都会disabled
  2. 所有中断赋予优先级值为0(最高优先级)
  3. 所有中断的状态标志位清零

1.3.2 CPU接收中断请求条件?

  1. 中断标志位置1
  2. 中断使能
  3. 中断优先级大于屏蔽中断优先级

1.4 中断注意点

  1. 中断屏蔽:通过寄存器(如 PRIMASK)临时关闭中断,保护关键代码(临界区)。
    // 关闭所有中断(设置PRIMASK=1)
    __disable_irq();  // 关闭全局中断
    // 临界区操作(如修改全局变量)
    // 开启中断(设置PRIMASK=0)
    __enable_irq();   // 恢复中断
  2. 中断嵌套:高优先级中断可打断低优先级中断(需配置抢占优先级)。
  3. ​中断延迟:从触发中断到执行 ISR 第一条指令的时间,影响实时性。

2. NVIC

2.1 什么是NVIC?

2.1.1 NVIC概念与结构框图

Nested vectored interrupt controller,嵌套向量中断控制器。

  • 全局管理所有中断源的优先级、使能和响应

  • 处理中断仲裁、跳转到ISR地址等核心操作

  • 属于内核级中断管理​(Core-Level Control)

  1. IRQs(Interrupt Requests,外设中断请求:连接外部外设(如串口、GPIO 等),接收外设发送的中断请求信号。NVIC 根据预设的优先级对多个 IRQ 请求进行仲裁,决定响应顺序。

  2. NMI(Non-Maskable Interrupt,非屏蔽中断):优先级最高的中断,用于处理紧急不可屏蔽事件(如电源故障),一旦触发,CPU 必须立即响应

  3. SysTick Timer(系统滴答定时器):内置的定时器,为操作系统或应用程序提供精准的时间基准与 NVIC 交互,可配置为触发中断,让 CPU 定期执行时间相关的任务(如延时、周期性数据采集)。

  4. Processor Core(处理器内核):与 NVIC 通信:接收 NVIC 的中断响应通知,跳转执行中断服务程序。处理System Exceptions(系统异常/内核中断):如复位、硬件错误、总线错误等系统级异常事件,由内核直接管理。

2.1.2 中断向量表(基于STM32F407ZGT6,别的系列中断数可能不同)

 关于中断向量表和中断向量号相关,可以参考学习
MCU开发学习记录3 - MAP、启动流程(HAL库)-CSDN博客

  1. 中断向量表中的内核中断10个(从Reference manual可知
    优先级为负数的
    通常reset -> main()

  2. 中断向量表的外部中断一共有82个

2.2 NVIC相关配置函数(基础版)

    2.2.1 NVIC相关配置函数

            中断失能:只是阻止NVIC将中断请求传递给CPU(即不执行ISR)。如果有中断发生,中断标志位会保持为1,只能软件手动清除。

    1. cortex内核函数
            

    2. HAL库NVIC配置函数(stm32f4xx_hal_cortex.c)
            

    2.2.2 NVIC配置流程

    1. NVIC进行中断优先级分组(一般都是程序开头就完成了声明)
    2. NVIC设置中断优先级
    3. NVIC对应外设使能
    4. 编写对应外设句柄函数
      一般这个函数是调用 HAL库对应外设的ISR
      1. 对应外设的ISR有两个作用:清理中断标志位,调用中断回调函数(__weak,用户自定义)
      2. 再次清理该中断标志位(此时Callback已经执行完毕)
    5. 编写对应外设的中断回调函数Callback

    2.2.3 NVIC中断优先级概念

    在STM32的中断优先级配置中,​数值越小的中断优先级越高。
    NVIC中断优先级分为抢占优先级(Preemption Priority)子优先级(Subpriority)。

    1. 抢占优先级

            高抢占优先级的中断可以打断正在执行的低抢占优先级的中断(嵌套中断)。

    2. 子优先级

            • 仅在同一抢占优先级的中断之间比较。
            • 子优先级高的中断会优先执行,但不能打断正在执行的同抢占优先级中断。

    3. 自然优先级

            即在前两者设置相同时,根据自然优先级决定中断顺序。

            自然优先级就是中断向量表是序号。

    3. NVIC相关寄存器总结(详细介绍)

    NVIC:管理 ​外设中断 和 ​内核中断 的使能、优先级配置、挂起状态和活动状态。

    SCB:本文只对SCB中,中断相关寄存器进行介绍。
    管理 ​系统级控制,如优先级分组、系统异常(内核中断)配置、复位控制等。

    3.1 NVIC寄存器

    0xE000E100 - 0xE000E11CInterrupt Set Enable RegistersNVIC->ISER [0] - NVIC->ISER [7]Write 1 to set enable
    0xE000E180 - 0xE000E19CInterrupt Clear Enable RegistersNVIC->ICER [0] - NVIC->ICER [7]Write 1 to clear enable
    0xE000E200 - 0xE000E21CInterrupt Set Pending RegistersNVIC->ISPR [0] - NVIC->ISPR [7]Write 1 to set pending status
    0xE000E280 - 0xE000E29CInterrupt Clear Pending RegistersNVIC->ICPR [0] - NVIC->ICPR [7]Write 1 to clear pending status
    0xE000E300 - 0xE000E31CInterrupt Active Bit RegistersNVIC->IABR [0] - NVIC->IABR [7]Active status bit. Read only.
    0xE000E400 - 0xE000E4EFInterrupt - Priority RegistersNVIC->IPR [0] - NVIC->IPR [239]Interrupt - Priority Level (8 - bit wide) for each interrupt
    0xE000EF00Software Trigger Interrupt RegisterNVIC->STIRWrite an interrupt number to set its pending status

    3.1.1 ISER and ICER(控制外部中断)

            通过ISER/ICER,实现启用或禁用中断不会影响其他中断的启用状态。ISER/ICER寄存器是32位宽的;每个位代表一个中断输入。

            对应的函数:


    3.1.2 ISPR and ICPR(内核级)

            通过ISPR/ICPR,使用NVIC控制器向CPU直接发送中断挂起信号,不需要外部触发。

    注:

    • 这种内核级发送中断挂起信号,要成对使用。(平常不使用)

    • 正常:外设中断控制器->NVIC控制器->CPU(也不需要清除挂起标志位,内部清除)


    3.1.3 IABR

    Active status基础概念:
            当处理器启动中断处理程序时,该位被设置为1,并在执行中断返回时被清除。即使在这个过程中被抢断,该位仍置为1。相较于读取ISPR确定中断是否active,在嵌套中断,读取ISPR无法判断该中断是否active。

    3.1.4 IPR

            使用IPR对外部中断配置优先级。


    3.1.5 STIR

            STIR用来软件触发中断挂起信号(与ISPR功能一样)


    3.2 SCB寄存器

    0xE000ED04Interrupt Control and State RegisterSCB->ICSRControl and status of system exceptions
    0xE000ED08Vector Table Offset RegisterSCB->VTOREnable the vector table to be relocated to other address location
    0xE000ED0CApplication Interrupt / Reset Control RegisterSCB->AIRCRConfiguration for priority grouping, and self - reset control
    0xE000ED18- 0xE000ED23System Handler Priority RegistersSCB->SHPR[0]- SCB->SHPR [11]Exception priority setting for system exceptions

    3.2.1 ICSR

            ICSR用于管理和监控系统中断及异常状态。(设计中断调试使用。)
            无这种需求,先不了解了。

    3.2.2 VTOR(这个就是Bootloader+APP要用到的寄存器)

    后续开创一个新专栏做一些小项目,然后会针对这个Bootloader+APP,会写一个文章来说明。

            通过修改VTOR的值,可以将默认位于Flash起始地址(0x00000000)的中断向量表重定位到其他内存区域​(如SRAM或用户自定义的Flash地址),适应多阶段启动、动态固件更新等场景。

    // Bootloader跳转代码示例
    void jump_to_user_app(uint32_t user_app_addr) {
        // 1. 关闭全局中断
        __disable_irq();
        
        // 2. 设置VTOR指向用户程序的向量表(地址需128字对齐)
        SCB->VTOR = user_app_addr; // 例如:0x08008000
        
        // 3. 获取用户程序复位向量(用户程序的入口地址)
        uint32_t *reset_vector = (uint32_t*)(user_app_addr + 0x04);
        
        // 4. 设置堆栈指针并跳转
        __set_MSP(*(uint32_t*)user_app_addr); // 初始化主堆栈指针
        void (*user_reset_handler)(void) = (void (*)(void))(*reset_vector);
        user_reset_handler(); // 跳转到用户程序
    }

    3.2.3 AIRCR(10:8)

            对于该寄存器只关注[10:8],用来确定中断优先级如何进行分组(分抢占优先级位数和子优先级位数)。



    3.2.4 SHPR

            SHPR对内部中断进行中断优先级设置。


     3.3 NVIC相关函数汇总(HAL库)

    4. EXTI

            终于写到EXTI了,回忆一下EXTI的全称:External Interrupt/Event Controller。这名字起的真好,直接把作用写了出来。EXTI的作用:一是可以用来作为外部中断使用,二是可以作为外部触发事件使用(这个控制器真不错)。本文针对第一种使用。

            下面是这个是正点原子对于中断与事件的描述(说的很好)。

    • 中断:要进入NVIC,有相应的中断服务函数,需要CPU处理。
    • 事件:不进入NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC。

    4.1 什么是EXTI?

    4.1.1 EXTI结构框图

    4.1.2 EXTI构成

    1. EXTI可以产生23个中断/事件请求。

    2. 每个EXTI的线,都有自己的触发器和屏蔽器。

    3. 每个EXTI的线,都有自己专属的状态位。

    4. 但是,不是每个EXTI的线都有专属于自己的中断请求
    5. 同时参考手册里说明,EXTI可以捕获比APB时钟周期更短的脉冲(具体需要查看芯片手册),例如UART1(APB2_CLK=84Mhz,11.9ns)

    4.2 基于HAL库配置EXTI中断

            本文根据MCU开发学习记录4 - GPIO学习与实践(HAL库)-CSDN博客,建立工程继续修改,即使用按键作为外部中断控制LED灯状态反转。

    4.2.1 CubeMX配置EXTI中断

    1. 使能EXIT9引脚
      这里一共有六个模式,选择中断模式下降沿触发。

    2. 使能NVIC对应中断
    3. cubemx生成代码


    4.2.2 EXTI中断初始化流程

    1. main函数初始化,设置SCB的AIRCR
    2. GPIO初始化(MCU开发学习记录4 - GPIO学习与实践(HAL库)-CSDN博客
    3. 给NVIC配置EXTI中断
    4. 编写中断服务函数(cubemx会自动把中断服务函数放到stm32f4xx_it.c

      它会自动清除中断标志位
    5. 编写中断处理回调函数
      一般会再回调函数结束时,再清除一次中断标志位

    4.2.3 EXTI寄存器基地址


    4.2.3 EXTI寄存器介绍

    1. Interrupt mask register (EXTI_IMR)
    2. Event mask register (EXTI_EMR)
    3. Rising trigger selection register (EXTI_RTSR)
    4. Falling trigger selection register (EXTI_FTSR)
    5. Software interrupt event register (EXTI_SWIER)
    6. Pending register (EXTI_PR)

    4.3 EXTI中断实践

    4.3.1 硬件连接

    PB9 - KEY0 - GND

    4.3.2 用户代码

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
        if (GPIO_Pin == KEY0_Pin)
        {
            HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
            __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
        }
    }
    
    //main()
     while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
        // key_val = key_scan(0);
        // if (key_val == 1)
        // {
        //     dht11_read_data(&temp, &humi);
        //     printf("temp:%d\r\n", temp);
        //     printf("humi:%d\r\n", humi);
        //     HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
        //     delay_ms(500);
        // }
        delay_ms(500);
      }

    5. 本文相关下载连接

    5.1 本文参考资料下载链接

    1. Programming manual

    https://www.st.com/en/microcontrollers-microprocessors/stm32f407-417/documentation.html

    2. Cortex -M4 Devices Generic User Guide Generic User Guide

    https://developer.arm.com/search#q=The%20Definitive%20Guide%20to%20ARM%C2%AE%20Cortex%C2%AE-M3%20and%20Cortex-M4%20Processors&numberOfResults=48

    3. The Definitive Guide to ARM® CORTEX®-M3 and CORTEX®-M4 Processors

    https://archive.org/details/cortexr-m4/page/n975/mode/2up

    5.2 本文的工程文件下载链接

    工程CSDN下载链接:https://download.csdn.net/download/weixin_45483813/90583949?spm=1001.2014.3001.5503
    工程Github下载链接:https://github.com/chipdynkid/MCU-DL-STM32

    (国内)工程Gitcode下载链接:GitCode - 全球开发者的开源社区,开源代码托管平台

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值