news 2026/4/18 3:47:42

STM32笔记归纳6:中断

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32笔记归纳6:中断

中断

目录

中断

一、中断的概念

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

序号抢占优先级子优先级
中断1100110(2)01(1)
中断2100010(2)00(0)
中断3001100(0)11(3)
中断4111011(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); }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 15:24:49

史上最狠春节!阿里千问豪掷30亿,加入AI大战

梦瑶 发自 凹非寺量子位 | 公众号 QbitAI救命,现在的AI,光会帮我下单已经不够了。连免单、发红包都要一并安排上???(还有这种好事儿)你还别说,真有。今天,千问官宣了一个…

作者头像 李华
网站建设 2026/4/17 21:52:48

Agent当上群主后,群聊变成办事大厅了

西风 发自 凹非寺量子位 | 公众号 QbitAI文心APP的群里,最近有点“AI多势众”。此群非一般的群,正是文心APP最近正在内测的行业首个“多人、多Agent”群聊功能。该怎么形容它最贴切,一进这个群,就相当于进入了一个微型“办事处”&…

作者头像 李华
网站建设 2026/4/18 3:44:24

<span class=“js_title_inner“>4000万行的Linux怎么管?Linus爆料:两周合并1.2万次提交、7周专门抓Bug,“我不是世界之王,只能给内核定规矩”</span>

整理 | 屠敏出品 | CSDN(ID:CSDNnews)今年年初,Linux 内核的代码行数突破了 4000 万行。而作为这个庞大项目的掌舵者,Linus Torvalds 对外宣称自己“已经不再是程序员”、“不再编程”了,那么,他…

作者头像 李华
网站建设 2026/4/15 10:36:12

Doris在广告技术中的应用:实时竞价分析系统

Doris在广告技术中的应用:实时竞价分析系统 关键词:Doris数据库、实时竞价(RTB)、广告技术、实时分析、高并发查询 摘要:在广告技术领域,实时竞价(RTB)系统需要在毫秒级内完成用户画…

作者头像 李华
网站建设 2026/4/18 3:44:23

实时消息推送系统

1、非修改序列算法 这些算法不会改变它们所操作的容器中的元素。 1.1 find 和 find_if find(begin, end, value):查找第一个等于 value 的元素,返回迭代器(未找到返回 end)。find_if(begin, end, predicate):查找第…

作者头像 李华
网站建设 2026/4/8 3:50:18

GDPR合规必备:大数据环境下的数据脱敏策略

GDPR合规必备:大数据环境下的数据脱敏策略 关键词:GDPR合规、数据脱敏、隐私保护、大数据安全、敏感信息处理 摘要:在欧盟《通用数据保护条例》(GDPR)的严格监管下,企业如何处理用户个人数据成为合规关键。…

作者头像 李华