当前位置: 首页 > article >正文

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);
	
}

http://www.kler.cn/a/292698.html

相关文章:

  • C语言入门到精通(第六版)——第十六章
  • 从社交媒体到元宇宙:Facebook未来发展新方向
  • HBase理论_背景特点及数据单元及与Hive对比
  • NAT网络工作原理和NAT类型
  • Java的dto,和多表的调用
  • 11张思维导图带你快速学习java
  • 基于springboot的二手车交易系统的设计与实现
  • 在 Cloud TPU Pod 上训练 PyTorch 模型
  • Java重修笔记 第四十八天 TreeSet 类、TreeMap 类
  • 计算机毕设选题推荐-基于python的剧本杀预约服务平台【python-爬虫-大数据定制】
  • 人工智能在网络安全中的重要性
  • 一文讲懂扩散模型
  • 安装opengauss企业版单机流程
  • 【GD32】---- 使用GD32调试串口并实现printf打印输出
  • 修改服务器DNS解析及修改自动对时时区
  • 【Motion Forecasting】SIMPL:简单且高效的自动驾驶运动预测Baseline
  • AI时代来临,AI基础数据服务行业未来发展有哪些变化
  • 产品经理的学习笔记(全集)-持续更新
  • 基础算法题————散列/哈希/Hash
  • ElasticSearch-倒排索引 文档映射
  • 深入理解JavaScript闭包:避免常见的内存泄漏问题
  • 深度学习|模型推理:端到端任务处理
  • 【Netty】自定义网络通信协议
  • FFmpeg源码:avpriv_set_pts_info函数分析
  • SpringBoot 实战:SpringBoot整合Flink CDC,实时追踪mysql数据变动
  • Java简单实现服务器客户端通信