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

相关文章

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

前端bug调试的方法技巧及常见错误

《前端bug调试的方法技巧及常见错误》:本文主要介绍编程中常见的报错和Bug,以及调试的重要性,调试的基本流程是通过缩小范围来定位问题,并给出了推测法、删除代码法、console调试和debugg... 目录调试基本流程调试方法排查bug的两大技巧如何看控制台报错前端常见错误取值调用报错资源引入错误解析错误

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

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