中断控制原理 一、基本概念1.1 定义中断是指MCU在运行过程中遇到需要处理的内部或外部事件时自动暂停当前程序、跳转执行对应服务程序、完成后返回原程序继续运行的一种硬件自动响应机制。1.2 工作流程外部中断处理流程IO引脚电平变化 → EXTI控制器挂起 → NVIC控制器 → CPU处理。外设如EXTI、UART、ADC产生的中断事件经由对应控制器挂起后由NVIC嵌套向量中断控制器统一管理优先级并转发给CPU处理而复位、SysTick等异常则由SCB系统控制块进行控制。整体上NVIC负责外设中断SCB负责内核异常两者共同向Cortex-M处理器内核提交请求实现优先级管理与响应。两者均最终提交给Cortex-M处理器内核响应处理。二、EXTI控制器EXTI控制器包含23个边沿检测器每根输入线可单独配置触发类型上升沿/下降沿/双边沿及屏蔽用于产生中断或事件。处理流程GPIO引脚电平变化 → EXTI边沿检测 → 挂起中断/事件 → NVIC中断或直接响应事件 → CPU处理。输入线分配EXTI0~EXTI15连接外部GPIO引脚每个引脚可配置但最多同时使用16路每个EXTI输入线只能被一个GPIO组如PAx、PBx等中的同一引脚号占用即若PA0使用了EXTI0线则PB0等其他组的引脚不能再使用该线只能改用其他未被占用的EXTI线如EXTI1~EXTI15。EXTI16PVD输出EXTI17RTC闹钟EXTI18USB OTG FS唤醒EXTI19以太网唤醒EXTI20USB OTG HS唤醒EXTI21RTC入侵/时间戳EXTI22RTC唤醒EXTI中的事件外部电平跳变触发后不经过CPU处理直接通知片内外设控制器如ADC、TIM等执行相应动作的硬件联动机制。共享中断多个外设共用一条中断线由NVIC根据优先级和状态判断处理专用中断每个外设独立占用一条中断线无需仲裁即可直接响应。中断清理中断产生后会在中断挂起寄存器中置位标志需软件手动清除同时软件中断事件也会被清除但清除软件中断事件并不会清理中断挂起寄存器两者需分别独立操作。三、NVIC3.1 定义NVIC是Cortex-M架构的中断控制器用于管理中断优先级、使能/禁用中断及处理中断请求。STM32F407共有82个可屏蔽中断和10个系统异常。3.2 中断和异常触发源中断由外部设备定时器、GPIO等产生异常由指令执行除零、越界等引起。原因中断是异步外部事件用于通知处理器处理外设请求异常是同步的内部错误或特殊情况反映程序执行中的问题。3.3 异常向量表作用记录所有中断服务程序ISR入口地址的表处理器根据中断号查找并跳转执行。结构第一个条目存放主栈指针MSP初始值其余条目均为异常/中断处理函数入口地址。大小最多支持240个外部中断。重定位可通过向量表偏移寄存器VTOR重新定义向量表位置但0x0地址仍需保留最小表项用于内核启动引导。向量号每个异常/中断有唯一向量号用于中断控制状态寄存器中标识活动或挂起的异常。3.4 挂起和解挂挂起当CPU来不及处理或正在处理更高/同级优先级中断时中断请求被置为等待状态挂起优先级高的优先处理低的保持挂起等待。解挂分为两种方式硬件自动解挂当挂起的中断被CPU响应并进入异常处理时硬件自动清除挂起状态软件解挂由软件手动清除挂起标志完整流程中断请求产生 → 挂起状态置位 → CPU确认并响应 → 进入中断处理硬件自动解挂→ 进入ISR清除外设中断请求3.5活跃状态位每个中断都有一个活跃状态位当处理器开始执行中断处理程序时该位被硬件自动置1进入激活状态当中断处理完成并执行中断返回时该位被硬件自动清零。3.6 相关的基址3.6.1 NVIC 控制器寄存器映射基址0xE000E000地址范围寄存器名称符号功能0xE000E100 ~ 0xE000E11C中断设置使能寄存器ISER0~ISER2最大 ISER7写1 设置使能0xE000E180 ~ 0xE000E19C中断清除使能寄存器ICER0~ICER2最大 ICER7写1 清除使能0xE000E200 ~ 0xE000E21C中断设置挂起寄存器ISPR0~ISPR2最大 ISPR7写1 设置挂起状态0xE000E280 ~ 0xE000E29C中断清除挂起寄存器ICPR0~ICPR2最大 ICPR7写1 清除挂起状态0xE000E300 ~ 0xE000E31C中断活跃位寄存器IABR0~IABR2最大 IABR7只读查询中断活跃状态0xE000E400 ~ 0xE000E4EF中断优先级寄存器IP0~IP81最大 IP2398位中断优先级配置3.6.2 SCB 寄存器映射基址0xE000ED00地址寄存器名称符号功能0xE000ED04系统异常控制和状态寄存器ICSR控制 NMI、PendSV 等异常的挂起与触发0xE000ED08向量表偏移寄存器VTOR设置异常向量表起始地址重定位0xE000ED0C应用中断/复位控制寄存器AIRCR设置优先级分组抢占与响应位分配0xE000ED18 ~ 0xE000ED23系统处理优先级寄存器SHPR0~SHPR3最大 SHPR11设置系统异常MemManage、BusFault 等优先级0xE000ED24系统处理控制和状态寄存器SHCSR使能或查看系统异常状态四、中断优先级4.1异常嵌套异常是否能被处理器接受并执行由异常优先级和当前处理器优先级共同决定优先级编号更小的异常优先级更高可以抢占优先级编号更大的低优先级异常从而实现异常嵌套。4.2 中断优先级中断优先级由优先级寄存器IPRx控制有效位宽为3~8位由厂商决定STM32仅实现低4位中的高4位低4位保留且读写无效。抢占优先级决定中断能否抢占打断正在执行的低抢占优先级中断数值越小优先级越高。响应优先级当抢占优先级相同时决定多个中断同时产生时的处理顺序数值越小越优先但不能发生抢占即不能打断同抢占优先级的中断。自然优先级当抢占优先级和响应优先级均相同时由中断在向量表中的位置编号决定编号越小优先级越高不可编程。处理优先级抢占优先级 响应优先级 自然优先级五、CPU 中断屏蔽 寄存器组复位Reset优先级 -3最高系统上电或复位时触发初始化系统不可屏蔽。NMI不可屏蔽中断优先级 -2用于紧急事件如硬件看门狗、电源失效不可屏蔽。HardFault硬故障优先级 -1处理内存访问错误、指令错误等严重异常FAULTMASK置位时可屏蔽。屏蔽寄存器PRIMASK将当前处理器优先级阈值设为0即屏蔽所有优先级数值≥0的中断也就是除复位、NMI、HardFault外所有中断均被屏蔽用于临时禁止普通中断以执行时序关键任务。FAULTMASK将当前处理器优先级阈值设为-1即屏蔽所有优先级数值≥-1的中断也就是除复位、NMI外所有中断包括HardFault均被屏蔽实现更深度的屏蔽。BASEPRI按优先级阈值屏蔽只禁止优先级数值大于等于设定值的中断即优先级低于或等于设定值的中断被屏蔽保留更高优先级数值更小的中断响应。允许设置一个任意的阈值优先级数值越小优先级越高。六、HAL接口6.1 HAL_NVIC_SetPriorityGrouping函数项目内容函数功能设置优先级分组函数原型void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)参数PriorityGroup优先级分组值返回值无作用配置中断优先级分组决定抢占优先级和响应优先级的位分配6.2HAL_NVIC_GetPriorityGrouping函数项目内容函数功能读取当前系统优先级分组函数原型uint32_t HAL_NVIC_GetPriorityGrouping(void)参数无返回值当前优先级分组值作用获取系统当前的优先级分组配置6.3HAL_NVIC_SetPriority函数项目内容函数功能设置中断优先级函数原型void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)参数IRQn中断编号PreemptPriority抢占优先级SubPriority响应优先级返回值无作用为指定中断设置抢占优先级和响应优先级6.4HAL_NVIC_GetPriority函数项目内容函数功能获取中断的抢占优先级和响应优先级函数原型void HAL_NVIC_GetPriority(IRQn_Type IRQn, uint32_t PriorityGroup, uint32_t *pPreemptPriority, uint32_t *pSubPriority)参数IRQn中断编号PriorityGroup当前优先级分组pPreemptPriority返回抢占优先级指针pSubPriority返回响应优先级指针返回值无作用获取指定中断当前的抢占优先级和响应优先级6.5HAL_NVIC_EnableIRQ函数项目内容函数功能使能中断函数原型void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)参数IRQn中断编号返回值无作用使能指定中断允许CPU响应6.6HAL_NVIC_DisableIRQ函数项目内容函数功能关闭中断函数原型void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)参数IRQn中断编号返回值无作用关闭指定中断CPU不再响应6.7HAL_NVIC_SetPendingIRQ函数项目内容函数功能设置中断挂起标志函数原型void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn)参数IRQn中断编号返回值无作用软件触发指定中断将其挂起标志置位6.8HAL_NVIC_GetPendingIRQ函数项目内容函数功能读取中断挂起标志函数原型uint32_t HAL_NVIC_GetPendingIRQ(IRQn_Type IRQn)参数IRQn中断编号返回值挂起状态1挂起中0未挂起作用查询指定中断是否处于挂起状态6.9HAL_NVIC_ClearPendingIRQ函数项目内容函数功能清除中断挂起标志函数原型void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn)参数IRQn中断编号返回值无作用清除指定中断的挂起标志6.10HAL_NVIC_GetActive函数项目内容函数功能获取中断激活状态函数原型uint32_t HAL_NVIC_GetActive(IRQn_Type IRQn)参数IRQn中断编号返回值激活状态1正在处理中0未激活作用查询指定中断是否正在被CPU执行处理