外观
七、按键检测实验
独立按键基础知识
独立按键结构组成
独立按键实际上是一个非自锁的轻触开关,有左右四个触点,当按下时左右四个触点闭合,当松开时左右四个触点断开,12触点与34触点在内部是连接在一起的。
![]() | ![]() |
---|
独立按键原理
单片机通过检测按键按下前后的高低电平变化,来判断按键是否按下。通过程序的控制,就可以实现不同的功能与设置。机械式按键在按下或者释放时,由于机械弹性作用的影响,通常伴随有一定时间的触点机械抖动,然后其触点才稳定下来。抖动时间长短与开关的机械特性有关,一般为5-10ms。在触点抖动期间检测按键的按下与否,可能会导致判断错误,为了克服机械抖动所产生的影响,必须采取消抖措施,可分为硬件消抖和软件消抖。
硬件消抖
硬件消抖一般会在按键检测引脚处加入电容与电阻,通过RC延迟电路将按键按下时的高频振荡吸收滤除掉。
软件消抖
软件消抖一般是通过延时。当检测到按键按下时,不会立即去检测电平,而是经过短暂的延时之后,再去检测当前引脚的电平,这样就可以去掉抖动过程中的干扰,一般抖动时间在10ms以内。
按键一侧接电源,GPIO需要设置为下拉,也就是默认为低电平,通过判断对应GPIO引脚为高电平,从而判断按键是否按下。
按键一侧接GND,GPIO需要设置为上拉,也就是默认为高电平,通过判断对应GPIO引脚为低电平,从而判断按键是否按下。
板载按键原理图
按键检测配置
项目分析
本次项目完成KEY1点亮两个LED灯,KEY2熄灭两个LED灯,KEY3留给大家自行发挥;
通过前面的知识,我们已经知道了按键检测的原理与按键连接的引脚;
- KEY1--->PB13
- KEY2--->PB14
- KEY3--->PB15
从原理图中可看出,按键一侧接GND,所以需要判断GPIO引脚为低电平,从而判断按键是否按下。
配置流程
一般我们使用GPIO的端口,都需要有以下几个步骤;
- 开启GPIO的端口时钟;
- 配置GPIO的模式;
- 配置GPIO的输出;
开启GPIO端口时钟
GD32的所有外设资源时钟默认都是关闭的,在配置外设之前需要先开启对应的时钟。
时钟库函数在gd32e23x_rcu.h头文件中,也可通过附件资料中的《GD32固件库使用指南》查看该函数的详细说明。
C
//使能时钟
rcu_periph_clock_enable(RCU_GPIOB);
1
2
2
配置GPIO模式
在配置模式前,首先需要了解GPIO的模式,GD32E230GPIO模式有以下几种:
- GPIO_MODE_INPUT-------输入模式
- GPIO_MODE_OUTPUT-----输出模式
- GPIO_MODE_AF-----------复用模式(引脚复用功能时使用)
- GPIO_MODE_ANALOG----模拟模式(ADC读取模拟量时使用,可以读取细微变化的值)
当GPIO用作输入时,还会有以下几种情况可以设置:
- GPIO_PUPD_NONE--------引脚浮空
- GPIO_PUPD_PULLUP------引脚上拉
- GPIO_PUPD_PULLDOWN-引脚下拉
相关GPIO操作库函数在gd32e23x_gpio.h中,也可通过附件资料中的《GD32固件库使用指南》查看该函数的详细说明。
此函数有四个参数:
第一个参数是引脚端口,第二参数设置引脚模式;
第三个参数是设置上下拉情况,第四个参数是具体端口引脚号;
此处我们使用引脚的输入功能,按照原理说明,设置为引脚上拉;可通过“|”语法一次配置多个引脚
C
//设置输出模式,上拉
gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
1
2
2
配置GPIO的输出
这里使用的是GPIO的输入功能,输出配置不会生效,可直接选择不进行配置。自此,GPIO引脚配置完成。
检测输入电平
引脚配置完成后,现在可通过检测GPIO是否为低电平来判断按键是否按下。
相关GPIO操作库函数在gd32e23x_gpio.h中,也可通过附件资料中的《GD32固件库使用指南》查看该函数的详细说明。
C
//高电平返回SET,低电平返回RESET
gpio_input_bit_get(GPIOB,GPIO_PIN_13)
1
2
2
项目完整源码
下载成功后即可看到,按下KEY1,板载LED灯点亮,按下KEY2,板载LED灯熄灭。 此处项目源码中,有一个小细节,当我们检测按键是低电平时,开始延迟10ms进行消抖,随后再次判断,如果还是低电平,那就确定是按键按下,但还会有另外一个问题出现,如果我们一直按着按键,那就会一直是低电平,就会造成反复判断。 所以,加入一个死循环,如果按键一直按下,就一直循环,当按下松手的时候,才算一次完整的按键按下。
C
#include "gd32e23x.h"
#include "systick.h"
#include <stdio.h>
#include "led.h"
#include "main.h"
int main(void)
{
//初始化滴答定时器
systick_config();
//使能时钟
rcu_periph_clock_enable(RCU_GPIOC);
//使能时钟
rcu_periph_clock_enable(RCU_GPIOB);
//设置输出模式,不上下拉
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_14);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
//设置输出模式,上拉
gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
//设置输出类型,推挽输出,50Mhz
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
//没有按键按下时引脚输出为高电平,不点亮
gpio_bit_set(GPIOC,GPIO_PIN_14);
gpio_bit_set(GPIOC,GPIO_PIN_15);
while(1)
{
//KEY1按下
if(gpio_input_bit_get(GPIOB,GPIO_PIN_13)==RESET)
{
//消抖
delay_1ms(10);
//判断是否是真的按下
if(gpio_input_bit_get(GPIOB,GPIO_PIN_13)==RESET)
{
//等待按键松手
while(gpio_input_bit_get(GPIOB,GPIO_PIN_13)==RESET);
//点亮LED
gpio_bit_reset(GPIOC,GPIO_PIN_14);
gpio_bit_reset(GPIOC,GPIO_PIN_15);
}
}
if(gpio_input_bit_get(GPIOB,GPIO_PIN_14)==RESET)
{
delay_1ms(10);
if(gpio_input_bit_get(GPIOB,GPIO_PIN_14)==RESET)
{
while(gpio_input_bit_get(GPIOB,GPIO_PIN_14)==RESET);
gpio_bit_set(GPIOC,GPIO_PIN_14);
gpio_bit_set(GPIOC,GPIO_PIN_15);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
资料下载
工程代码可前往gitee下载资料包,简易数字示波器资料包
注意事项
消抖时间判断
软件消抖延迟时间为经验值,可根据实际情况增大或减少。
按键不灵敏
此时我们按键扫描是在while(1)中,无间断的扫描,如果此时在循环中加入延迟函数,那么延迟函数在延时时也是死循环,意味着延时时间内你按键按下是没有任何判断的,所以不建议在循环中加入大延迟函数或做大延迟操作。