第12章     GPIO输入—按键检测

全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn

野火视频教程优酷观看网址:http://i.youku.com/firege

本章参考资料:《STM32F4xx参考手册》、库帮助文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。

按键检测使用到GPIO外设的基本输入功能,本章中不再赘述GPIO外设的概念,如您忘记了,可重读前面"GPIO框图剖析"小节,STM32标准库中GPIO初始化结构体GPIO_TypeDef的定义与"定义引脚模式的枚举类型"小节中讲解的相同。

12.1 硬件设计

按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生图 121中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。本实验板连接的按键带硬件消抖功能,见图 122,它利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。

图 121 按键抖动说明图

图 122 按键原理图

从按键的原理图可知,这些按键在没有被按下的时候,GPIO引脚的输入状态为低电平(按键所在的电路不通,引脚接地),当按键按下时,GPIO引脚的输入状态为高电平(按键所在的电路导通,引脚接到电源)。只要我们检测引脚的输入电平,即可判断按键是否被按下。

若您使用的实验板按键的连接方式或引脚不一样,只需根据我们的工程修改引脚即可,程序的控制原理相同。

12.2 软件设计

同LED的工程,为了使工程更加有条理,我们把按键相关的代码独立分开存储,方便以后移植。在"工程模板"之上新建"bsp_key.c"及"bsp_key.h"文件,这些文件也可根据您的喜好命名,这些文件不属于STM32标准库的内容,是由我们自己根据应用需要编写的。

12.2.1 编程要点

1.    使能GPIO端口时钟;

2.    初始化GPIO目标引脚为输入模式(引脚默认电平受按键电路影响,浮空/上拉/下拉均没有区别);

3.    编写简单测试程序,检测按键的状态,实现按键控制LED灯。

12.2.2 代码分析

1.    按键引脚宏定义

同样,在编写按键驱动时,也要考虑更改硬件环境的情况。我们把按键检测引脚相关的宏定义到"bsp_key.h"文件中,见代码清单 111。

代码清单 121 按键检测引脚相关的宏

1 //引脚定义

2 /*******************************************************/

3 #define KEY1_PIN GPIO_Pin_0

4 #define KEY1_GPIO_PORT GPIOA

5 #define KEY1_GPIO_CLK RCC_AHB1Periph_GPIOA

6

7 #define KEY2_PIN GPIO_Pin_13

8 #define KEY2_GPIO_PORT GPIOC

9 #define KEY2_GPIO_CLK RCC_AHB1Periph_GPIOC

10 /*******************************************************/

以上代码根据按键的硬件连接,把检测按键输入的GPIO端口、GPIO引脚号以及GPIO端口时钟封装起来了。

2.    按键 GPIO初始化函数

利用上面的宏,编写按键的初始化函数,见代码清单 122。

代码清单 122 按键GPIO初始化函数

1 /**

2 * @brief 配置按键用到的I/O口

3 * @param 无

4 * @retval 无

5 */

6 void Key_GPIO_Config(void)

7 {

8 GPIO_InitTypeDef GPIO_InitStructure;

9

10 /*开启按键GPIO口的时钟*/

11 RCC_AHB1PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);

12

13 /*选择按键的引脚*/

14 GPIO_InitStructure.GPIO_Pin = KEY1_PIN;

15

16 /*设置引脚为输入模式*/

17 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

18

19 /*设置引脚不上拉也不下拉*/

20 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

21

22 /*使用上面的结构体初始化按键*/

23 GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);

24

25 /*选择按键的引脚*/

26 GPIO_InitStructure.GPIO_Pin = KEY2_PIN;

27

28 /*使用上面的结构体初始化按键*/

29 GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);

30 }

同为GPIO的初始化函数,初始化的流程与"LED GPIO初始化函数"章节中的类似,主要区别是引脚的模式。函数执行流程如下:

(1)    使用GPIO_InitTypeDef定义GPIO初始化结构体变量,以便下面用于存储GPIO配置。

