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

|-----|------|-------|-------|
| 序号 | | 抢占优先级 | 子优先级 |
| 中断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.编写闪灯代码

cpp 复制代码
#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.初始化串口

cpp 复制代码
//创建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

要想使标志位触发中断

需要闭合中断屏蔽开关

cpp 复制代码
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的中断函数

cpp 复制代码
//创建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.配置中断优先级分组
cpp 复制代码
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.设置中断优先级、闭合开关
cpp 复制代码
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

解析:

**参数:**初始化的参数结构体地址

**作用:**初始化NVIC,配置NVIC的各种参数

**补充:**NVIC_InitTypeDef结构

cpp 复制代码
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:**开关状态

cpp 复制代码
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.编写中断响应函数

cpp 复制代码
//创建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.总代码

cpp 复制代码
#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);
}
相关推荐
来自晴朗的明天2 小时前
8、2N7002 MOS 管电平转换电路
单片机·嵌入式硬件·硬件工程
BlackWolfSky2 小时前
鸿蒙高级课程笔记1—应用DFX能力介绍
笔记·华为·harmonyos
恒锐丰小吕2 小时前
屹晶微 EG3013S 低压60V半桥驱动芯片技术解析
嵌入式硬件·硬件工程
别了,李亚普诺夫2 小时前
数字测速方法和PID控制
笔记·学习·电机
全栈游侠3 小时前
STM32F103XX 01-存储器和总线架构
stm32·嵌入式硬件·架构
1104.北光c°3 小时前
【黑马点评项目笔记 | 登录篇】Redis实现共享Session登录
java·开发语言·数据库·redis·笔记·spring·java-ee
恒锐丰小吕3 小时前
屹晶微 EG2124A 中压260V三相半桥驱动芯片技术解析
嵌入式硬件·硬件工程
曾浩轩3 小时前
C语言学习记录——BC119 最高分与最低分之差
c语言·笔记·学习
来自晴朗的明天4 小时前
5、CBMV321 分压式电压跟随器电路
单片机·嵌入式硬件·硬件工程