阅读小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);
}
创作不易,请多多点赞,收藏,转发,您的支持,是我创作最大的动力!
内容若有误,在所难免,还望指出,定会积极订正,不胜感激,还望海涵!


 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