按键输入——GPIO做输入

1)步骤

  1. 使能按键对应 IO 口的时钟(所有操作的第一步)

  2. 初始化 IO 模式

  3. 扫描 IO 口电平

2)按键扫描思路(两种)

  1. 支持连续按
    芯片一定时间扫描一次,按住按键不放,则会被认为多次按下,触发多次效果
  2. 不支持连续按
    按下一次再松开被视为一次, 按住不松开不会连续触发效果

补充
C语言的关键字 “static
static 申明的局部变量储存在静态储存区
他在函数结束调用之后不会被释放,其值会一直保留下来
即 static 定义的变量具有记忆功能

1

int a()
{
	static int a=0;
	b++;
	return b;
}

2

int a()
{
	int b=0;
	b++;
	return b;
}

多次调用函数 a 当为情况 2 时:每次都会返回 a=1
每次函数a调用b的值会被重新赋值 0 进行a++运算,返回b=1
情况 1 时:则会返回 1.2.3.4.5…
经过 static 修饰后b不会被重新初始化,从而实现累积的效果

3)建立文件

建立文件夹 + 建立key.c key.h两个文件 + 文件引入group

4)输入代码

在 key.h 中输入

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

#define KEY0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//读取按键 0
#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//读取按键 1
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键 2 

#define KEY0_PRES 1 //KEY0 
#define KEY1_PRES 2 //KEY1 
#define WKUP_PRES 3 //WK_UP 

void KEY_Init(void);//IO 初始化
u8 KEY_Scan(u8 mode); //按键扫描函数

3个宏定义

#define KEY0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//读取按键 0
#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//读取按键 1
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键 2 

使用库函数 GPIO_ReadInputDataBit 读取某个IO口的值
或者使用位带操作更加简洁

#define KEY0 PCin(5) 
#define KEY1 PAin(15)
#define WK_UP PAin(0)

但库函数在各个STM32芯片上的移植性更好,不需要修改任何代码

还定义了 KEY0_PRES / KEY1_PRES / KEYUP_PRES 等 3 个宏定义
对应开发板的 KEY0、KEY1 和 WK_UP 按键按下时 KEY_Scan 的返回值

在key.c中输入

#include "key.h"
#include "delay.h"
//按键初始化函数
//PA15 和 PC5 设置成输入
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;									RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,
	ENABLE);//使能 PORTA,PORTC 时钟
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	//关闭 jtag,使能 SWD,可以用 SWD 模式调试
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA15
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PC5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
	GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化 GPIOC5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 设置成输入,默认下拉 
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA.0
}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY0_PRES,KEY0 按下
//KEY1_PRES,KEY1 按下
//WKUP_PRES,WK_UP 按下
//注意此函数有响应优先级,KEY0>KEY1>WK_UP!

u8 KEY_Scan(u8 mode)
{
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1; //支持连按 
	if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
	delay_ms(10);//去抖动
	key_up=0;
	if(KEY0==0)return KEY0_PRES;
	else if(KEY1==0)return KEY1_PRES;
	else if(WK_UP==1)return WKUP_PRES; 
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; 
return 0;// 无按键按下
}

两个函数
void KEY_Init(void) 和 u8 KEY_Scan(u8 mode)

1)void KEY_Init(void) 用来初始化按键输入的 IO 口 ,实现PA0,PA15,PC5 的输入设置

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
这个函数,用于禁止 JTAG,开启 SWD,因为 PA15 占用了 JTAG 的一个 IO,所以要禁止 JTAG,从而让 PA15 用作普通 IO输入。

2)KEY_Scan用来扫描这三个 IO 口是否有按键被按下

参数 U8 ——unsigned char——无符号char类型字符

该函数整合了两种扫描思路,通过参数,mode来设置

static u8 key_up=1;//按键按松开标志
if(mode)key_up=1;//支持连按

当 mode =1 , if 语句启用,会为 key_up 重新赋值为 1,去除了 static 的累积效果
达到了按着按键不动,连续多次触发的效果

当 mode=0,调用检测后为 key_up 赋值为 0,标记这这次按键已经按下,在下一次循环时

if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
	delay_ms(10);//去抖动
	key_up=0;
	if(KEY0==0)return KEY0_PRES;
	else if(KEY1==0)return KEY1_PRES;
	else if(WK_UP==1)return WKUP_PRES; 
}

因为 key_up =0,所以该循环不执行
后一句 else if 语句

else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; 

其按键的值与上一句 if 语句中的值相反,表示松开的情况
当送开按键时,为 key_up 赋值 1 表示松开,从而进行下一次的 if 语句
如果一直按着不松开,按键的值也一直不变,该语句也一直不执行
从而达到了按着不动,只执行一次的效果

在 led.c 中输入

#include "led.h"
//初始化 PA8 和 PD2 为输出口.并使能这两个口的时钟
//LED IO 初始化
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
	RCC_APB2Periph_GPIOD, ENABLE); //使能 PA,PD 端口时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED0-->PA.8 端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度为 50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.8
	GPIO_SetBits(GPIOA,GPIO_Pin_8); //PA.8 输出高
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED1-->PD.2 端口配置, 推挽输出
	GPIO_Init(GPIOD, &GPIO_InitStructure); //推挽输出 ,IO 口速度为 50MHz
	GPIO_SetBits(GPIOD,GPIO_Pin_2); //PD.2 输出高
}

初始化 LED 灯,配置一系列参数

在 led.h 中输入

#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED 端口定义
#define LED0 PAout(8) // PA8
#define LED1 PDout(2) // PD2
void LED_Init(void);//初始化 
#endif

宏定义两个IO口

#在 main.c 中输入

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "key.h"
//ALIENTEK Mini STM32 开发板范例代码 2
//按键输入实验 
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司
int main(void)
{
	u8 t; 
	delay_init(); //延时函数初始化 
	LED_Init(); //初始化与 LED 连接的硬件接口
	KEY_Init(); //初始化与按键连接的硬件接口
	LED0=0; //点亮 LED
	while(1)
	{
		t=KEY_Scan(0); //得到键值
		switch(t)
		{
			case KEY0_PRES:
			LED0=!LED0;
			break;
			case KEY1_PRES:
			LED1=!LED1;
			break;
			case WKUP_PRES:
			LED0=!LED0;
			LED1=!LED1;
			break;
			default:
			delay_ms(10);
		} 
	}
}

定义 t 来得到按键值,用于 switch 的分支

5)编译

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值