GPIO输入——按键检测

描述

GPIO输入——按键检测

按键检测使用到GPIO外设的基本输入功能,本章中不再赘述GPIO外设的概念,如您忘记了可重新回到第八章节进行阅读。

12.1. 硬件设计

按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生 图12_1中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。

本实验用到的野火启明6M5开发板的按键带硬件消抖功能,它利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。

瑞萨设计的微处理器(MCU)拥有硬件数字滤波的功能用来实现去除按键带来的纹波影响, 不过前提是按键用在外部中断作为按键信号输入的情况下使用, 通过使用数字滤波的方式能够替代掉用电容式滤波的方法来消除纹波, 从而减少我们在硬件上的开发成本。

野火启明6M5开发板的按键电路图如 图12_2所示,图中RA6M5芯片的P004、P005引脚分别通过一个10KΩ的贴片电阻连接到电源的正极,所以按键在没有被按下的时候,GPIO引脚的输入状态为高电平状态, 分别又通过串联一个100Ω的贴片电阻和一个按键接地,所以按键在被按下的时候,GPIO引脚的输入状态为低电平状态。 只要我们检测引脚的输入电平,即可判断按键是否被按下。

开发板

开发板

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

12.2. 按键程序设计

使用瑞萨官方提供的FPS库进行编程,瑞萨官方提供的FPS库具有方便、快捷、简洁的特性。 在下面会教大家如何使用FPS库进行编程。

12.2.1. 新建工程

对于 e2 studio 开发环境:拷贝一份我们之前的 e2s 工程模板 “11_GPIO_LED” , 然后将工程文件夹重命名为 “12_Key” ,最后再将它导入到我们的 e2 studio 工作空间中。

对于 Keil 开发环境:拷贝一份我们之前的 Keil 工程模板 “11_GPIO_LED” , 然后将工程文件夹重命名为 “12_Key” ,并进入该文件夹里面双击 Keil 工程文件,打开该工程。

工程新建好之后,在工程根目录的 “src” 文件夹下面新建 “key” 文件夹, 再进入 “key” 文件夹里面新建 key 驱动的源文件和头文件:“bsp_key.c” 和 “bsp_key.h”。 工程文件结构如下。

文件结构

12_Key
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ key
   │  ├─ bsp_key.c
   │  └─ bsp_key.h
   └─ hal_entry.c

警告

注意:对于使用 Keil 开发环境的用户,将代码文件放到 “src” 文件夹下之后, Keil 软件并不会自动将它们加入到工程,这时候需要打开 RASC FSP 配置界面, 点击一次单击右上角的 “Generate Project Content” 按钮,从而 “src” 文件夹下的代码文件就会被自动加进工程中。 接着关闭 FSP 配置界面返回到 Keil,然后进行一次编译会弹出一个提示框提示工程结构发生了变化,点击确定即可。 对于使用 e2 studio 的用户则不需如此。

12.2.2. FSP配置

接下来我们要在fsp里配置芯片的引脚相关的属性。

在打开 “FSP” 配置界面后, 在 “FSP” 配置界面里面点开 “Pins” -> “Ports” -> “P0” -> “P004” , 然后将连接到按键的IO引脚的 “Mode” 属性配置为 “Input Mode” ,其他的属性默认即可,LED引脚的配置同上节一样配置。

开发板Pin Configuration 页面的 IOPORT 属性介绍:

IOPORT 属性介绍

IOPORT 属性 描述
----------------------------------------------------
模式 IO引脚的工作模式,包括输入模式和输出模式。
IO引脚是否上拉。
驱动器容量 IO引脚的驱动能力设置。
输出类型 IO引脚的输出类型。 可以选 CMOS 推挽输出或开漏输出。

配置完成之后的配置界面如图所示。

开发板配置完成之后按下快捷键“Ctrl + S”保存,最后点右上角的 “Generate Project Content” 图标, 让软件根据我们的设置自动生成配置代码即可。

对于 Keil 这边 RASC 的 FSP 配置也是一样的,需要先通过 RASC 软件打开 Keil 工程相关的 FSP 配置界面。 具体的方法在前面的章节已经详述过了,这里不再重复说明。

12.3. 按键程序思路

使用瑞萨的FSP对软件设计的思路非常地简单:首先通过R_IOPORT_Open函数初始化配置 LED 引脚,之后使用R_IOPORT_PinRead 函数来获取当前引脚的电平的状态。

12.3.1. R_IOPORT_PinRead 函数

