一、按键介绍
按键就是一种电子开关使用时轻轻按开关按钮就可以使开关接通,当松开手的时候,开关断开。说白了按键就是用来实现一个电路的通路以及断开操作的开关。
如何接线
假设我们接的是1,3,此时电路一直是通路,当我们按下按键和不按下按键都是同一个结果,因为1,3相连引脚初始是导通的,那我们不能实现按键操作。所以我们应该接1,2引脚,同样的我们也可以接1,4引脚
按键抖动
- 通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号如图:
- 当按键按下立刻变为低电平,松开的时候立刻变为高电平,这是理想状态的波形。实际上,机械开关在安下或者松开的时候有一个抖动,等到一定时间后他就会稳定,抖动时间通常是10 ~ 20ms。
- 需要消除抖动的波形,抖动过程中产生低电平,会导致设备误操作,所以需要对进行按键滤波。
- 按键的滤波方法:
- 硬件消抖:通过RC的滤波电路,通过充放电,实现时间的滤除
- 软件消抖:使用延时
二、硬件设计
开发板上一共有4个按键:
- KEY_UP:PA0,按键按下检测到有效电平是3.3V,高电平有效
- KEY0:PE4,按键按下检测到低电平有效
- KEY1:PE3,按键按下检测到低电平有效
- KEY2:PE2,按键按下检测到低电平有效
三、软件设计
程序主要框架:
- 初始化按键使用的端口及时钟
- 按键检测处理
- 按键控制处理
创建文件
- 在APP文件夹下创建KEY文件夹,用来存放按键文件
- 在KEY文件夹下创建key.h和key.c文件
- 进行按键初始化时,和LED、蜂鸣器时类似的,但是需要用到GPIO的输入功能,当按键按下的时候,检测端口引脚是高电平还是低电平
key.c文件
#include "key.h"
#include "SysTick.h"
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使用或运算使能多个时钟
RCC_APB2PeriphClockCmd(KEY_UP_PORT_RCC | KEY_012_PORT_RCC, ENABLE);
// 配置成输入不需要设置速度
// KEY_UP高电平有效,先给引脚配置一个默认电平低电平,引脚默认输入低点平,当按键按下电路导通,输入就会变成高电平
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN;
GPIO_Init(KEY_UP_PORT, &GPIO_InitStructure);
// KEY_012低电平有效,先给引脚配置一个默认电平高电平,引脚默认输入高点平,当按键按下电路导通,输入就会变成低电平
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = KEY0_PIN | KEY1_PIN | KEY2_PIN;
GPIO_Init(KEY_012_PORT, &GPIO_InitStructure);
}
// 按键扫描,检测哪一个按键按下
// mode用于对按键进行单次检测或者连续检测
// mode = 0,单次检测按键,mode = 1,连续检测按键,类似于遥控器的音量调节,连续按+或-
u8 KEY_Scan(u8 mode)
{
static u8 key = 1; // key用来实现按键是否连续检测
if(mode == 1) key = 1;
if(key == 1 && (KEY_UP == 1 || KEY0 == 0 || KEY1 == 0 || KEY2 == 0)) // 说明按键按下,检测到了高电平
{
delay_ms(10); // 消抖
key = 0;
if(KEY_UP == 1) // 如果是高电平,代表按键确实是按下了
return KEY_UP_PRESS;
if(KEY0 == 0)
return KEY0_PRESS;
if(KEY1 == 0)
return KEY1_PRESS;
if(KEY2 == 0)
return KEY2_PRESS;
}
// 按键松开检测,按键松开时key == 0
else if(key == 0 && (KEY_UP == 0 && KEY0 == 1 && KEY1 == 1 && KEY2 == 1)) // 确保4个按键都是松开的,所以用&&
{
key = 1;
}
return 0; // 按键没有按下就返回0
}
key.h文件
#ifndef __KEY_H
#define __KEY_H
#include "system.h"
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#define KEY_UP_PORT_RCC RCC_APB2Periph_GPIOA
#define KEY_UP_PIN GPIO_Pin_0
#define KEY_UP_PORT GPIOA
#define KEY_012_PORT_RCC RCC_APB2Periph_GPIOE
#define KEY0_PIN GPIO_Pin_4
#define KEY1_PIN GPIO_Pin_3
#define KEY2_PIN GPIO_Pin_2
#define KEY_012_PORT GPIOE
#define KEY_UP PAin(0)
#define KEY0 PEin(4)
#define KEY1 PEin(3)
#define KEY2 PEin(2)
// 返回值,用来获取是哪一个按键按下
#define KEY_UP_PRESS 1
#define KEY0_PRESS 2
#define KEY1_PRESS 3
#define KEY2_PRESS 4
#endif
main.c文件
#include "LED.h" // 包含 LED 模块的头文件
#include "system.h"
#include "SysTick.h"
#include "beep.h"
#include "key.h"
// 主函数
int main()
{
u8 key = 0; // 判断哪个按键按下
u8 i = 0; //让LED1指示灯闪烁,确保程序在执行
SysTick_Init(72);
LED_Init(); // 初始化 LED1 和 LED2
BEEP_Init();
KEY_Init();
// 主循环
while(1)
{
key = KEY_Scan(0);
switch(key)
{
case KEY_UP_PRESS: LED2 = 0; break;
case KEY0_PRESS: BEEP = 1; break;
case KEY1_PRESS: LED2 = 1; break;
case KEY2_PRESS: BEEP = 0; break;
}
i ++;
if(i % 20 == 0) // 每经过200ms,让LED1翻转一次
LED1 = !LED1;
delay_ms(10);
}
}