ST32中的中断的概念
在STM32微控制器中,中断是一种允许设备在特定事件(例如外部引脚状态变化、定时器溢出、ADC转换完成等)发生时打断当前程序执行的机制。中断可以显著提高系统的实时响应能力,因为处理器无需主动等待特定事件,而是可以在事件发生时通过中断快速响应。
1. 中断基本概念
中断机制允许外设模块(如UART、GPIO、定时器等)向CPU发出请求,CPU会停止当前执行的代码,跳转到中断服务程序(ISR)中执行特定代码,处理完后返回原代码继续执行。STM32中断可分为以下两类:
- 外部中断:由外部引脚(GPIO)变化或其他外围设备(如RTC、IWDG等)触发。
- 内部中断:由芯片内部外设(如定时器、ADC、DMA等)触发。
2. 中断优先级
STM32的中断系统支持不同的优先级,以确保在多个中断源同时请求中断时,具有更高优先级的中断会优先得到响应。优先级分为以下两类:
- 抢占优先级(Preemption Priority):决定了中断是否可以打断其他中断。
- 子优先级(Sub Priority):决定了当具有相同抢占优先级的中断请求同时发生时,哪个中断会先被响应。
STM32的中断优先级配置通过NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)实现。
3. 中断控制器NVIC
在标准外设库中,NVIC的中断设置和控制主要通过NVIC_InitTypeDef
结构体和NVIC_Init()
函数来完成。这个方法将中断配置的各项参数集中在一个结构体中,使得配置过程更加便捷和一致。该方法包括以下关键步骤:
NVIC_InitTypeDef 结构体
NVIC_InitTypeDef
是一个结构体,用于配置特定中断通道的参数:
NVIC_IRQChannel
:指定要配置的中断源,即IRQ通道编号。NVIC_IRQChannelPreemptionPriority
:设置中断的抢占优先级。NVIC_IRQChannelSubPriority
:设置中断的子优先级,用于同一抢占优先级的中断排序。NVIC_IRQChannelCmd
:启用或禁用该中断。
配置NVIC的标准库方法
通过初始化NVIC_InitTypeDef
结构体并调用NVIC_Init()
函数即可实现中断配置。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 选择EXTI0通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级设置为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; // 子优先级设置为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该中断通道
NVIC_Init(&NVIC_InitStructure);
4. 中断配置步骤
步骤 1:配置中断源(以外部中断为例)
如果是外部中断(EXTI),首先配置GPIO引脚的中断模式。
- 使能GPIO时钟:打开对应的GPIO端口时钟。
- 配置GPIO引脚模式:将引脚设置为输入模式,并指定中断触发边沿(上升沿、下降沿或双边沿)。
配置PA0为外部中断引脚并设置为下降沿触发:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // 使能GPIOA和AFIO时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); // 将GPIOA的0号引脚映射到EXTI0
步骤 2:配置外部中断控制(EXTI)
设置外部中断触发的边沿、引脚和通道等配置。
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 选择EXTI0,即对应PA0引脚
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 设置为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能EXTI线路
EXTI_Init(&EXTI_InitStructure);
步骤 3:配置NVIC
使用NVIC_InitTypeDef
结构体配置中断通道、抢占优先级和子优先级,并使能中断。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 指定中断通道(EXTI0中断)
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; // 子优先级为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该中断
NVIC_Init(&NVIC_InitStructure);
6. 编写中断服务函数
当事件发生时,CPU会跳转到对应的中断服务程序。每个中断有一个固定的中断处理函数名,例如,EXTI0_IRQHandler()
负责处理EXTI0中断。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 指定中断通道(EXTI0中断)
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; // 子优先级为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该中断
NVIC_Init(&NVIC_InitStructure);
5. 其他常用NVIC函数
在标准库中,NVIC的相关配置可以通过NVIC_EnableIRQ()
、NVIC_DisableIRQ()
和NVIC_SetPriority()
等函数进行操作,这些函数可以在不使用结构体的情况下直接控制中断:
NVIC_EnableIRQ(IRQn_Type IRQn)
:使能指定中断。NVIC_DisableIRQ(IRQn_Type IRQn)
:禁用指定中断。NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
:设置指定中断的优先级。
NVIC_SetPriority(EXTI0_IRQn, 1); // 设置优先级 NVIC_EnableIRQ(EXTI0_IRQn); // 使能中断
6. 常见应用场景
- 按键检测:外部中断处理按键按下或松开等事件。
- 定时任务:通过定时器中断实现定时任务,如周期性读取传感器数据。
- 串口通信:通过串口中断处理数据收发,提升通信效率。
- ADC采样完成:在ADC转换完成后触发中断,数据采集更高效。
- DMA传输完成:在DMA完成数据传输后触发中断,进行数据后续处理。
7. 注意事项
- 合理设置中断优先级:确保关键任务的中断优先级最高,以保证实时性。
- 中断服务函数中避免阻塞操作:避免耗时的代码,以免影响系统响应。
- 谨慎使用中断嵌套:避免嵌套过深导致系统不稳定。
通过标准外设库的中断配置,STM32可以实现实时响应的应用,适用于嵌入式系统的各种场景。