stm32 /*EXTI外部中断使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


理论部分:

一、EXTI简介

在这里插入图片描述

二、中断系统

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

三、执行流程

在这里插入图片描述

四、60个中断源

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
如图这些灰色的属于CM3内核的中断-内核中断,哪个芯片都有,剩下的属于外部中断,ADC、CAN总线、RCC、TIM定时器、I2C总线、UART串口等灯都也是支持外部中断功能;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、NVIC基本原理

在这里插入图片描述
首先CPU不可能引出太多接线口,但是我们的外设很多足足有68个还多,所以这里就增加了NVIC模块;
NVIC模块就能引出很多接线了,这里箭头上写了个n,意思是一个外设可能会同时占用多个中断通道,所哟这里实际是n条线的;
然后NVIC只有一个输出口,NVIC根据每个中断的优先级分配中断的先后顺序,之后通过右边这一个输出口告诉CPU,你该处理哪个中断。
NVIC起到中断通道分配的作用。
举个例子,CPU就是医生,NVIC是医院的叫号系统,哪些中断外设就是看病的病人,NVIC的作用就是给病人分配一个看病的优先等级,提高医生的看病效率。
优先叫号紧急的病人,最后叫号系统输出的就是一个一个排好队的病人给医生。

六、中断处理优先等级

在这里插入图片描述

七、EXTI内部执行结构

在这里插入图片描述最左边是GPIO外设A~G,每个外设有16根线,所以进去是16根线的进去到AFIO;
GPIOA~G就有16组,每组有有16个引脚1-6根线,那么接线口就不够用了,所以这里增添了AFIO中断引脚选择器(这个就类似数字电路中的数据选择器)
AFIO是一个多路数据选择器,他可以将前面这3个GPIO外设的16个引脚里选择其中一路通道,连接到EXTI,给EXTI时候扔然是16根线,每16根线叫一个通道;
GPIOA~G 16个+PVD输出+RTC闹钟+USB唤醒+ETH以太网唤醒共20路,就构成EXTI的20个外设输入信号通道,每次每个通道也只有一个的16根数据-一路加到EXTI的输入口;
接着在EXTI里要经历一个“边沿检测及控制”的处理:此时输出有两类
→①类是接到NVIC;
接到NVIC就是用来触发中断的,按理说20路输入对应20路输出,在这EXYI9_5合为一个通道,EXTI15_10合为一个通道,也就是使用EXYI9_5会触发一个中断函数,使用EXTI15_10会触发另一中断函数
→②类是接到其他外设;
这里是有20根数据线构成一路输出给其他外设,也就是刚才说的“事件响应”;

实操部分:

一-如何进入中断

以对射红外传感器试验为例

接线图连接

在这里插入图片描述
对射红外传感器的Vcc接面包板的Vcc,GND接面包板的GND,Do数据后随便找一个GPIO口接上;
如此接上,先测以下对射红外传感器好坏,当住传感器凹口,板子输出灯会熄灭,说明能正常输出高低电平;

试验结果

教程演示的应该是,每遮挡一次“对射红外传感器”,“OLED显示屏”显示的数值就会自加1;
“对射式红外传感器”每被遮挡一次,他就会输出一次跳变的信号;

开始写代码-建立工程

继上次OLED显示屏的代码,复制出来继而改造;
还是把这个外传感器的功能封装起来,就继续在Hardware文件下建立CountSensor的.c和.h文件:
在这里插入图片描述
在这里插入图片描述

【重点】功能模块初始化

一般程序都是先写初始化部分

①步配置RCC,把涉及到的外设时钟都打开

涉及的外设包含RCC时钟、GPIOA~G这一列、AFIO、EXTI、NVIC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO
//EXTI和NVIC时钟本来就默认是打开的,故不用配置开启,NVIC属于内核模块
//RCC管不着他,EXTI兼顾唤醒功能也是打开的

②步配置GPIO,设置端口为输入模式

在这里插入图片描述
在这里插入图片描述
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
//对于外设模式选择浮空输入、上拉输入、下拉输入其中的一个,在这给了一个浮空输入
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11 ;//我们用的是B11引脚
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//频率只有输出模式起作用
GPIO_Init(GPIOA, &GPIO_InitStruct);
这是GPIO的配置结果:
在这里插入图片描述

③步配置AFIO,选择我们用的GPIO-连接到EXTI

这个AFIO外设,ST公司并没有给他分配专门的库函数文件,他的库函数是和GPIO在一个文件里,打开stm3210fx_gpio.h拉倒最后,其中有一些就是和AFIO相关的:
350行 void GPIO_AFIODeInit(void);//这个函数是用来复位AFIO的,调用以下这个函数,AFIO外设的配置就会全部清楚;
361行 void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//这个函数是用来锁定GPIO配置的,调用这个函数参数指定某个引脚,那这个引脚的配置就会被锁定,放置意外更改,这个属于GPIO外设的函数,用的不多;
362行 void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
363行 void GPIO_EventOutputCmd(FunctionalState NewState);
//这两个函数是用来配置AFIO的时间输出功能的,用的也不多;
364行 void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
365行 void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
//这两个函数就比较重要了,GPIO_PinRemapConfig()可以用来进行引脚重映射,第一个参数可以选择你要重映射的方式,第二个参数是新的状态;
void GPIO_EXTILineConfig()就是我们本节外部中断需要用到的函数,调用这个函数,就可以配置AFIO的数据选择器,来选择我们想要的中断引脚
366行 void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
//这个是和以太网有关的,我们103f这个芯片没有以太网外设,所以不考虑了

回到keil,AFIO配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//接通PB14引脚
当执行完这个函数后,AFIO的第14个数据选择器就拨好了,其中输入端被拨到GPIOB外设上,对应的就是PB14引脚,输出端固定连接的是EXTI的第14个中断线路,这样PB14号引脚的电平信号就可以顺利通过AFIO,进入后级的EXTI电路了

④步配置EXTI,选择触发方式和选择触发相应方式

我们找到exti.h文件,打开拖到最后,这些就就是EXTI的所有库函数
在这里插入图片描述
158行 void EXTI_DeInit(void);//调用他就可以把EXTI的配置都清除,恢复成上电默认的状态
159行 void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);//调用这个函数,就可以根据这个结构题里的参数配置EXTI外设,我们初始化EXTI主要也是用到的这个函数,使用方法也是和GPIO_Init也是一样的
160行 void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);//调用这个函数,可以把参数传递的结构体变量赋一个默认值,前面这三个函数(158/159/160),基本所有外设都有,就像库函数的模板函数一样,基本每个外设都需要这些类型的函数
161行 void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);//这个函数是用来软件触发外部中断的,调用这个函数,参数给一个指定的中断线,就能软件触发一次这个外部中断
162/163/164/165行 也是库函数的模板函数,一个套路格式的,在外设运行过程中,会产生一些状态标志位,比如外部中断来了,是不是会有一个挂起寄存器置位一个标志位?对于其他外设,比如串口收到数据,也会置位标志位,还有定时器时间到,也会置位标志位,这些标志位都是存放在状态寄存器的,当程序想要看这些标志位时,就用到了162/163/164/165行这四个函数了
162行 FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);//可以获取指定的标志为是否被置1了
163行 void EXTI_ClearFlag(uint32_t EXTI_Line);//可以对置1的标志位进行清除
有些标志位比较紧急,那么他是在中断程序中的,就用到164/165
164行 ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);//获取中断标志位是否被置1了
165行 void EXTI_ClearITPendingBit(uint32_t EXTI_Line);//清除中断挂起标志位

所以总结下,若果你想在主程序例查看和清除标志位,就用162/163,若是想在中断函数中查看和清除标志位,就用164/165这两行

查看EXTI_Line能选什么
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
这是EXTI的配置结果:
在这里插入图片描述

⑤步配置NVIC,给我们中断选一个合适的优先级

找到NVIC库函数,因为NVIC是内核外设,所以他存在了文件的杂项里面了,找到misc.h,拉倒最后就能找到
在这里插入图片描述
196行 void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
//这个函数是用来中断分组的,参数是中断分组的方式
197行 void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
//根据结构体里面指定的参数初始化NVIC
198行 void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
//设置中断相量表,用的不多可以先不看
199行 void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
//系统低功耗配置,用的不多可以先不看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以下是整个EXTI外设的配置结果:

至此外部中断就配置完成,信号从GPIO——AFIO——EXTI——NVIC——CPU,这样才能让CPU由主程序跳转到中断程序执行;
那么执行中断程序,中断程序放到哪呢?
那就需要一个中断函数了,在stm32中,中断函数的名字都是固定的,每个中断通道都对应这一个中断函数;
中断函数的名字我们可以参考以下启动文件:
这里定义了中断相量表,里面以IRQHandler结尾的字符串,就是中断函数的名字,我们可以找到这个EXTI15_10_IRQHandler这一项,中就是EXTI15_10的中断函数,我们复制一下,开始写中断函数,格式:
void EXTI15_10_IRQHandler(void)
{

}
中断函数都是无参数无返回值的,中断函数的名字不要写错了,写错了就进不了中断了,最好是直接从启动文件复制过来,这样就不会有问题了
在写中断函数时,一般都是先来个进行中断标志位的判断,确保是我们想要的中断源触发的这个个中断函数,因为这个函数 EXTI15_10都能进来,具体是哪个呢??所以需要先判断以下是不是我们想要的EXTI11进来的,这时就需要到exti.h里看一下
在这里插入图片描述
至此中断程序就写完了,就是下面这个
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line11)==SET)
{
EXTI_ClearITPendingBit(EXTI_Line11);
}
}

接下来我们试一下他能不能进去中断函数??!!~
剩下别忘了,初始化的函数要声明,中断函数不需要声明,因为他是硬件自动执行,不需要软件声明上的引导;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这是最后的.h声明文件

调试参考

在编译→下载之前,可以使用台式功能查看能不进如中断
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
验证:
这个是进入中断的程序调试,这时在面包板去触发PB11脚,看到结果,断点处多了一个黄色箭头,表示成功进入断点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
重复验证的方法:再此点击“全速运行”→然后在触发PB11脚看结果

浮空输入触发中断结果

在这里插入图片描述
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入模式
浮空输入模式下只要用一个电阻或一根线,一头接触PB11脚,就能触发中断

按键上拉输入触发中断

在这里插入图片描述
在这里插入图片描述

紧接着浮空输入触发中断,我们换成按键能不能触发中断;
只修改如图,的GPIO输入模式,浮空模式换成上拉模式;

按键上拉输入结果

在这里插入图片描述

EXTI外部中断初始化配置总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、【重点】中断处理优先等级(详解)

理论概述

在这里插入图片描述
在这里插入图片描述

这里意思说的是:
①抢占优先级高的会打断抢占优先级低的,无论响应优先级是否高于低于等于;
例:中断2的抢占优先级高于中断1的抢占优先级,忽略响应优先级;
那么中断1正在进行中,中断2就应该能打断中断1;
②响应优先级必须在抢占优先级相同的情况下,才能发生,继而也有三种情形,高、低、相同,值得注意的是响应优先级不存在打断的事情,比较讲道理,论先来后到,谁先来就执行谁;
下面验证下这几种情形,我们预期的结果是:
验证①中断2抢占优先级高于中断1抢占优先级,无论它们的响应优先级高低等与否,中断2都能终止中断1,并执行中断2;分有三种情形(中断2高于中断1;中断2低于中断1;中断2等于中断1;)
验证②中断2和中断①抢占优先级相同的情况下,中断2分三种情形(中断2低于中断1;中断2等于中断1;)它们都不应该打断中断1,而是和中断1平级,谁先来就执行谁;

验证

建立3个中断的程序

方法是在原有1个中断初始化后面再排列2个初始化程序,和中断程序中要增添其他中断进入后做的事情
void CountSensor12_Init(void)//PB12脚中断初始化
{

}
void CountSensor13_Init(void)//PB12脚中断初始化
{

}
void CountSensor14_Init(void)//PB12脚中断初始化
{

}

void EXTI15_10_IRQHandler(void)//中断程序
{
if(EXTI_GetFlagStatus(EXTI_Line12)==SET)
{
CountSensor_Count++;//PB12c触发数值自增1
EXTI_ClearITPendingBit(EXTI_Line12);
}
if(EXTI_GetFlagStatus(EXTI_Line13)==SET)
{
CountSensor_Count–;//PB13触发数值自减1
EXTI_ClearITPendingBit(EXTI_Line13);
}
if(EXTI_GetFlagStatus(EXTI_Line14)==SET)
{
CountSensor_Count++;//PB14触发数值自增1
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
``

情形1-中断2高于中断1

验证中断2抢占优先级高于中断1抢占优先级,无论它们的响应优先级高低等与否,中断2都能终止中断1,并执行中断2;分有三种情形(验证①中断2高于中断1;验证②中断2低于中断1;验证③中断2等于中断1;)
验证①中断2高于中断1
设置中断1抢占优先级居中,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组,设为第2组;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级设为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级设为2
设置中断1无论是抢占优先级还是响应优先级都是居中;
设置中断2抢占优先级比中断1的要高一级,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断分组,设为第1组;
在这里插入图片描述
验证结果
当镊子按住不放PB12(中断1)浮空触发时,数值增加,在这当中,螺丝刀碰触PB13(中断2),数值终止增加而减小,达到了预期的结果

情形2-中断2低于中断1

验证中断2抢占优先级高于中断1抢占优先级,无论它们的响应优先级高低等与否,中断2都能终止中断1,并执行中断2;分有三种情形(验证①中断2高于中断1;验证②中断2低于中断1;验证③中断2等于中断1;)
验证②中断2低于中断1
设置中断1抢占优先级居中,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组,设为第2组;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级设为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级设为2
设置中断1无论是抢占优先级还是响应优先级都是居中;

设置中断2抢占优先级比中断1的要一级,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);//中断分组,设为第3组;
在这里插入图片描述
验证结果
当镊子按住不放PB12(中断1)浮空触发时,数值增加,在这当中,螺丝刀碰触PB13(中断2),数值并没有终止增加而减小,达到了预期的结果

情形3-中断2抢占优先级等于中断1抢占优先级

验证中断2抢占优先级等于中断1抢占优先级,这时候响应优先级发挥作用,但是不存在打断的情型,即使你响应优先级高,这里中断1和中断2的响应优先级高、中断2的响应优先级低、中断2的响应优先级等是平级关系,谁先触发就执行谁;
验证的前提:中断2抢占优先级等于中断1抢占优先级;
分有三种情形
验证①中断2响应优先级高于中断1响应优先级;
验证②中断2响应优先级低于中断1响应优先级;
验证③中断2响应优先级等于中断1响应优先级;
验证①中断2响应优先级高于中断1响应优先级;
设置中断1抢占优先级居中,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断1分组,设为第2组;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级设为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级设为2
设置中断1无论是抢占优先级还是响应优先级都是居中;
设置中断2抢占优先级和中断1抢占优先级相同,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断2分组,设为第2组;
设置中断2响应优先级高于中断1的响应优先级,那就是
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级设为1
在这里插入图片描述
验证结果
当镊子按住不放PB12(中断1)浮空触发时,数值增加,在这当中,螺丝刀碰触PB13(中断2),数值并没有终止增加而减小,PB12和PB13会单独独立触发运行,谁先到就先执行谁,互不关联达到了预期的结果

验证②中断2响应优先级低于中断1响应优先级;
设置中断1抢占优先级居中,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断1分组,设为第2组;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级设为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级设为2
设置中断1无论是抢占优先级还是响应优先级都是居中;
设置中断2抢占优先级和中断1抢占优先级相同,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断2分组,设为第2组;
设置中断2响应优先级低于中断1的响应优先级,那就是
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;//响应优先级设为3
在这里插入图片描述
验证结果
当镊子按住不放PB12(中断1)浮空触发时,数值增加,在这当中,螺丝刀碰触PB13(中断2),数值并没有终止增加而减小,PB12和PB13会单独独立触发运行,谁先到就先执行谁,互不关联达到了预期的结果

验证③中断2响应优先级等于中断1响应优先级;
设置中断1抢占优先级居中,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断1分组,设为第2组;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级设为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级设为2
设置中断1无论是抢占优先级还是响应优先级都是居中;
设置中断2抢占优先级和中断1抢占优先级相同,那就是NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断2分组,设为第2组;
设置中断2响应优先级低于中断1的响应优先级,那就是
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级设为2
在这里插入图片描述
验证结果
当镊子按住不放PB12(中断1)浮空触发时,数值增加,在这当中,螺丝刀碰触PB13(中断2),数值并没有终止增加而减小,PB12和PB13会单独独立触发运行,谁先到就先执行谁,互不关联达到了预期的结果

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值