(2)    调用库函数RCC_AHB1PeriphClockCmd来使能按键的GPIO端口时钟,调用时我们使用"|"操作同时配置两个按键的时钟。

(3)    向GPIO初始化结构体赋值,把引脚初始化成浮空输入模式,其中的GPIO_Pin使用宏"KEYx_PIN"来赋值,使函数的实现方便移植。由于引脚的默认电平受按键电路影响,所以设置成"浮空/上拉/下拉"模式均没有区别。

(4)    使用以上初始化结构体的配置,调用GPIO_Init函数向寄存器写入参数,完成GPIO的初始化,这里的GPIO端口使用"KEYx_GPIO_PORT"宏来赋值,也是为了程序移植方便。

(5)    使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它按键检测时使用的GPIO引脚。

3.    检测按键的状态

初始化按键后,就可以通过检测对应引脚的电平来判断按键状态了,见代码清单 123。

代码清单 123 检测按键的状态

1 /** 按键按下标置宏

2 * 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0

3 * 若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可

4 */

5 #define KEY_ON 1

6 #define KEY_OFF 0

7

8 /**

9 * @brief 检测是否有按键按下

10 * @param GPIOx:具体的端口, x可以是(A...K)

11 * @param GPIO_PIN:具体的端口位,可以是GPIO_PIN_x(x可以是0...15)

12 * @retval 按键的状态

13 * @arg KEY_ON:按键按下

14 * @arg KEY_OFF:按键没按下

15 */

16 uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)

17 {

18 /*检测是否有按键按下 */

19 if (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON ) {

20 /*等待按键释放 */

21 while (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);

22 return KEY_ON;

23 } else

24 return KEY_OFF;

25 }

在这里我们定义了一个Key_Scan函数用于扫描按键状态。GPIO引脚的输入电平可通过读取IDR寄存器对应的数据位来感知,而STM32标准库提供了库函数GPIO_ReadInputDataBit来获取位状态,该函数输入GPIO端口及引脚号,函数返回该引脚的电平状态,高电平返回1,低电平返回0。Key_Scan函数中以GPIO_ReadInputDataBit的返回值与自定义的宏"KEY_ON"对比,若检测到按键按下,则使用while循环持续检测按键状态,直到按键释放,按键释放后Key_Scan函数返回一个"KEY_ON"值;若没有检测到按键按下,则函数直接返回"KEY_OFF"。若按键的硬件没有做消抖处理,需要在这个Key_Scan函数中做软件滤波,防止波纹抖动引起误触发。

4.    主函数

接下来我们使用主函数编写按键检测流程,见代码清单 124。

代码清单 124 按键检测主函数

1 /**

2 * @brief 主函数

3 * @param 无

4 * @retval 无

5 */

6 int main(void)

7 {

8 /* LED 端口初始化 */

9 LED_GPIO_Config();

10

11 /*初始化按键*/

12 Key_GPIO_Config();

13

14 /* 轮询按键状态,若按键按下则反转LED */

15 while (1) {

16 if ( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) {

17 /*LED1反转*/

18 LED1_TOGGLE;

19 }

20

21 if ( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON ) {

22 /*LED2反转*/

23 LED2_TOGGLE;

24 }

25 }

26 }

代码中初始化LED灯及按键后,在while函数里不断调用Key_Scan函数,并判断其返回值,若返回值表示按键按下,则反转LED灯的状态。

12.2.3 下载验证

把编译好的程序下载到开发板并复位,按下按键可以控制LED灯亮、灭状态。

12.3 每课一问

1.    工程中的Key_Scan函数使用while循环来阻塞检测,等待按键释放,若按键一直被按下,会导致CPU无法进行其它操作,降低效率。尝试修改按键检测的方式,避免阻塞等待。

