【STM32标准库】【基础知识】中断和NVIC


文章基于适用于STM32F4系列,作者使用STM32F401CCU6开发板。
本文章基于此系列和开发板展开讨论。

中断

什么是中断

故名思意,中断就是打断某个程序的运行过程。转而运行其他规定的程序。

为什么要有中断

因为单片机的程序运行从本质上说是顺序执行程序(单线程),因此无法及时处理未知的突发事件。
突发情况包括但不限于某个按键的触发,达到某个时间,收到某个信号等。
所以硬件设计者设计出了一种可以在某个特定情况发生的时候及时响应的系统(中断系统)。

中断的运作过程

这里不解释底层的原理,详情请看微机原理

从编程的角度来看。可以把中断当作一个函数(中断服务函数),这个函数的调用和平常的函数不同,它可以在出现某个信号(中断信号)时被自动调用。

中断的调用过程和函数一样,在出现中断信号(函数被调用)时会存储现在执行到的位置,然后进入函数进行执行,中断服务函数(函数)被执行完毕后会回到原来保存下的位置继续执行。
就像这张图一样。(PS:函数的调用过程也类似)
在这里插入图片描述

中断优先级

既然中断是用来处理突发事件的,那必然不同的事件有不同的紧急程度。
反应在编程中便是中断优先级。

中断优先级就是表示在两个中断同时(虽然对单片机来说不存在同时,可以认为是在较短时间内出现两个)发送中断请求时决定优先处理哪个。

中断系统内部有一套程序决定不同中断的优先级(中断号)。当然编程者也可以自行设置,也就是后文要介绍的NVIC。

中断嵌套

中断是存在优先级的,高优先级的中断可以打断低优先级的中断。在中断函数中出现中断并被执行就叫做中断嵌套。

其实就像函数嵌套一样,是在中断函数中执行中断函数,只不过会不会产生中断嵌套是要取决于两个中断的优先级。只有在较低优先级的中断函数中才能运行较高优先级的中断函数。

就像个图一样
在这里插入图片描述

NVIC

NVIC是一套用来管理中断的系统。

初始化思路

  1. 设置NVIC分组
  2. 设置NVIC初始化结构体
  3. 初始化NVIC

NVIC分组

STM32中中断优先级有2个,一个是抢占优先级,一个是响应优先级。
官方起的名字容易使人产生误导,可以认为分为主优先级(抢占优先级),和副优先级(响应优先级)
到这里可以将STM32的中断优先级系统介绍完全了。

首先比较主优先级(标号小的优先级高,0是最高),然后比较副优先级(标号小的优先级高,0是最高),如果主副优先级都相同,则比较中断号(系统确定好的,无法简单更改)(同样是小的优先级高)。

注意:没有两个中断源的优先级完全相同,总会存在先后次序。
注意:主优先级相同的两个中断无法产生中断嵌套,会先执行优先级高的再执行优先级低的
NVIC分组就是来设置主优先级和副优先级的数量。如下表

名称主优先级(抢占优先级)数量/可取值副优先级(响应优先级)数量/可取值
NVIC_PriorityGroup_00(可取0)16(可取0-15)
NVIC_PriorityGroup_12(可取0-1)8(可取0-7)
NVIC_PriorityGroup_24(可取0-3)4(可取0-3)
NVIC_PriorityGroup_38(可取0-7)2(可取0-1)
NVIC_PriorityGroup_416(可取0-15)0(可取0)

也就是一个4位的寄存器,根据上面的不同组分为主副优先级。

根据需要选取分组后使用这个函数进行设置

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)

NVIC初始化结构体

这个结构体包含了配置NVIC一些参数

typedef struct
{
  uint8_t NVIC_IRQChannel;						//中断名称
  uint8_t NVIC_IRQChannelPreemptionPriority;	//主优先级
  uint8_t NVIC_IRQChannelSubPriority; 			//副优先级
  FunctionalState NVIC_IRQChannelCmd; 			//打开或关闭
} NVIC_InitTypeDef;

中断名称就是要设置的中断,只能传入1个
名字长的是主优先级
中断名称的取值请查阅标准库的stm32f4xx.h文件的189行左右。

初始化NVIC

使用这个函数初始化NVIC

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

传入的是之前定义的结构体的地址,请使用取址符(&)

例子

	NVIC_InitTypeDef NVIC_Initstruct;						//定义NVIC初始化结构体
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);			//选定NVIC分组,选择组2
	NVIC_Initstruct.NVIC_IRQChannel=EXTI0_IRQn;				//选择中断源(外部中断0)
	NVIC_Initstruct.NVIC_IRQChannelCmd=ENABLE;				//打开NVIC使能
	NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority=1;	//设置主优先级
	NVIC_Initstruct.NVIC_IRQChannelSubPriority=1;			//设置副优先级
	NVIC_Init(&NVIC_Initstruct);							//初始化NVIC

中断初始化思路

  1. 配置NVIC(上文介绍的)
  2. 配置中断设置(不同中断不同,单独博客介绍)
  3. 编写中断服务函数

注意:中断服务函数的名字是固定的,不允许写错,不同中断不同,需要时介绍

与NVIC有关的常用的函数

NVIC_SetPriority

原型

__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
名称描述
输入 1要改变的中断号(可以是内部中断也可以是外部中断)
输入 2优先级
输出

功能描述:设置中断优先级,这个函数是直接设置中断优先级寄存器,0表示最高位,15表示最低位,具体主副优先级需要看NVIC组的划分
其实就是设置四位的中断优先级寄存器,具体是主副优先级需要看划分
例子:使用NVIC_PriorityGroup_2组,则

输入2主优先级副优先级
0b00000b000b00
0x00010b000b01
0x10010b100b01

NVIC_GetPriority

原型

__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
名称描述
输入 1要读取的中断号(可以是内部中断也可以是外部中断)
输出优先级(0-15)

功能描述:读取中断优先级,这个函数是直接读取中断优先级寄存器,0表示最高,15表示最低,具体主副优先级需要看NVIC组的划分
基本同上,写入和读取

NVIC_SystemReset

原型

__STATIC_INLINE void NVIC_SystemReset(void)
名称描述
输入 1
输出

功能描述:软件复位
注意;使用此函数到复位成功有个延迟,可以响应中断,如果有精度需要在前面加上关闭中断的控制函数

__set_FAULTMASK(1);			//关闭中断
NVIC_SystemReset();			//复位
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32标准中的串口中断收发通常涉及USART(通用同步/异步接收器发送器)模块,这里简要概述一个基本的示例代码,假设我们使用的是USART1,并启用半双工模式。首先,你需要配置USART,然后设置中断处理函数和开启中断。 ```c #include "stm32f10x_usart.h" #include "stm32f10x_rcc.h" // 假设USART1初始化 void USART1_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 启动USART1时钟 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 9600; // 设置波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); // 启动串口 } // 中断服务函数,用于接收数据 void EXTI0_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) { // 如果有数据接收就进入接收过程 uint8_t data = USART_ReceiveData(USART1); // 接收数据 // 处理接收到的数据... USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除接收中断标志 } } // 发送数据 void SendData(uint8_t data) { USART_SendData(USART1, data); while (!USART_GetFlagStatus(USART1, USART_FLAG_TXE)); // 等待发送缓冲区空闲 } // 初始化串口中断 void USART1_ITConfig(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } int main(void) { USART1_Init(); USART1_ITConfig(); // 开启串口接收中断 while (1) { // 发送数据 SendData('H'); // ... } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值