大家好,欢迎来到IT知识分享网。
STM32学习笔记(三)——STM32的中断
STM32学习笔记(一)——STM32介绍
一、中断编程的原理
1.1 什么是中断
1.1.1 生活中的中断
中断:正在进行的事务被突发事件打断,转而去处理这个突发事件,突发事件处理完成后回到被打断的事务继续执行,这一处理突发事件的过程叫中断
1.1.2 单片机中的中断
常规程序:main方法和被main方法调用的程序;由于main方法的执行而得到执行的程序,叫常规程序
用电脑给STM32串口发送程序,只要电脑发来了数据,STM32就必须马上处理这个数据,如果不及时处理,电脑发送新的数据,就会覆盖之前传送的数据,造成数据的丢失
为了实现,来了数据,立马处理这个数据的功能,我们写了一个方法(也就说写了一个函数,函数内部代码的功能为,先接收数据,再处理数据)
流程为:
我们将这样突发的事件,叫中断源
在main中程序叫常规程序
由于中断源触发而调用的程序叫中断响应函数
1.1.3 为什么要使用中断
1.2 中断处理过程
1.3 中断的优先级
中断优先级:
- 优先级的值小,优先级越高
- 抢占优先级高的中断会对抢占优先级低的发生中断嵌套
- 发生中断嵌套时,会发生排队,总优先级高的中断排在前面
例子1:
执行A中断的过程总发生了中断B和C.
中断A先发生,而后中断B发生, 但中断B的抢占优先级高,所以发生中断嵌套
例子2:
执行A中断的过程总发生了中断B和C.
中断A先发生,而后中断B和C同时发生, 且B和C的抢占优先级不比A的高,不发生中断嵌套
但需要判断B和C的中断优先级B为1100(12) C为0101(5) 根据优先级数低的优先级高,所以C先发生
例子3:
执行A中断的过程总发生了中断B和C.
中断A先发生,而后中断B和C同时发生, 且B和C的抢占优先级不比A的高,不发生中断嵌套
但需要判断B和C的中断优先级B为0101(5) C为0100(4) 根据优先级数低的优先级高,所以C先发生
1.4 两种中断源类型
1.5 中断源的四种状态
二、STM32的NVIC
2.1 NVVIC简介
NVIC(Nested Vectored Interrupt Controller)嵌套中断向量控制器,是一种核心外设,位于Cortex-M3内核中,负责管理中断
2.2 中断协作模型
2.3 NVIC的内部结构
中断优先级分组:我们可以根据需要,设置不同的分组方式
2.4 中断向量表
Flash存储器中,有各种代码,CPU在中断发生时,如何定位是执行这个中断的中断响应函数呢?
中断向量表:看成一个目录,Flash存储器内部从地址0开始的一段区域,按照中断号排列,每4个字节(STM32是32位处理器,1个字节8bit,4字节正好32位)存储一个中断响应函数地址
2.5 NVIC编程
NVIC_PriorityGroupConfig()函数详解:
NVIC_Init()
2.6 NVIC编程实例
根据中断编程模型,将中断编程分为三个部分:
问题1:如何让片上外设产生中断源?
- 不同的片上外设开启方式不同
- USART1外设开启某中断源的方法:USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
问题2:如何配置NVIC?
- 为啥NVIC不用开启时钟?因为NVIC在内核里,只要一上电就有时钟(大脑不能休眠)
- 1.设置中断优先级分组
- 2.填写初始化调查问卷(写名,填问题)
问题3:如何编写中断响应函数
- 弱方法:标注为weak的方法可以被同名的方法覆盖,一开始中断向量表指向的是弱方法进行占位,当我们编写同名函数后,就指向了我们所编写的函数代码
- 步骤:
- 在.s文件中找到中断响应函数
- 写一个同名函数覆盖它 void xxx_IRQHandler(void){}v
void USART1_IRQHandler(void) { //具体的中断响应代码//主函数外部 }
三、STM32的EXTI简介
3.1 EXTI简介
3.2 EXTI的内部结构
3.3 EXTI的通道
EXTI这么多通道用来作什么呢?
- 让所有的IO口都具有触发中断的能力
使用PA0触发外部中断了 就不能使用PB0、PC0…了
- 其它功能
3.4 EXTI的寄存器组
3.4 EXTI的标准库编程
3.4.1 EXTI标准库编程接口
EXTI_Init():
- 初始化EXTI20个通道中的某一个
- 参数结构体指针类型(填调查问卷方式)
例子:
EXTI_GenerateSWInterrupt()
- 产生软件中断
EXTI_GetFlagStatus()
- 获取中断标志位(硬件图中的4,获取中断挂起的bit位)
EXTI_ClearFlag()
- 清除标志位(硬件图中的4,清楚中断挂起的bit位)
EXTI_GetITStatus()
- 中断屏蔽寄存器与上中断挂起寄存器的值,中断屏蔽开关闭合同时中断被触发,中断挂起寄存器值也为1,函数才返回1
EXTI_ClearITPendingBit()
- 同EXTI_ClearFlag()
3.4.2 EXTI标准库编程实验
3.4.2.1 实验介绍
3.4.2.2 实验思路
GPIO片上外设:对按键使用的IO进行初始化
AFIO片上外设:EXTI有20个通道,拿出0-15个通道,对应GPIOx的0-15号引脚,引脚组x由AFIO选择,通过复用器选择编号
EXTI片上外设:使用外部中断,产生中断源
NVIC核内外设:配置中断参数
- 找到.s文件
- 写同名函数覆盖
函数里写:- 清除中断源 EXTI_ClearITPendingBit(EXTI_Line1);
- 编写功能函数
#include "stm32f10x.h" #include "stm32f10x_pal.h" int main(void) {
//4.1设置中断优先级分组 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); PAL_Init(); //1.初始化IO引脚 //将PA0和PA1分别设置为输入上拉模式 //开启GPIOA的时钟 RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,ENABLE); //PA0,PA1 GPIO_InitTypeDef GPIOInitStruct; GPIOInitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA,&GPIOInitStruct); //2.配置EXTI的引脚映射 //开启AFIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //PA0->EXTI0 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //PA1->EXTI1 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); //3.配置EXTI //3.1初始化EXTI0 EXTI_InitTypeDef EXTIInitStruct; EXTIInitStruct.EXTI_Line = EXTI_Line0; EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTIInitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTIInitStruct); //3.2初始化EXTI1 EXTIInitStruct.EXTI_Line = EXTI_Line1; EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTIInitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTIInitStruct); //4.初始化NVIC //4.2初始化某一路的中断 NVIC_InitTypeDef NVICInitStruct; //4.2.1EXTI0 NVICInitStruct.NVIC_IRQChannel = EXTI0_IRQn; NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVICInitStruct.NVIC_IRQChannelSubPriority = 2; NVICInitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVICInitStruct); //4.2.2EXTI1 NVICInitStruct.NVIC_IRQChannel = EXTI1_IRQn; NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVICInitStruct.NVIC_IRQChannelSubPriority = 2; NVICInitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVICInitStruct); //5.初始化PC13 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //open-drain开漏模式 GPIOInitStruct.GPIO_Pin = GPIO_Pin_13; GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC,&GPIOInitStruct); while(1) {
} } void EXTI0_IRQHandler(void) {
//清除中断 EXTI_ClearITPendingBit(EXTI_Line0); //点亮LED-向PC13写0 GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); } void EXTI1_IRQHandler(void) {
//清除中断 EXTI_ClearITPendingBit(EXTI_Line1); //熄灭LED GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); }
若是PA5和PA6产生中断,其中断处理函数为同一个,在调用中断处理函数时,怎么知道是哪个中断产生的呢?
- 只需要判断其中断挂起寄存器的值,若为1,则代表是这个中断源产生的中断
#include "stm32f10x.h" #include "stm32f10x_pal.h" int main(void) {
//4.1设置中断优先级分组 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); PAL_Init(); //1.初始化IO引脚 //将PA0和PA1分别设置为输入上拉模式 //开启GPIOA的时钟 RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,ENABLE); //PA0,PA1 GPIO_InitTypeDef GPIOInitStruct; GPIOInitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA,&GPIOInitStruct); //2.配置EXTI的引脚映射 //开启AFIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //PA0->EXTI0 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5); //PA1->EXTI1 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6); //3.配置EXTI //3.1初始化EXTI0 EXTI_InitTypeDef EXTIInitStruct; EXTIInitStruct.EXTI_Line = EXTI_Line5; EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTIInitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTIInitStruct); //3.2初始化EXTI1 EXTIInitStruct.EXTI_Line = EXTI_Line6; EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTIInitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTIInitStruct); //4.初始化NVIC //4.2初始化某一路的中断 NVIC_InitTypeDef NVICInitStruct; //4.2.1EXTI0 NVICInitStruct.NVIC_IRQChannel = EXTI9_5_IRQn; NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVICInitStruct.NVIC_IRQChannelSubPriority = 2; NVICInitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVICInitStruct); //4.2.2EXTI1 //5.初始化PC13 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //open-drain开漏模式 GPIOInitStruct.GPIO_Pin = GPIO_Pin_13; GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC,&GPIOInitStruct); while(1) {
} } void EXTI9_5_IRQHandler(void) {
if(EXTI_GetITStatus(EXTI_Line5) == SET)//EXTI {
EXTI_ClearITPendingBit(EXTI_Line5); //清除中断 GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); } //不写if else原因:可能同时为1 两个都执行 if(EXTI_GetITStatus(EXTI_Line6) == SET) {
EXTI_ClearITPendingBit(EXTI_Line6);//清除中断 GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); } }
3.5 EXTI的标准库编程方法总结
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/114291.html













































