中断
目录
中断
一、中断的概念
1.1.中断的基本概念
1.2.中断编程举例
二、中断优先级
2.1.中断优先级的概念
2.2.中断优先级的表示方法
2.2.1中断结构框图
2.2.2.嵌套中断向量控制器(NVIC)
2.3.抢占优先级与中断嵌套
2.4.子占优先级与中断排队
2.5.练习
三、串口中断编程实验
3.1.编写闪灯代码
3.2.初始化串口
3.3.让RxNE标志位触发中断
3.4.配置NVIC模块
3.4.1.配置中断优先级分组
3.4.2.设置中断优先级、闭合开关
3.5.编写中断响应函数
3.6.总代码
一、中断的概念
1.1.中断的基本概念
单片机应对突发事件的一种
生活中的突发事件:
单片机的突发事件:
常规程序:
中断相应函数:
1.2.中断编程举例
串口发送数据控制LED闪烁速率
闪灯程序:
串口数据接收程序:
如果直接合并程序:
假设亮灯需要100ms,灭灯需要100ms,一次完整的闪灯周期为200ms
但只有在每次执行判断串口RXNE标志位时才会检查串口是否有数据
如果数据在闪灯延迟期间送达,就会被延迟到下一次轮询时才能处理
串口波特率为115200bps,数据帧格式为1位停止位+8位数据位+1位校验位
115200 / 10 = 11520,串口每秒中最多可以接收11520个字节
如果使用中断:
当串口接收到数据时,会触发中断
CPU立即停止主循环的闪灯程序
转而去执行中断服务函数来读取并且处理数据
二、中断优先级
2.1.中断优先级的概念
在第一个事例中:
正在给病人1看病,病人2比病人3先到,但病人3需要赶火车,所以先看病人3
在第二个事例中:
正在给病人4看病,但病人5病情较急,所以先给病人5看病
优先级:优先处理重要紧急的事情,用数字表示中断的紧急程度
2.2.中断优先级的表示方法
2.2.1中断结构框图
片上外设:芯片内部模块,每一种模块都有对应的功能
中断:芯片上的片上外设可以产生中断
例:USART模块的全局中断(由标志位控制)
嵌套中断向量控制器(NVIC):中断的管理员,根据中断的优先级进行排队、嵌套
中断时序图:反映中断的时序流程
中断向量表:CPU响应中断时,从中断向量表中寻找中断响应函数
2.2.2.嵌套中断向量控制器(NVIC)
- 配置中断优先级分组
- 设置抢占优先级和子优先级
- 控制中断开关
2.3.抢占优先级与中断嵌套
中断嵌套:更高优先级的中断打断正在执行的中断
中断嵌套的条件:新中断的抢占优先级更高
示例:
假设中断优先级分组为2
| 序号 | 抢占优先级 | 子优先级 | |
| 中断1 | 1001 | 10(2) | 01(1) |
| 中断2 | 1000 | 10(2) | 00(0) |
| 中断3 | 0011 | 00(0) | 11(3) |
| 中断4 | 1110 | 11(3) | 10(2) |
注:抢占优先级越小,优先级越高
判断:
中断1的抢占优先级与中断2的抢占优先级都为2,不会发生中断嵌套
中断3的抢占优先级比中断1的抢占优先级小,所以比中断1的优先级高,会发生中断嵌套
中断1的抢占优先级比中断4的抢占优先级小,所以中断1的优先级高,不会发生中断嵌套
2.4.子占优先级与中断排队
中断排队:优先级相仿,等待前一个中断执行完再处理新中断
- 因为抢占优先级相仿,不会打断当前中断的执行
- 子占优先级高的排在前面
- 子占优先级相同,则根据先来后到排队
2.5.练习
中断优先级分组2
三、串口中断编程实验
3.1.编写闪灯代码
#include "stm32f10x.h" #include "delay.h" //声明板载LED初始化函数 void App_OnBoardLED_Init(void); //创建闪灯间隔变量 uint32_t blinkInterval = 1000; int main(void) { App_OnBoardLED_Init(); while(1) { /*点亮板载LED*/ GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); /*延迟*/ Delay(blinkInterval); /*熄灭板载LED*/ GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); /*延迟*/ Delay(blinkInterval); } } //创建板载LED初始化函数 void App_OnBoardLED_Init(void) { /*启动GPIOC时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); /*声明GPIO结构变量*/ GPIO_InitTypeDef GPIO_InitStruct; /*选择PC13引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13; /*输出开漏模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; /*最大输出速率为2MHz*/ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; /*初始化PA0引脚*/ GPIO_Init(GPIOC,&GPIO_InitStruct); }3.2.初始化串口
//创建USART1初始化函数 void App_USART1_Init(void) { /*GPIO结构前置声明*/ GPIO_InitTypeDef GPIO_InitStruct; //配置发送端Tx对应的PA9引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA9引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; /*设置复用输出推挽模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; /*最大输出速度为10MHz*/ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; /*初始化PA9引脚*/ GPIO_Init(GPIOA,&GPIO_InitStruct); //配置接收端Rx对应的PA10引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA10引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; /*设置输入上拉模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /*初始化PA10引脚*/ GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化串口 /*开启USART1模块时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /*USART结构前置声明*/ USART_InitTypeDef USART_InitStruct; /*波特率为115200*/ USART_InitStruct.USART_BaudRate = 115200; /*硬件流控设为无*/ USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /*数据位为8位*/ USART_InitStruct.USART_WordLength = USART_WordLength_8b; /*停止位为1位*/ USART_InitStruct.USART_StopBits = USART_StopBits_1; /*校验方式为无*/ USART_InitStruct.USART_Parity = USART_Parity_No; /*收发方向为双向*/ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; /*初始化USART1*/ USART_Init(USART1,&USART_InitStruct); /*闭合串口总开关*/ USART_Cmd(USART1,ENABLE); }3.3.让RxNE标志位触发中断
每当串口接收到数据时,就要产生一个中断
可以通过串口的RxNE标志位判断
每当RxNE从0变为1时,说明串口收到数据
逻辑或门:
只要有一个数据为1,就输出1
只有当所有数据为0,才输出0
要想使标志位触发中断
需要闭合中断屏蔽开关
void USART_ITConfig(USART_TypeDef* USARTx,uint16_t USART_IT,FunctionalState NewState);解析:
参数1:串口的名称 USART1 USART2
参数2:标志位的名称
- USART_IT_TXE
- USART_IT_TC
- USART_IT_RXNE
- USART_IT_PE
- USART_IT_ERR
参数3:开关状态
- 闭合:ENABLE
- 断开:DISABLE
作用:配置USART的中断函数
//创建USART1初始化函数 void App_USART1_Init(void) { /*GPIO结构前置声明*/ GPIO_InitTypeDef GPIO_InitStruct; //配置发送端Tx对应的PA9引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA9引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; /*设置复用输出推挽模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; /*最大输出速度为10MHz*/ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; /*初始化PA9引脚*/ GPIO_Init(GPIOA,&GPIO_InitStruct); //配置接收端Rx对应的PA10引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA10引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; /*设置输入上拉模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /*初始化PA10引脚*/ GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化串口 /*开启USART1模块时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /*USART结构前置声明*/ USART_InitTypeDef USART_InitStruct; /*波特率为115200*/ USART_InitStruct.USART_BaudRate = 115200; /*硬件流控设为无*/ USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /*数据位为8位*/ USART_InitStruct.USART_WordLength = USART_WordLength_8b; /*停止位为1位*/ USART_InitStruct.USART_StopBits = USART_StopBits_1; /*校验方式为无*/ USART_InitStruct.USART_Parity = USART_Parity_No; /*收发方向为双向*/ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; /*初始化USART1*/ USART_Init(USART1,&USART_InitStruct); /*闭合串口总开关*/ USART_Cmd(USART1,ENABLE); //配置中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); }3.4.配置NVIC模块
3.4.1.配置中断优先级分组
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);解析:
参数:分组方式选择
- NVIC_PriorityGroup_0:0位抢占优先级,4位子优先级
- NVIC_PriorityGroup_1:1位抢占优先级,3位子优先级
- NVIC_PriorityGroup_2:2位抢占优先级,2位子优先级
- NVIC_PriorityGroup_3:3位抢占优先级,1位子优先级
- NVIC_PriorityGroup_4:4位抢占优先级,0位子优先级
3.4.2.设置中断优先级、闭合开关
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);解析:
参数:初始化的参数结构体地址
作用:初始化NVIC,配置NVIC的各种参数
补充:NVIC_InitTypeDef结构
struct NVIC_InitTypeDef { uint8_t NVIC_IRQChannel; uint8_t NVIC_IRQChannelPreemptionPriority; uint8_t NVIC_IRQChannelSubPriority; FunctioalState NVIC_IRQChannelCmd; };分析:
1.NVIC_IRQChannel:中断的名称(见stm32f10.h IRQn)
2.NVIC_IRQChannelPreemptionPriority:抢占优先级
3.NVIC_IRQChannelSubPriority:子优先级
4.NVIC_IRQChannelCmd:开关状态
int main(void) { /*设置中断优先级分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); App_OnBoardLED_Init(); App_USART1_Init(); while(1) { /*点亮板载LED*/ GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); /*延迟*/ Delay(blinkInterval); /*熄灭板载LED*/ GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); /*延迟*/ Delay(blinkInterval); } } //创建USART1初始化函数 void App_USART1_Init(void) { /*GPIO结构前置声明*/ GPIO_InitTypeDef GPIO_InitStruct; //配置发送端Tx对应的PA9引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA9引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; /*设置复用输出推挽模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; /*最大输出速度为10MHz*/ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; /*初始化PA9引脚*/ GPIO_Init(GPIOA,&GPIO_InitStruct); //配置接收端Rx对应的PA10引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA10引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; /*设置输入上拉模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /*初始化PA10引脚*/ GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化串口 /*开启USART1模块时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /*USART结构前置声明*/ USART_InitTypeDef USART_InitStruct; /*波特率为115200*/ USART_InitStruct.USART_BaudRate = 115200; /*硬件流控设为无*/ USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /*数据位为8位*/ USART_InitStruct.USART_WordLength = USART_WordLength_8b; /*停止位为1位*/ USART_InitStruct.USART_StopBits = USART_StopBits_1; /*校验方式为无*/ USART_InitStruct.USART_Parity = USART_Parity_No; /*收发方向为双向*/ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; /*初始化USART1*/ USART_Init(USART1,&USART_InitStruct); /*闭合串口总开关*/ USART_Cmd(USART1,ENABLE); //配置中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //配置NVIC /*声明NVIC结构变量*/ NVIC_InitTypeDef NVIC_InitStruct; /*设置USART1中断名称*/ NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; /*设置抢占优先级*/ NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; /*子优先级*/ NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; /*闭合中断开关*/ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; /*初始化NVIC*/ NVIC_Init(&NVIC_InitStruct); }3.5.编写中断响应函数
//创建USART中断响应函数 void USART1_IRQHandler(void) { /*判断中断产生原因*/ if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET) { uint8_t dataRcvd = USART_ReceiveData(USART1); if(dataRcvd == '0') { blinkInterval = 1000; } else if(dataRcvd == '1') { blinkInterval = 200; } else if(dataRcvd == '2') { blinkInterval = 50; } } }3.6.总代码
#include "stm32f10x.h" #include "delay.h" //声明板载LED初始化函数 void App_OnBoardLED_Init(void); //声明USART1初始化函数 void App_USART1_Init(void); //声明USART中断响应函数 void USART1_IRQHandler(void); //创建闪灯间隔变量 uint32_t blinkInterval = 1000; int main(void) { /*设置中断优先级分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); App_OnBoardLED_Init(); App_USART1_Init(); while(1) { /*点亮板载LED*/ GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); /*延迟*/ Delay(blinkInterval); /*熄灭板载LED*/ GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); /*延迟*/ Delay(blinkInterval); } } //创建USART中断响应函数 void USART1_IRQHandler(void) { /*判断中断产生原因*/ if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET) { uint8_t dataRcvd = USART_ReceiveData(USART1); if(dataRcvd == '0') { blinkInterval = 1000; } else if(dataRcvd == '1') { blinkInterval = 200; } else if(dataRcvd == '2') { blinkInterval = 50; } } } //创建USART1初始化函数 void App_USART1_Init(void) { /*GPIO结构前置声明*/ GPIO_InitTypeDef GPIO_InitStruct; //配置发送端Tx对应的PA9引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA9引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; /*设置复用输出推挽模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; /*最大输出速度为10MHz*/ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; /*初始化PA9引脚*/ GPIO_Init(GPIOA,&GPIO_InitStruct); //配置接收端Rx对应的PA10引脚 /*开启GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*选择PA10引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; /*设置输入上拉模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /*初始化PA10引脚*/ GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化串口 /*开启USART1模块时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /*USART结构前置声明*/ USART_InitTypeDef USART_InitStruct; /*波特率为115200*/ USART_InitStruct.USART_BaudRate = 115200; /*硬件流控设为无*/ USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /*数据位为8位*/ USART_InitStruct.USART_WordLength = USART_WordLength_8b; /*停止位为1位*/ USART_InitStruct.USART_StopBits = USART_StopBits_1; /*校验方式为无*/ USART_InitStruct.USART_Parity = USART_Parity_No; /*收发方向为双向*/ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; /*初始化USART1*/ USART_Init(USART1,&USART_InitStruct); /*闭合串口总开关*/ USART_Cmd(USART1,ENABLE); //配置中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //配置NVIC /*声明NVIC结构变量*/ NVIC_InitTypeDef NVIC_InitStruct; /*设置USART1中断名称*/ NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; /*设置抢占优先级*/ NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; /*子优先级*/ NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; /*闭合中断开关*/ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; /*初始化NVIC*/ NVIC_Init(&NVIC_InitStruct); } //创建板载LED初始化函数 void App_OnBoardLED_Init(void) { /*启动GPIOC时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); /*声明GPIO结构变量*/ GPIO_InitTypeDef GPIO_InitStruct; /*选择PC13引脚*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13; /*输出开漏模式*/ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; /*最大输出速率为2MHz*/ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; /*初始化PA0引脚*/ GPIO_Init(GPIOC,&GPIO_InitStruct); }