文章目录
- 一、GPIO输入——按键输入检测
- 二、硬件设计
- 三、软件设计
- 下载验证
一、GPIO输入——按键输入检测
按键检测原理
按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生 下图中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。
本实验用到的野火启明6M5开发板的按键带硬件消抖功能, 它利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。
瑞萨设计的微处理器(MCU)拥有硬件数字滤波的功能用来实现去除按键带来的纹波影响, 不过前提是按键用在外部中断作为按键信号输入的情况下使用, 通过使用数字滤波的方式能够替代掉用电容式滤波的方法来消除纹波, 从而减少在硬件上的开发成本。
二、硬件设计
野火启明6M5开发板的按键电路图如下图所示, 图中RA6M5芯片的P004、P005引脚分别通过一个10KΩ的贴片电阻连接到电源的正极,所以按键在没有被按下的时候,GPIO引脚的输入状态为高电平状态, 分别又通过串联一个100Ω的贴片电阻和一个按键接地,所以按键在被按下的时候,GPIO引脚的输入状态为低电平状态。 只要我们检测引脚的输入电平,即可判断按键是否被按下。
三、软件设计
1. 新建工程
对于 Keil 开发环境:
拷贝一份我们之前的 Keil 工程 “11_GPIO_LED”, 然后将工程文件夹重命名为 “12_GPIO_Key”,并进入该文件夹里面双击 Keil 工程文件,打开该工程。
工程新建好之后,在工程根目录的 “src” 文件夹下面新建 “key” 文件夹, 再进入 “key” 文件夹里面新建 Key 驱动的源文件和头文件:“bsp_key.c” 和 “bsp_key.h”。 工程文件结构如下。
12_GPIO_Key
├─ ......
└─ src
├─ led
│ ├─ bsp_led.c
│ └─ bsp_led.h
├─ key
│ ├─ bsp_key.c
│ └─ bsp_key.h
└─ hal_entry.c
2. FSP配置
首先打开 “12_GPIO_Key” 项目的 FSP 配置界面,接下来我们要在这个界面里配置芯片的引脚。
在 FSP 配置界面里面点开 “Pins”-> “Ports”-> “P0”-> “P004”, 然后将连接到按键1的IO引脚的 “Mode” 属性配置为 “Input Mode”,其他的属性默认即可。 按键2的引脚 “P005” 也是按照这样进行配置。
配置完成之后的配置界面如下图所示。 “P004”和“P005”引脚的工作模式(Mode)都设置为输入模式,外部中断(IRQ)不启用。
配置完成之后按下快捷键“Ctrl + S”保存,最后点右上角的 “Generate Project Content” 图标, 让软件根据我们的设置自动生成配置代码即可。
对于 Keil 这边 RASC 的 FSP 配置也是一样的,需要先通过 RASC 软件打开 Keil 工程相关的 FSP 配置界面。
3. Key_Scan按键扫描函数
按键程序设计思路可以非常简单:想要知道某个按键是否被按下, 只需检测连接到改按键的IO引脚是高电平还是低电平,若是低电平,说明按键正处于被按下的状态。
通过使用 R_IOPORT_PinRead 函数,我们可以获取某个IO引脚的电平状态。 R_IOPORT_PinRead 函数原型如下:
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 枚举类型的变量 pin 传入要读取的 IO 引脚的端口号和引脚号;
-
通过 bsp_io_level_t 枚举类型的指针 p_pin_value 来获取该 IO 引脚的电平状态。
bsp_io_level_t 枚举类型的定义如下:
/* 可以为单个引脚设置电平和读取电平 */
typedef enum e_bsp_io_level
{
BSP_IO_LEVEL_LOW = 0, ///< Low
BSP_IO_LEVEL_HIGH ///< High
} bsp_io_level_t;
Key_Scan 按键扫描函数如下:
/* 定义宏 KEY_ON 表示按键按下
定义宏 KEY_OFF 表示按键没有按下
*/
#define KEY_ON 1
#define KEY_OFF 0
/* 按键扫描函数(阻塞式)
* key: KEY1_SW2_PIN 用户按键1(丝印SW2)的引脚
* KEY2_SW3_PIN 用户按键2(丝印SW3)的引脚
*/
uint32_t Key_Scan(bsp_io_port_pin_t key)
{
bsp_io_level_t state;
// 读取按键引脚电平
R_IOPORT_PinRead(&g_ioport_ctrl, key, &state);
if (BSP_IO_LEVEL_HIGH == state)
{
return KEY_OFF; //按键没有被按下
}
else
{
do //等待按键释放
{
R_IOPORT_PinRead(&g_ioport_ctrl, key, &state);
} while (BSP_IO_LEVEL_LOW == state);
}
return KEY_ON; //按键被按下了
}
这是一个简单的按键扫描函数,当调用该函数并且检测到按键被按下的时候,就会在 do-while 语句里重复检测按键是否被松开, 一直到当手松开按键的时候才能跳出循环,并返回 KEY_ON 数值表明按键被按下; 而当按键没有被按下的时候 Key_Scan 函数则返回 KEY_OFF 的数值。
值得注意的是,若程序在 do-while 循环里一直检测到手没有松开按键, 则程序会被一直阻塞在这里,因此这是一个阻塞式的扫描函数。
4. hal_entry入口函数
在 hal_entry 函数里,首先初始化了 LED 和按键, 接着进入了 while 主循环,在该循环下反复地调用 Key_Scan 函数对两个用户按键进行实时扫描。 若按键1按下,则翻转LED1的状态;若按键2按下,则翻转LED2的状态。
需要注意的是,KEY1_SW2_PIN 和 KEY2_SW3_PIN 宏定义了两个用户按键的引脚,不同的板子按键引脚是不一样的。
/* 启明6M5开发板,两个按键引脚定义 */
#define KEY1_SW2_PIN BSP_IO_PORT_00_PIN_04
#define KEY2_SW3_PIN BSP_IO_PORT_00_PIN_05
hal_entry 入口函数如下:
/* 用户头文件包含 */
#include "led/bsp_led.h"
#include "key/bsp_key.h"
void hal_entry(void)
{
/* TODO: add your own code here */
LED_Init(); // LED 初始化
Key_Init(); // 按键初始化
while(1)
{
if( Key_Scan(KEY1_SW2_PIN) == KEY_ON ) //扫描按键1
{
LED1_TOGGLE; //翻转LED1状态
}
if( Key_Scan(KEY2_SW3_PIN) == KEY_ON ) //扫描按键2
{
LED2_TOGGLE; //翻转LED2状态
}
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
下载验证
将程序编译并下载到开发板之后,按下复位按键来复位开发板。
然后按下用户按键1可以控制 LED1 灯的亮灭;按下用户按键2则可以控制 LED2 灯的亮灭。