通过 R_IOPORT_Open 函数初始化相应的引脚之后,我们使用R_IOPORT_PinRead函数来获取引脚的电平的状态。 我们通过分析R_IOPORT_PinRead函数,最主要的是通过p_pin_value这个枚举类型来获取IO的状态。

fsp_err_t R_IOPORT_PinRead (ioport_ctrl_t * const p_ctrl, bsp_io_port_pin_t pin, bsp_io_level_t * p_pin_value)

注解

bsp_io_port_pin_t枚举来决定需要获取的引脚,通过bsp_io_level_t来获取当前GPIO的状态。

e_bsp_io_level枚举

/* IOPORT 实例控制块 */
 typedef enum e_bsp_io_level
 {
     BSP_IO_LEVEL_LOW = 0,              ///< Low
     BSP_IO_LEVEL_HIGH                  ///< High
 } bsp_io_level_t;

12.3.2. 主函数

在while(1)里不断调用R_IOPORT_PinRead函数,并判断其返回值,若返回值表示按键按下,则LED灯的点亮,否则LED灯灭掉。

完整代码如下:

代码清单12_4

代码清单 12-4:主函数

void hal_entry(void)
 {
     fsp_err_t      err;                                                                 //
     err = R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg);                                //初始化引脚
     assert(FSP_SUCCESS == err);                                                         //判断是否初始化成功


     bsp_io_level_t Pin_P004;                                                            //定义获取函数的结构体
     while(1)
     {
         R_IOPORT_PinRead(&g_ioport_ctrl,BSP_IO_PORT_00_PIN_04, &Pin_P004);              //运行函数并把获取的数据赋值结构体
         if(Pin_P004 == BSP_IO_LEVEL_LOW){                                               //判断按键有没有按下
             R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);//点亮LED
         }else if(Pin_P004 == BSP_IO_LEVEL_HIGH){                                        //判断按键有没有松开
             R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW); //关闭LED
         }
     }

 #if BSP_TZ_SECURE_BUILD
     /* Enter non-secure code */
     R_BSP_NonSecureEnter();
 #endif
 }

注解

使用这种方式来获取IO口的状态相对会比较复杂,下面将介绍一种新的写法来简化这一个过程,可以使程序看起来更简单,让我们开发起来更加的顺畅。

12.4. 封装 Key 设备驱动程序

R_key_read函数

/*
 * 按键读取函数 输入引脚 返回当前引脚的状态
 * */
 uint32_t R_key_read(bsp_io_port_pin_t key)
 {
     bsp_io_level_t state;
     R_IOPORT_PinRead(&g_ioport_ctrl, key, &state);
     return state;
 }

我们这里对R_IOPORT_PinRead进行一次封装,为什么要加这一层封装呢,因为在对R_IOPORT_PinRead编程中多了一个指向型bsp_io_port_pin_t枚举类型数据, 每当程序中增加一个需要读取的IO口时我们就需要增加一个枚举类型数据,这样大大增加了我们程序的冗余程度。 我们封装的过程中通过输入当前的引脚,然后return返回当前的状态,这样简化了我们进行程序的编写。

Key_Scan函数

/*
 * 按键扫描函数判断你的手是否松开
 */
 uint32_t Key_Scan(bsp_io_port_pin_t key)
 {
     if(R_key_read(key) == BSP_IO_LEVEL_HIGH)
     {
         return KEY_OFF;
     }
     else
     {
         do  //等待按键释放
         {
             R_key_read(key);
         } while (BSP_IO_LEVEL_LOW == R_key_read(key));
     }
     return KEY_ON;
 }

这是一个对R_IOPORT_PinRead函数的使用案例,当按下按键的时候单片机会检测手是否松开当手离开的时候返回KEY_ON数值,当按键没有被按下的时候Key_Scan函数则返回KEY_OFF的数值, 下面是一个Key_Scan函数的实践案列。

主函数hal_entry()

void hal_entry(void)
 {
     while(1)
     {
         if( Key_Scan(KEY_SW2_PIN) == KEY_ON )   //扫描判断按键
         {
             LED1_ON;    //宏定义LED开
             LED2_ON;
             LED3_ON;
         }
         if( Key_Scan(KEY_SW3_PIN) == KEY_ON )
         {
             LED1_OFF;   //宏定义LED关
             LED2_OFF;
             LED3_OFF;
         }
     }

 #if BSP_TZ_SECURE_BUILD
     /* Enter non-secure code */
     R_BSP_NonSecureEnter();
 #endif
 }

在 “hal_entry.c” 文件中添加对头文件 “bsp_key.h” 的包含, 然后将 hal_entry 入口函数的内容改为如上所示。

12.5. 下载验证

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

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分