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

相关文章

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa

Java -jar命令如何运行外部依赖JAR包

《Java-jar命令如何运行外部依赖JAR包》在Java应用部署中,java-jar命令是启动可执行JAR包的标准方式,但当应用需要依赖外部JAR文件时,直接使用java-jar会面临类加载困... 目录引言:外部依赖JAR的必要性一、问题本质:类加载机制的限制1. Java -jar的默认行为2. 类加

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

MySQL基本查询示例总结

《MySQL基本查询示例总结》:本文主要介绍MySQL基本查询示例总结,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Create插入替换Retrieve(读取)select(确定列)where条件(确定行)null查询order by语句li

C#通过进程调用外部应用的实现示例

《C#通过进程调用外部应用的实现示例》本文主要介绍了C#通过进程调用外部应用的实现示例,以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序,具有一定的参考价值,感兴趣的可以了解一下... 目录窗口程序类进程信息类 系统设置类 以WINFORM应用程序为例,在C#应用程序中调用python程序

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)