按键输入-GPIO输入

时间:2022-07-21 16:15:05

关于GPIO的输出功能之前我们已经有了一定的了解
这次通过按键输入对GPIO输入功能做实际应用

主要内容:
按键输入的硬件连接
读取IO输入的相关函数
捕捉按键状态的步骤
按键扫描实现思路
按键扫描程序代码

一,硬件连接

  按键输入-GPIO输入
  
如图,有4个按键,分两组

 第一组:WK_UP连接VCC
 第二组:KEY0,KEY1,KEY2连接GND

确定IO口工作模式:

 当IO口按下时我们需要捕捉到IO口的电平变化
 所以WK_UP按下后为高地平,需设置按下前为低电平,应设置为下拉输入
 同理KEY0,KEY1,KEY2按下后为低电平,应设置为上拉输入

二,读取IO输入的相关函数:

1,库函数
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

2,寄存器
GPIO端口输入寄存器:GPIOx_IDR

3,位操作
PEin(n) 读取GPIOE.n的输入电平

三,步骤:

 1,使能相应的GPIO时钟
RCC_APB2PeriphColckCmd();

2,初始化IO口工作模式
GPIO_Init();
参考GPIO初始化

3,扫描IO口电平

四,按键扫描思路:

 1,读取按键对应IO口的输入电平
2,比较输入电平确定按键是否被按下
注意:按键被按下和抬起的一瞬间会有按键抖动需延时一段时间避免判断错误

按键输入-GPIO输入


五,按键扫描代码:

HARDWARE/KEY/新建key.h头文件,定义函数和变量

#ifndef __KEY_H
#define __KEY_H
#include "sys.h"

//位操作读取IO输入电平
//#define KEY0 PEin(4) // KEY0-PE4
//#define KEY1 PEin(3)   // KEY1-PE3
//#define KEY2 PEin(2)   // KEY2-PE2
//#define WK_UP PAin(0)  // WK_UP-PA0

//库函数读取IO输入电平
#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) // 读取按键0-PE4
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3 // 读取按键0-PE3
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) // 读取按键0-PE2
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) // 读取按键0-PA0

#define KEY0_PRES 1 // KEY0按下
#define KEY1_PRES 2 // KEY1按下
#define KEY2_PRES 3 // KEY2按下
#define WKUP_PRES 4 // KEY_UP按下

void KEY_Init(void); // Key初始化函数
u8 KEY_Scan(u8); // 按键扫描函数
#endif

HARDWARE/KEY/新建key.c实现函数

#include "stm32f10x.h"
#include "key.h"
#include "sys.h"
#include "delay.h"

//按键初始化函数
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

//使能GPIOA,GPIOE时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);

//初始化KEY0-KEY2-->GPIOE.2-GPIOE.4 上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOE, &GPIO_InitStructure);

//初始化WK_UP-->GPIOA.0 下拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // PA0设置为输入 默认下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);     // 初始化GPIOA.0

}

//按键扫描函数,返回扫描值
//mode=0不支持连续按,1支持连按
//0,没有按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY2按下
//4,WK_UP按下
//优先级 KEY0 > KEY1 > KEY2 > WK_UP
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//是否抬起状态
if(mode)key_up=1; //支持连续

if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))//有按键按下
{
delay_ms(10);  // 去抖动
key_up=0;    // 设置按下

if(KEY0==0)return KEY0_PRES; // KEY0按下
else if(KEY1==0)return KEY1_PRES; // KEY1按下
else if(KEY2==0)return KEY2_PRES; // KEY2按下
else if(WK_UP==1)return WKUP_PRES; // WK_UP按下
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0){ //没有按键按下
key_up=1;
}

return 0;
}

USER文件夹下新建main.c主函数并编写代码:

#include "led.h"          // LED
#include "delay.h"  // 延时函数
#include "key.h" // 按键初
#include "sys.h" // 位操作
#include "beep.h"  // 蜂鸣器

int main(void)
{
vu8 key=0;
delay_init(); // 初始化延时函数
LED_Init(); // LED端口初始化
KEY_Init(); // 初始化按键连接的硬件接口
BEEP_Init(); // 初始化蜂鸣器端口
LED0=0; // 使能LED0

while(1)
{
key=KEY_Scan(0); // 不支持连续按 得到Key值,返回哪个按键被按下了

if(key) // 如果有被按下的按键
{
switch(key) // 判断是哪个按键被按下做相应的动作
{
case WKUP_PRES: // WK_UP按键控制蜂鸣器开关
BEEP=!BEEP;
break;
case KEY2_PRES: // Key2控制LED0
LED0=!LED0;
break;
case KEY1_PRES: // Key1控制LED0
LED1=!LED1;
break;
case KEY0_PRES: // Key0控制LED0,LED1
LED0=!LED0;
LED1=!LED1;
break;
}
}else { // 如果本次没有检测到按键被按下,延迟10ms
delay_ms(10);
}
}
}

以上代码实现不同按键控制不同硬件功能

WK_UP 控制 蜂鸣器
KEY2 控制 LED0
KEY1 控制 LED1
KEY0 控制 LEDE0+LED1

按键扫描间隔10ms