1)步骤
-
使能按键对应 IO 口的时钟(所有操作的第一步)
-
初始化 IO 模式
-
扫描 IO 口电平
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 的分支