速通STM32-基础篇-中断
本文介绍了STM32嵌入式开发中的中断机制及其应用。通过日常生活例子通俗讲解中断概念,内容适合初学者搭建嵌入式基础框架,建议后续结合视频教程深入学习。
阅读小tips!(Look at my eyes!)
本篇基于电子类大学生自主学习嵌入式的学习总结,知识点理解输出较于浅显,只适用于深入学习stm32前的一些理解和引导,或是大学期末前一周速通,若要深入学习嵌入式,可借助阅读本篇来搭建一个入门嵌入式的框架,而后想深入可转战b站等学习网站,有更多的大牛在等待你!
一.中断的概念
中断的基本概念:
中断:单片机应对突发事件的一种方式。通俗易懂就是,被打断去做更重要的事。
举个例子:

此处的蚊子来了,鞋带开了,快递到了都被看做是一种中断信号,此处的阅读,跑步,玩游戏被看做是常规程序,当中断信号触发时,转而去做“拍蚊子”“系鞋带”“取快递”这样的突发事件,当中断程序完成时,再去做常规程序。这就叫做一次中断。

int main(void)
{
while(1)
{
//常规程序
}
}
//IRQ Handler = Interrupt Request Handler 中断 请求 处理器
//中断响应函数
void xxx_IRQHandler(void)
{
//对中断的具体处理代码
}
中断编程举例:
现在我们想要做如下实验,一颗LED灯按照一定频率进行闪烁,当串口收到一系列指令信息时,例如收到“1”,加快闪烁频率,收到“2”,减缓闪烁频率。下面让我们来用伪代码来实现。
int main(void)
{
while(1){
GPIO_WriteBit(...,Bit_RESET);//亮灯
Delay(...);//延迟一段时间
GPIO_WriteBit(...,Bit_SET);//灭灯
Delay(...);//延迟一段时间
if(USART_GetFlagStatus(RxNE)==SET)
{
uint8_t byte = USART_ReceiveData(...);//读取数据
//根据收到的数据改变闪灯的速度
}
}
}
但代码运行起来,现象并不像预期那样,闪灯的速度并不受控制,这是因为,CPU在执行程序时,遵循代码从上至下的运行顺序,闪灯的程序耗费100~200ms,而接收一个字节只耗费0.1~0.2ms,而且当CPU在执行闪灯程序时,此时收到的数据并不能被立刻读取,CPU的堵塞造成了数据的覆盖丢失,看来,程序并不能像我们想象的这么简单。
此时中断便发挥出了作用,当数据到来时,CPU先去接收数据,接收完成后转而再接着执行闪灯程序,由于接收数据时间远远小于闪灯耗费时间,现象并不能体现出来,所以代码可以这样修改。
int main(void)
{
while(1){
//闪灯程序
GPIO_WriteBit(...,Bit_RESET);//亮灯
Delay(...);//延迟一段时间
GPIO_WriteBit(...,Bit_SET);//灭灯
Delay(...);//延迟一段时间
}
}
//中断程序
void USART1_IRDHandler(void){
//接收数据
uint8_t byte = USART_ReceiveData(...);//读取数据
//根据收到的数据改变闪灯的速度
}
二.中断优先级
中断优先级的概念:
中断优先级:用数字表示中断的紧急程度。数字越小,中断紧急程度越高。
举个例子:

例子1中,此时病人1正在就诊,排号中的病人3有更紧急的事件,于是中断优先级体现,病人1就诊完毕后,病人3就诊,最后病人2 就诊。
例子2中,此时病人4正在就诊,此时来了一个急诊的病人5,于是中断优先级体现,病人4的就诊被打断,优先为病人5就诊,而后接着为病人4就诊。
中断优先级的表示方法:

单片机中的很多片上外设都有中断,大大小小的中断是如何做到有条不紊的呢?聪明的程序员们为了管理众多中断,请了一个中断管理员,NVIC,用一套系统来管理着中断的发生。例如,当片上外设USARTx接收到中断响应,开启全局中断时,经过NVIC判断中断优先级,与CPU正在执行的程序相比较,进行排队或是嵌套,而后在中断向量表中执行相应的响应函数。
NVIC的一套系统:

NVIC与诸多的片上外设不同,位于Cortex-M3内核中,不用手动开启时钟。
NVIC中的轴可以自由调节,有5中分组模式,例如响应中的(1011),若是在分组0中,抢占优先级占0位,子优先级占4位,则抢占优先级数为0,子优先级数为11(2的权重相加),后续根据抢占优先级数判断是否进入中断嵌套,根据子优先级数判断排队的顺序。
void App_NVIC_Init(void)
{
//配置NVIC
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//串口1为例子
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
抢占优先级与中断嵌套:
抢占优先级数越低,优先级更高。
中断嵌套:更高优先级的中断打断正在执行的判断。
中断嵌套的条件:新中断的抢占优先级更高。

急诊病人的抢占优先级数更低,优先级更高,于是进入中断嵌套。
子优先级与中断排队:
抢占优先级数一样时,子优先级的级数越低,排队顺序越靠前。
中断排队:优先级相仿,等待前一个中断执行完在处理新中断。

最终的排队顺序为,乘客1,乘客4,乘客3,乘客5,乘客2。
三.串口中断编程实验
已默认初始化LED,USART1
#include "stm32f10x.h"
#include "delay.h"
uint32_t blinkinterval = 1000//闪灯间隔
int main(void)
{
App_LED_Init();
App_USART_Init();
App_NVIC_Init();
while(1){
GPIO_WriteBit(GPIOC,GPIO_Pin13,Bit_RESET);//亮灯
Delay(blinkinterval);//延迟一段时间
GPIO_WriteBit(GPIOC,GPIO_Pin13,Bit_SET);//灭灯
Delay(blinkinterval);//延迟一段时间
}
}
//中断程序
void USART1_IRDHandler(void){
//判断中断产生的原因
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET)
{
uint8_t byte = USART_ReceiveData(USART1);//读取数据
//根据收到的数据改变闪灯的速度
if(byte =="0") blinkinterval = 1000;//慢
if(byte =="1") blinkinterval = 200;//中
if(byte =="2") blinkinterval = 50;//快
}
}
void App_NVIC_Init(void)
{
//配置中断usart
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//配置NVIC
NVIC_InitTypeDef NVIC_InitStruct;
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);
}
创作不易,请多多点赞,收藏,转发,您的支持,是我创作最大的动力!
内容若有误,在所难免,还望指出,定会积极订正,不胜感激,还望海涵!
更多推荐



所有评论(0)