你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 GPIO—按键轮询

[复制链接]
STMCU小助手 发布时间:2022-4-28 20:53
12.1 关于按键
前面控制LED灯是让GPIO输出高低电平,而获取按键则是读取GPIO电平,从而获知用户是否按下按键。

按键监测一般有两种:按键扫描和按键中断。按键扫描是间隔很短时间反复查询GPIO状态,从而得知是否有按键动作,这种方式代码简单,但比较耗资源。按键中断而是通过按键产生中断信号,从而实现按键的检测,这种方式需要使用到中断机制,需要对MCU了解深入一点,效果是最好的。

本节先介绍按键扫描,理解按键的基本原理,下一章再介绍按键中断,同时了解STM32F103的中断使用方法。

按键一般占用一个GPIO口,通过监测该GPIO的电平变化得知按键操作,典型的电路如图 12.1.1 所示。当所需按键比较多时,则可以采用矩阵按键减少GPIO的占用。矩阵按键需要通过编程扫描等方式实现对多个按键的监控,这里以最简单的独立按键为基础进行介绍。

HCXQS2@B6Z%8(G)O$}H`{}A.png

图 12.1.1 按键与MCU的连接方式示意图
可以看到,在没有按下按键时,电源3.3V通过电阻连接到MCU的PA0脚上,此时MCU读取PA0的电平就是3.3V的高电平。在按键按下时,电源3.3V经过电阻,再经过按键连接到了地,此时PA0连接到接地的一端,读到的电平就是0V的低电平。由此,MCU就可用过读取对应引脚的电平值,得知按键的变化。

常用的按键都是机械触点式按键,机械式按键在按下或释放的过程中,由于机械弹性作用的影响,会伴随机械抖动,如图 12.1.2 所示。


J}%W8`E]}Q(CJPAEPFG8FA2.png

图 12.1.2 机械按键抖动示意图


抖动的时长与机械开关特性相关,一般为5-10ms。在这抖动过程中,会产生多次高低电平,导致被识别为多次按键操作。为了避免机械触点按键检测误判,必须消抖处理。按键消抖可以硬件上处理,即在按键旁并联电容,吸收抖动的电平。也可以软件处理,即通过延时,避开抖动。

由此,首先获取对应引脚的电平得知按键状态,再硬件或软件消除抖动。


12.2 硬件设计
开发板上有两个按键,一个是复位按键(K1,红色),另一个是用户按键(K2,白色),这里只有用户按键能够编程控制。

如图 12.2.1 为开发板用户按键部分的原理图,电容C15用于硬件去抖,可以看作不存在。按键松开时,3V3经过上拉电阻R20到网络标号KEY,网络标号KEY另一端连接MCU的PA0,此时读取PA0电平为高电平;按键按下时,3V3经过上拉电阻R20,再通过按键接地,此时读取PA0电平为低电平。

由此可知,按键按下,GPIO引脚电平变低,反之为高,按键所接GPIO为PA0。

FU[36R~I8ZR%]K%{3L@E2~E.png

图 12.2.1 用户按键原理图


12.3 软件设计
1.3.1 软件设计思路
实验目的:本实验通过轮询读方式取GPIO的输入电平判断按键是否按下,并操作LED。

1) 按键初始化:GPIO端口时钟使能、GPIO引脚设置为输入(PA0);

2) 封装每个按键处理函数:读取按键GPIO状态,操作LED灯亮灭;

3) 主函数轮询按键状态:一直检测是否有按键被按下;

本实验配套代码位于“5_程序源码\5_GPIO—按键轮询\”。


1.3.2 软件设计讲解
1) GPIO宏定义与接口宏定义