第12章 GPIO输入-按键检测—零死角玩转STM32-F429系列的更多相关文章

  1. 第12章 GPIO输入—按键检测

    第12章     GPIO输入—按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

  2. 第33章 TIM—电容按键检测—零死角玩转STM32-F429系列

    第33章     TIM—电容按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  3. 第13章 GPIO输入—按键检测

    本章参考资料:<STM32F76xxx参考手册>.库帮助文档<STM32F779xx_User_Manual.chm>. 按键检测使用到GPIO外设的基本输入功能,本章中不再赘 ...

  4. 第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列

    第44章     MPU6050传感器—姿态检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  5. 第42章 电源管理—实现低功耗—零死角玩转STM32-F429系列

    第42章     电源管理—实现低功耗 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  6. GPIO 输入—按键检测

    这里要用到一定的模电知识.电容两端电压不能突变,电感两端电流不能突变.这里利用了电容的放电延时实现硬件消抖.按键按下会有抖动,波形有毛刺,使得高低电平显现不明显,而按键按下时,电容放电一下,马上又被充 ...

  7. GPIO输入—按键检测(开关控制小灯)

    本次的代码全是在上次代码之上添加的. 1.user下新建文件夹key,新建bsp_key.h bsp_key.c文件. 2.keil项目添加bsp_key.c,魔术棒C/C++中include pat ...

  8. 第39章 ETH—Lwip以太网通信—零死角玩转STM32-F429系列

    第39章     ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  9. 第29章 电容触摸屏—触摸画板—零死角玩转STM32-F429系列

    第29章     电容触摸屏—触摸画板 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

随机推荐

  1. drupal7 hook_validate

    原文:function hook_validate function hook_validate($node, $form, &$form_state) { if (isset($node-& ...

  2. 简易的canvas画板

    没事仿照windows画板工具用canvas实现了一个简易版的画板. html: <!doctype html> <html> <head> <meta ch ...

  3. javaSE——字节流

    IO流:InputStream/OutputStream 字节流:         文件输出流 :内存 ——>文件 文件输入流 :内存<——文件 应用             文件输入/出 ...

  4. EOS下控制台以及图形界面打印sql语句

    EOS下控制台以及图形界面打印sql语句 场景需求:在eos中打印sql语句,包括数据实体,查询实体和命名sql的sql语句. 所需资源: P6spy:负责拦截sql,并打印. Sqlprofiler ...

  5. Java实验案例(接口)

    实验任务 任务一:设计实现发声接口 任务二:动物乐园 实验内容 任务一:设计实现发声接口 任务目的: 理解并掌握如何定义接口 掌握接口的实现方式 任务描述: 设计和实现一个Soundable接口,该接 ...

  6. Android 仿美团网,探索使用ViewPager+GridView实现左右滑动查看更多分类的功能

    看下效果图,自己考虑下自己会如何实现,然后再继续看看作者的实现~ 不记得什么时候,我留意到到美团网首页有使用ViewPager+GridView实现左右滑动查看更多分类的一个功能,感觉它很有趣,于是想 ...

  7. ReactNative应用<DCL每日查看>开发总结

    App效果: 功能和交互简单描述: 针对微信使用用户每天的零碎时间来进行天气,新闻要点等查看,免去了打开其他App来查看; 针对每一天可以设置一项重要任务计划,可开启通知提醒,让每一天任务简化,免去太 ...

  8. 异度之刃 Xenoblade 后感

    WII版重置的N3DS劣化版异度之刃终于通关了.在出色的自制系统的快乐NTR的帮助下,充分体验到了神作的剧情史诗感. 关于游戏的玩法系统,从现在来看8年前的游戏,缺点显而易见,特别是跑地图这回事,地图 ...

  9. 数据契约(DataContract)里的DataMember特性

      数据契约(DataContract) 服务契约定义了远程访问对象和可供调用的方法,数据契约则是服务端和客户端之间要传送的自定义数据类型. 一旦声明一个类型为DataContract,那么该类型就可 ...

  10. 安卓 USB摄像头 开源库 UVCCamera 教程

    https://github.com/saki4510t/UVCCamera UVCCamera 听名字就知道使用UVC( USB VEDIO CLASS) 协议的通用类库.linux原生支持,基本支 ...