STM32外部中断(总结了易出现的BUG)

2024-09-02 05:20
文章标签 总结 中断 stm32 bug 外部

本文主要是介绍STM32外部中断(总结了易出现的BUG),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文主要讲述了,本人在使用STM32F103C8T6做项目时,使用到按键触发外部中断时,发现无法触发外部中断。通过查看寄存器找出问题的过程,并总结了出现该问题的原因。

出现的问题

在使用STM32F103C8T6做一个矩阵键盘任务时,发现了不规范使用标准库导致外部中断无法触发。
下面是实验时的部分原理图:
矩阵键盘原理图在这里插入图片描述

代码思路:让IO口PB12、PB13、PB14、PB15输出低电平,IO口PB8、PB9、PB10、PB11外部中断下降沿触发,检测按键是否按下。如果外部中断触发成功,LED指示灯将会被点亮。但是实际现象是怎么按按键,指示灯也不亮。并且使用在线仿真在外部中断处打断点也无法进入中断。(这段代码是之前成功案例复制过来的,只是进行了适当修改)
下面是有问题的代码:

在这里插入代码片
int main(void)
{	LED_Init();						//LED函数初始化(LED函数在HARDWARE文件夹中)LED_OFF();                      //关闭LED指示灯delay_init();Key_Exti_init();while(1)							//死循环,使得LED一直亮{                                   //将4个IO口输出低,确保随机按下哪个按钮,入IO口都能拉低,方便测试外部中断是否有用GPIO_ResetBits(GPIOB,GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_14);GPIO_ResetBits(GPIOB,GPIO_Pin_13);GPIO_ResetBits(GPIOB,GPIO_Pin_12);}	
}
//按键初始化函数
void KEY_Init(void) //IO初始化
{ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//使能GPIOB时钟//输出口GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置推挽输出GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOE2,3,4//输入口GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //上拉输入GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.0}
void Key_Exti_init(void)
{EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;KEY_Init();GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8|GPIO_PinSource9|GPIO_PinSource10|GPIO_PinSource11);EXTI_InitStructure.EXTI_Line=EXTI_Line8|EXTI_Line9|EXTI_Line10|EXTI_Line11;EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd=ENABLE;EXTI_Init(&EXTI_InitStructure);NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn|EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;NVIC_Init(&NVIC_InitStructure);
}
void EXTI9_5_IRQHandler(void)
{LED_ON();                     //当触发外部中断,指示灯点亮delay_ms(10);if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==RESET && EXTI_GetITStatus(EXTI_Line8)==SET){}if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==RESET && EXTI_GetITStatus(EXTI_Line9)==SET){}EXTI_ClearITPendingBit(EXTI_Line8);EXTI_ClearITPendingBit(EXTI_Line9);	
}
void EXTI15_10_IRQHandler(void)
{LED_ON();delay_ms(10);if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==RESET && EXTI_GetITStatus(EXTI_Line10)==SET){}if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==RESET && EXTI_GetITStatus(EXTI_Line11)==SET){}EXTI_ClearITPendingBit(EXTI_Line10);EXTI_ClearITPendingBit(EXTI_Line11);}

问题分析过程和解决过程

通过对数据手册外部中断、AFIO寄存器、NVIC寄存器章节进一步阅读,并通过在线仿真DUG查看寄存器是否置位,最终发现问题所在。
DUG时发现AFIO寄存器和NVIC控制外部中断的寄存器没有置位。具体看下图。
图2-1 EXTI寄存器
如图2-1可看出该寄存器已经被设置了,没有问题。
图2-1 AFIO寄存器
根据数据手册的描述当使用这些口做外部中断时EXTI8、EXTI9、 EXTI10 、EXTI11寄存器需要都赋值为0X01。与图2-1对比发现寄存器值不对,因此这个寄存器设置出现了 问题。
图2-3 NVIC寄存器
根据数据手册图2-3的寄存器设置也出现了问题。

结果

最终通过排查发现是下面使用代码使用不规范导致的错误:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8|GPIO_PinSource9|GPIO_PinSource10|GPIO_PinSource11);NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn|EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStructure);

将上面代码段改成下面代码段就可以解决BUG:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource10);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource11);NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStructure);

下面三张图片是解决BUG后寄存器的值
在这里插入图片描述
在这里插入图片描述

)在这里插入图片描述

最终修改后的代码如下

int main(void)
{	LED_Init();						//LED函数初始化(LED函数在HARDWARE文件夹中)LED_OFF();                      //关闭LED指示灯delay_init();Key_Exti_init();while(1)							//死循环,使得LED一直亮{                                   //将4个IO口输出低,确保随机按下哪个按钮,入IO口都能拉低,方便测试外部中断是否有用GPIO_ResetBits(GPIOB,GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_14);GPIO_ResetBits(GPIOB,GPIO_Pin_13);GPIO_ResetBits(GPIOB,GPIO_Pin_12);}	
}
//按键初始化函数
void KEY_Init(void) //IO初始化
{ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//使能GPIOB时钟//输出口GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置推挽输出GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOE2,3,4//输入口GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //上拉输入GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.0}
void Key_Exti_init(void)
{EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;KEY_Init();GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource10);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource11);EXTI_InitStructure.EXTI_Line=EXTI_Line8|EXTI_Line9|EXTI_Line10|EXTI_Line11;EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd=ENABLE;EXTI_Init(&EXTI_InitStructure);NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;NVIC_Init(&NVIC_InitStructure);
}
void EXTI9_5_IRQHandler(void)
{LED_ON();                     //当触发外部中断,指示灯点亮delay_ms(10);if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==RESET && EXTI_GetITStatus(EXTI_Line8)==SET){}if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==RESET && EXTI_GetITStatus(EXTI_Line9)==SET){}EXTI_ClearITPendingBit(EXTI_Line8);EXTI_ClearITPendingBit(EXTI_Line9);	
}
void EXTI15_10_IRQHandler(void)
{LED_ON();delay_ms(10);if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==RESET && EXTI_GetITStatus(EXTI_Line10)==SET){}if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==RESET && EXTI_GetITStatus(EXTI_Line11)==SET){}EXTI_ClearITPendingBit(EXTI_Line10);EXTI_ClearITPendingBit(EXTI_Line11);}

这篇关于STM32外部中断(总结了易出现的BUG)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129109

相关文章

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作