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

细说MCU检测按键输入的外部中断和修改HAL_GPIO_EXTI_IRQHandler() 的实现方法

目录

一、 硬件板及设计目的  

二、建立工程

1.配置GPIO

2.配置时钟源和Debug     

3.配置系统时钟   

4.配置NVIC

三、代码编写

四、修改HAL_GPIO_EXTI_IRQHandler() 


一、 硬件板及设计目的  

        本文使用的硬件板是ST的开发板NUCLEO-G474RE,板上MCU型号为STM32G474RET6。并按照资源提示设计制造了扩展IO板,有需要此扩展板的留言联系我。

        本例设计目的及其功能和操作流程如下。        

  • 按下KeyLeft键时,使LED1的输出翻转。
  • 按下KeyRight键时,使LED2的输出翻转。
  • 按下KeyUp键时,使LED1和LED2的输出都翻转。
  • KeyDown键按下时,产生EXTI0软中断,模拟KeyUp键按下。

用户标签

引脚名称

引脚功能

GPIO模式

默认电平

上拉或下拉

LED1

PB11

GPIO_Output

推挽输出

High

上拉

LED2

PB12

GPIO_Output

推挽输出

High

上拉

KeyRight

K1

PA0

EXTI0

输入

上拉

KeyDown

K2

PA1

EXTI1

输入

上拉

KeyLeft

K3

PA6

EXTI[9:5]

输入

上拉

KeyUp

K5

PA7

EXTI[9:5]

输入

上拉

二、建立工程

1.配置GPIO

  • 配置PB11、PB12,GPIO OUTPUT,默认High Level,PP,PullUp,High Speed,标识为LED1,LED2;
  • 配置PA0,EXTI0,PP,标识为:KeyRight;
  • 配置PA1,EXTI1,PP,标识为:KeyDown;
  • 配置PA6,EXTI[9:5],PP,标识为:KeyLeft;
  • 配置PA7,EXTI[9:5],PP,标识为:KeyUp;

2.配置时钟源和Debug     

        打开System Core中的RCC,高速时钟(HSE)选择Crystal/ eramic Resonator,使用片外时钟晶体作为HSE的时钟源。在SYS中将Debug设置Serial Wire。

3.配置系统时钟   

        将系统时钟(SYSCLK)频率配置为170 MHz。

4.配置NVIC

        配置Time base的抢占式优先级为0;配置EXTI0、EXTI1的抢占式优先级为1;配置EXTI[9:5]的抢占式优先级为2;这样处理后,当优先级1的中断执行期间,触发优先级为2的中断时不会及时响应,直到优先级为1的中断执行完毕,才去执行优先级为2的中断。

三、代码编写

        为实现设计目的,只需要在main.c的程序里添加外部中断的回调函数就可以。

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){if  (GPIO_Pin == KeyUp_Pin)  		//PA7=KeyUp, 使两个LED输出翻转{HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);HAL_Delay(500);					//软件消除按键抖动的影响}else if(GPIO_Pin == KeyRight_Pin)	//PA0=KeyRight, 使LED2 输出翻转{HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);HAL_Delay(500);					//软件消除按键抖动的影响,观察优先级的作用}else if (GPIO_Pin == KeyDown_Pin)	//PA1=KeyDown,产生EXTI0 软中断{__HAL_GPIO_EXTI_GENERATE_SWIT(GPIO_PIN_0);	//产生EXTI0 软中断HAL_Delay(500);					//这个延时也是必要的,否则由于按键抖动,会两次触发}else if (GPIO_Pin == KeyLeft_Pin)	//PA6=KeyLeft,  使LED1输出翻转{HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);HAL_Delay(1000);				//软件消除按键抖动的影响,观察优先级的作用}}/* USER CODE END 4 */

四、修改HAL_GPIO_EXTI_IRQHandler() 

        完成回调函数的代码后,下载到开发板上进行测试时,按键按下后的响应并不如预期(预期的现象是每按下一个按键,翻转对应的LED,再次按下按键,再翻转)。例如按下 Keyup键后,两个LED会出现无规律的现象:亮灭两次、或不亮、或亮了后又熄灭,这不是按键抖动影响的。这是由ISR中调用的外部中断通用处理函数HAL_GPIO_EXTI_IRQHandler()的代码引起的,这个函数的代码如下:

/*** @brief  Handle EXTI interrupt request.* @param  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.* @retval None*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{/* EXTI line interrupt detected */if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u){__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);HAL_GPIO_EXTI_Callback(GPIO_Pin);}
}

        这个函数在检测到中断挂起标志后,先清除中断挂起标志,然后再执行回调函数。一般的中断通用处理函数都是这样的处理流程,是为了硬件能及时响应下一次中断。但是对于检测按键输入的外部中断,这是有问题的,因为清除中断挂起标志后,按键的抖动就会触发下一次中断,并将中断挂起标志置位。虽然在回调函数里使用了延时,但是回调函数退出后,NVIC检测到中断挂起标志被置位,就会再执行一次回调函数。

        所以,对于外部中断方式的按键输入检测,需要修改一下HAL_GPIO_EXTI_IRQHandler() 的代码,将清除中断挂起标志位的功能放在后面,即修改为如下的代码,这样修改后的程序运行就实现了设计想要达到的目的了。