代码段 12.3.1 引脚宏定义(driver_key.h)

  1. /*********************

  2. * 按键引脚状态定义

  3. **********************/

  4. #define PUSH_DOWN                       GPIO_PIN_RESET

  5. #define SPRING_UP                       GPIO_PIN_SET



  6. /*********************

  7. * 引脚宏定义

  8. **********************/

  9. #define KEY_GPIO_PIN                 GPIO_PIN_0

  10. #define KEY_GPIO_PORT                GPIOA

  11. #define KEY_GPIO_CLK_EN()            __HAL_RCC_GPIOA_CLK_ENABLE()



  12. /*********************

  13. * 函数宏定义

  14. **********************/

  15. /*

  16. * 按键状态读取函数宏定义

  17. */

  18. #define KEY                  HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_GPIO_PIN)
复制代码


根据硬件设计选定的对应按键的引脚,将其宏定义命名为KEY,且对他们的读取函数进行重命名。其中“HAL_GPIO_ReadPin()”原型“GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)”,参数依次是:引脚组,引脚号,返回的是0(低电平)或1(高电平)。


2) GPIO初始化

代码段 12.3.2 按键初始化(driver_key.c)

  1. /*

  2. *  函数名:void KeyInit(void)

  3. *  输入参数:无

  4. *  输出参数:无

  5. *  返回值:无

  6. *  函数作用:初始化按键的引脚,配置为输入

  7. */

  8. void KeyInit(void)

  9. {

  10.     // 定义GPIO的结构体变量

  11.     GPIO_InitTypeDef GPIO_InitStruct = {0};

  12.     // 使能按键的GPIO对应的时钟

  13.     KEY_GPIO_CLK_EN();



  14.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;             // 设置为输入模式

  15.     GPIO_InitStruct.Pull = GPIO_PULLUP;                 // 默认上拉

  16.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;       // 引脚反转速度设置为快



  17.     // 初始化按键引脚配置

  18.     GPIO_InitStruct.Pin = KEY_GPIO_PIN;              // 选择按键的引脚

  19.     HAL_GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStruct);

  20. }
复制代码

使能时钟,将引脚初始化为上拉输入。


3) 按键读取函数

为了展示效果,编写代码查询按键是否按下,按下后切换LED灯亮灭状态。

代码段 12.3.3 按键读取函数(driver_key.c)

  1. /*

  2. *  函数名:void KeyPolling(void)

  3. *  输入参数:无

  4. *  输出参数:无

  5. *  返回值:无

  6. *  函数作用:使用轮询方式查询按键是否按下,通过按下控制LED灯亮灭

  7. */

  8. static bool key_flag = false;

  9. void KeyPolling(void)

  10. {

  11.     if(KEY == PUSH_DOWN)          // 如果检测到按键被按下

  12.     {

  13.         HAL_Delay(8);             // 延时8ms防按键抖动

  14.         if(KEY == PUSH_DOWN)      // 如果防抖动后按键依然是处于被按下的状态,就认为按键被按下过

  15.         {

  16.             key_flag = !key_flag; // 用一个标志位来判断按键被按下次数,按下一次灯亮,再按一次灯灭,如此反复

  17. BLED(key_flag?OFF:ON);

  18.         }

  19.     }

  20. }
复制代码

8行:定义了一个全局变量标志位“key_flag”,作为按键被按下的标志;

11行:获取该按键状态;

13行:延时5-10ms,软件去抖;

14行:再次获取该按键状态,此时依旧按下,说明是正常按键操作,非抖动;

16行:将标志位置反,按键按一次置反一次(即0->1->0->1这样循环);

17行:根据标志位“key_flag”的值,让LED灯亮或灭;

此时每按下一次按键键,蓝色LED灯将亮灭交替。


4) 主函数测试

代码段 12.3.4 主函数控制逻辑(main.c)

  1. // 初始化LED

  2. LedGpioInit();

  3. // 初始化按键

  4. KeyInit();



  5. while(1)

  6. {

  7.     // 轮询按键键

  8.     KeyPolling();

  9. }
复制代码

1~4行:初始化LED灯和按键;

6~10行:一直循环查询每个按键当前状态,从而判断对应按键是否按下;

12.4 实验效果
本实验对应配套资料的“5_程序源码\5_GPIO—按键轮询\”。打开工程后,编译,下载。按下按键,用户LED灯亮/灭。


收藏 评论0 发布时间:2022-4-28 20:53

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版