ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

嵌入式铁头山羊stm32-中断的概念,优先级,编程-Day18

嵌入式铁头山羊stm32-中断的概念,优先级,编程-Day18

嵌入式铁头山羊STM32-各章节详细笔记-查阅传送门https://blog.csdn.net/m0_56408226/article/details/151870808?spm=1001.2014.3001.5501

目录

一、中断的概念

1.概念

2.编程举例(中断的由来)

二、中断的优先级

1.中断优先级的概念

2.中断流程

3.中断优先级的表示方法

​4.抢占优先级与中断嵌套

5.子占优先级与中断排队

6.练习题

三、中断的编程实验

1.编写闪灯代码

2.初始化串口

3.让RxNE标志位触发中断

4.配置NVIC模块

5.编写中断响应函数

6.代码


一、中断的概念

1.概念

简单来说,就是正常程序运行的过程中,要去应发一个突发事件,应发完后就继续做自己原来的事。

2.编程举例(中断的由来)

目的:外部串口去发送给单片机0慢闪,发送1正常闪,发送2快闪

首先,正常的思维就是先开始实现闪灯,然后你发送指令,然后单片机如果读到值,就使用接收指令去读对应的值并采取相应的行为,这看着是没啥问题的。

但是注意一个比较容易忽略的问题,假设writebit往灯写数据使灯亮或者灭是100ms一次,那么一次闪烁就是200ms,而串口接收或者发送的周期:比如波特率是常见的115200,然后发送的时候,起始位1+8个数据位+1结束位,这样就是每秒发送115200/10个字节,那就是发送或者接收就是0.1ms左右,那根据下面的第二个图片看到,当始终不读取数据的时候,你的接受寄存器的值始终会被覆盖,最后等你一次闪烁完,我可能只拿到了第一次发送的数据和被覆盖的就剩的最后一层的数据,所以这时候我们可以使用中断。

那这里就可以使用中断,就拿USART来说,他的右上角所示的每个标志位都可以引起中断,我们这里使用RXNE去产生中断,比如一判断到当前接收数据寄存器有值,就中断,中断响应函数里面接收数据就行

二、中断的优先级

1.中断优先级的概念

优先级就分为两种,一种是子优先级,就是同类的中断排队现象。

另一种是只有 抢占优先级才会发生的中断嵌套现象。

2.中断流程

如下所示,片上外设靠标志位启动全局中断,因为片上外设很多,既而传给单片机的中断也很多(注意:每个外设对应的全局中断都有对应的名称,然后给这个名称的中断配置优先级),那么就需要一个中断管理员:NVIC去管理中断(在这里管理里面定义了管理规则,即中断的优先级),之后执行中断,执行中断的时候,需要去中断向量表里面找每个中断名对应的中断响应函数(比如USART的中断名下这个也有其对应的中断响应函数)

一般来说,中断响应函数,在底层制作声明,你自己调用然后实现自己想要实现的具体中断功能就行。


3.中断优先级的表示方法

中断优先级,就是前面提到的管理规则,即具体就是NVIC这块,他给每个字段配置了4位的数据,有一根中断分组线,线左边的叫抢占优先级,右边的叫子优先级。

这根线可以左右移动,既而导致了5个不同的分组。

同一个类别的优先级,谁的值越小,谁就是优先,但是特比注意抢占优先级和子优先级二者是不能直接相比的,要比就是你的抢占和我的抢占比,你的子优先级和我的子优先级比。


4.抢占优先级与中断嵌套


5.子占优先级与中断排队

这里唯一一个特别注意的就是中断排队不会打断当前中断的执行,即一定不会发送抢占所造成的嵌套中断的情况


6.练习题

三、中断的编程实验

1.编写闪灯代码

其实就是初始化GPIO的PC13引脚,然后在while循环里面不断亮灭就行

2.初始化串口

就是初始化串口的IO引脚和模块

(测试的时候可以引入USART的头文件输出字符串试试)

3.让RxNE标志位触发中断

4.配置NVIC模块

是属于内核的一部分,即大脑的一部分,所以不像片上外设一样要去手动开启,NVIC是时刻就是开启的

这里很容易就明白,配置NVIC,那首先就是先整体先制定规则,即分组规则,代表排序规则(这是一个函数,一般放到main的第一行去开启)。

之后就是在NVIC中给每个中断进行标配的配置了。(配置中断名,抢占优先级和子优先级的值(这里给赋值为默认的0,是因为就一个中断,所以不需要配置排序值),以及开关的状态。)----这个注意,这个配置建议在每个要产生的中断的外设里面去配置,不懂的可以看下面的代码,以及所有stm32设备的中断名需要在stm32头文件点击F12的下的中断名的枚举类型里面进行查找

5.编写中断响应函数

在启动文件里面找响应函数,一般后缀为handler的都是代表响应函数

6.代码

#include "stm32f10x.h" #include "Delay.h" void My_BoardLed_Init(void); void My_USART_Init(void); uint16_t adjustDelay=100; void USART1_IRQHandler(void); int main(void) { //首先就是配置中断的时候标志的中断规则 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //初始化亮灯 My_BoardLed_Init(); //初始化USART并开启其标志位下的中断 My_USART_Init(); // while(1) { GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); Delay(adjustDelay); GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); Delay(adjustDelay); } } //初始化板载LED void My_BoardLed_Init(){ //GPIO的引脚13初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDef GPIO_InitStruct={0}; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz; GPIO_Init(GPIOC,&GPIO_InitStruct); GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); } void My_USART_Init(){ //初始化IO RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct={0}; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化本身 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //五个 USART_InitTypeDef USART_InitStruct={0}; USART_InitStruct.USART_BaudRate=115200; USART_InitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx; USART_InitStruct.USART_Parity=USART_Parity_No; USART_InitStruct.USART_StopBits=USART_StopBits_1; USART_InitStruct.USART_WordLength=USART_WordLength_8b; USART_Init(USART1,&USART_InitStruct); //开启USART USART_Cmd(USART1,ENABLE); //开启中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //给每个中断配置NVIC模块下的中断配置 NVIC_InitTypeDef NVIC_InitStruct={0}; NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStruct.NVIC_IRQChannelSubPriority=0; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStruct); } void USART1_IRQHandler(void){ if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){ uint8_t temp=USART_ReceiveData(USART1); if(temp==0){ adjustDelay=10000; }else if(temp==1){ adjustDelay=1000; }else if(temp==2){ adjustDelay=100; } } }
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进