/*** @brief  Handle EXTI interrupt request.* @param  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.* @retval None*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{/* EXTI line interrupt detected */if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u){HAL_GPIO_EXTI_Callback(GPIO_Pin);__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);}
}

        需要注意的是,函数HAL_GPIO_EXTI_IRQHandler()是文件stm32g4xx_hal_gpio.c中的,这是HAL驱动的原始文件,这个函数里并没有代码沙箱,也不是弱函数,不可以重写。修改这个函数的代码后,在CubeMX 重新生成代码时,这个函数的代码又会变成原来的样子。所以,一定要记得再次改回去。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 贪吃蛇(使用QT)
  • 连接投影仪/显示器只能扩展不能复制的解决方案
  • 七夕警示:探索社工库与网络搜索下的个人隐私泄露与保护策略
  • 机器学习西瓜书笔记(五) 第五章神经网络+代码
  • Mybatis(Day 18)
  • 代码随想录算法刷题训练营day49:LeetCode(42)接雨水、LeetCode(84)柱状图中最大的矩形
  • Less 教程:从入门到精通
  • Golang | Leetcode Golang题解之第329题矩阵中的最长递增路径
  • 如何有效构建企业微信私域流量池并提升用户粘性?
  • LinuxC++(10):调用可执行程序
  • 【实现100个unity特效之16】unity2022之前或者之后版本实现全屏shader graph的不同方式 —— 适用于人物受伤红屏或者一些其他状态效果
  • 2024年8月8日(python基础)
  • 开源应用:AI监测如何成为社会安全的智能盾牌
  • 【Week-G7】Semi-Supervised GAN 实践,使用MNIST数据集
  • Oracle DBA常用 sql
  • python3.6+scrapy+mysql 爬虫实战
  • Akka系列(七):Actor持久化之Akka persistence
  • Centos6.8 使用rpm安装mysql5.7
  • ES6系列(二)变量的解构赋值
  • ES6之路之模块详解
  • Java面向对象及其三大特征
  • JS基础之数据类型、对象、原型、原型链、继承
  • Laravel Telescope:优雅的应用调试工具
  • python学习笔记-类对象的信息
  • React-Native - 收藏集 - 掘金
  • 规范化安全开发 KOA 手脚架
  • 使用parted解决大于2T的磁盘分区
  • 使用权重正则化较少模型过拟合
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • elasticsearch-head插件安装
  • UI设计初学者应该如何入门?
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​【数据结构与算法】冒泡排序:简单易懂的排序算法解析
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • ​批处理文件中的errorlevel用法
  • #Java第九次作业--输入输出流和文件操作
  • #Linux(帮助手册)
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (09)Hive——CTE 公共表达式
  • (13)Hive调优——动态分区导致的小文件问题
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2)STM32单片机上位机
  • (42)STM32——LCD显示屏实验笔记
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (分享)自己整理的一些简单awk实用语句
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)ssm码农论坛 毕业设计 231126
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (一)VirtualBox安装增强功能
  • (转)Unity3DUnity3D在android下调试
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • .NET值类型变量“活”在哪?