GPIO应用二——按键实验
1.按键硬件设计
KEY_UP 按键一端是连接 VCC_3V3 的,另外一端是连接到 IO 口的,KEY_UP 按键是高电平有效。
KEY0~KEY2 的按键一端都是接到 GND,这三个按键是低电平有效。
2.按键的软件设计
这里还是先介绍一下按键检测的基本原理,硬件上使用的按键是机械按键,按键按下和抬起都会产生电平抖动,抖动过程时间在 5ms~10ms 左右。
有了抖动就得消抖,否则检测的按键就不会准确,去抖动的方式有两种:硬件防抖和软件防抖。
硬件防抖需要借助外接电容和电阻,通过电容充放电来约束电平不能跳变达到去抖动的效果
软件防抖,用延时的方式错过这个抖动的时间再检测。
2.1简单按键实验
接下来先介绍一个简单简单按键实验,作为 GPIO 输入功能的入门。
先介绍一下思路:
-
使能按键引脚的时钟
-
初始化按键配置,使用 GPIO 的输入模式(注意,硬件连接上并没有外部上拉或者下拉电阻,因此需要根据连接方式使能芯片内部的上拉或者下拉电阻)
-
在函数中使用引脚输入电平检测,从而判断按键是否被按下
-
当读取到按键按下电平(有效电平)后,进行软件消抖,再次进行输入电平检测,最终确定按键状态
-
判断到按键被按下后,进行应用处理
接下来我们一步一步来实现这些功能,先介绍一下使用的 bsp_key.h 文件:
/*
*********************************************************************************************************
*
* 模块名称 : 按键模块
* 文件名称 : bsp_key.h
* 版 本 : V1.0
* 说 明 :
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 xxxx-xx-xx xxxxx 首发
*********************************************************************************************************
*/
#ifndef _BSP_KEY_H
#define _BSP_KEY_H
#include "sys.h"
///
#define RCC_ALL_KEY (WKUP_GPIO_CLK|KEY0_GPIO_CLK|KEY1_GPIO_CLK|KEY2_GPIO_CLK)
//key_up
#define WKUP_GPIO_PIN GPIO_Pin_0
#define WKUP_PIN_ID 0 //key_up引脚序号
#define WKUP_GPIO_PORT GPIOA //key_up端口号
#define WKUP_GPIO_CLK RCC_APB2Periph_GPIOA //key_up时钟
//#define WKUP_FUN_OUT PGout
#define WKUP_FUN_IN PAin //key_up输入端口配置函数
#define WKUP_GPIO_MODE GPIO_Mode_IPD //key_up下拉输入
#define WKUP_ACTIVE_LEVEL 1 //高电平有效
//key_0
#define KEY0_GPIO_PIN GPIO_Pin_4
#define KEY0_PIN_ID 4 //key_0引脚序号
#define KEY0_GPIO_PORT GPIOE //key_0端口号
#define KEY0_GPIO_CLK RCC_APB2Periph_GPIOE //key_0时钟
//#define WKUP_FUN_OUT PGout
#define KEY0_FUN_IN PEin //key_0输入端口配置函数
#define KEY0_GPIO_MODE GPIO_Mode_IPU //key_0上拉输入
#define KEY0_ACTIVE_LEVEL 0 //低电平有效
//key_1
#define KEY1_GPIO_PIN GPIO_Pin_3
#define KEY1_PIN_ID 3 //key_1引脚序号
#define KEY1_GPIO_PORT GPIOE //key_1端口号
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOE //key_1时钟
//#define WKUP_FUN_OUT PGout
#define KEY1_FUN_IN PEin //key_1输入端口配置函数
#define KEY1_GPIO_MODE GPIO_Mode_IPU //key_1上拉输入
#define KEY1_ACTIVE_LEVEL 0 //低电平有效
//key_2
#define KEY2_GPIO_PIN GPIO_Pin_2
#define KEY2_PIN_ID 2 //key_2引脚序号
#define KEY2_GPIO_PORT GPIOE //key_2端口号
#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOE //key_2时钟
//#define WKUP_FUN_OUT PGout
#define KEY2_FUN_IN PEin //key_2输入端口配置函数
#define KEY2_GPIO_MODE GPIO_Mode_IPU //key_2上拉输入
#define KEY2_ACTIVE_LEVEL 0 //低电平有效
/
//IO操作函数
#define WKUP WKUP_FUN_IN (WKUP_PIN_ID)
#define KEY0 KEY0_FUN_IN (KEY0_PIN_ID)
#define KEY1 KEY1_FUN_IN (KEY1_PIN_ID)
#define KEY2 KEY2_FUN_IN (KEY2_PIN_ID)
//返回值
#define NOKEY_NUM 0
#define WKUP_NUM 1
#define KEY0_NUM 2
#define KEY1_NUM 3
#define KEY2_NUM 4
//*外部函数调用*//
void bsp_InitKey(void);
uint8_t bsp_KeyScan(void);
#endif
/***************************** (END OF FILE) *********************************/
这个头文件主要定义了引脚,先说明一下按键端口的相关宏定义,这个和我们前面介绍GPIO 输出的功能有一点区别
注意一下使用 XXX_FUN_IN,并且输入模式有所差异,这里选择 IPD 或者 IPU 是与硬件连接一一对应的。IPU 为上拉输入,IPD 为下拉输入
注意一下ACTIVE_LEVEL 是设置有效电平的,有效电平在按键硬件连接部分已经介绍了。
特别注意软件设计和硬件设计是相关的,一定是一一对应的。最后为每一个按键按下,以及无键按下各规定了一个唯一的返回值。
接下来是关键的按键扫描函数,我们看看 bsp_key.c 里是怎么描述的
/*
*********************************************************************************************************
*
* 模块名称 : 按键模块
* 文件名称 : bsp_key.c
* 版 本 : V1.0
* 说 明 :
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 xxxx-xx-xx xxxxx 首发
*********************************************************************************************************
*/
#include "bsp.h"
/*******************************************************************************
* 函数名 :bsp_InitKey()
* 函数功能 :按键初始化函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void bsp_InitKey(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*打开GPIO时钟*/
RCC_APB2PeriphClockCmd( RCC_ALL_KEY , ENABLE );
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
/*配置所有按键GPIO*/
GPIO_InitStructure.GPIO_Pin=WKUP_GPIO_PIN; /*WKUP端口*/
GPIO_InitStructure.GPIO_Mode=WKUP_GPIO_MODE; /*WKUP模式*/
GPIO_Init(WKUP_GPIO_PORT,&GPIO_InitStructure); /*初始化WKUP*/
GPIO_InitStructure.GPIO_Pin=KEY0_GPIO_PIN; /*KEY0端口*/
GPIO_InitStructure.GPIO_Mode=KEY0_GPIO_MODE; /*KEY0模式*/
GPIO_Init(KEY0_GPIO_PORT,&GPIO_InitStructure); /*初始化KEY0*/
GPIO_InitStructure.GPIO_Pin=KEY1_GPIO_PIN; /*KEY1端口*/
GPIO_InitStructure.GPIO_Mode=KEY1_GPIO_MODE; /*KEY1模式*/
GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStructure); /*初始化KEY1*/
GPIO_InitStructure.GPIO_Pin=KEY2_GPIO_PIN; /*KEY2端口*/
GPIO_InitStructure.GPIO_Mode=KEY2_GPIO_MODE; /*KEY2模式*/
GPIO_Init(KEY2_GPIO_PORT,&GPIO_InitStructure); /*初始化KEY2*/
}
/*******************************************************************************
* 函数名 :bsp_KeyScan()
* 函数功能 :键扫函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
uint8_t bsp_KeyScan(void)
{
///WKUP
if(WKUP==WKUP_ACTIVE_LEVEL) //判断按键是否按下
{
/*延时消抖*/
delay_ms(10);
if