一 引言
在我们的日常生活中,使用按键控制电器开关的情况还是非常多的,比如说按键控制LED灯的亮灭,按键控制继电器的吸合,按键控制电机的正反转等操作。同样按键在嵌入式开发也非常的重要,比如说按下KEY1,使LED1点亮,再按下KEY1,LED1熄灭。按键的种类有很多,然而今天我们要研究的是贴片按键的使用,我们今天的实例为:通过KEY1的状态来控制LED的点亮与熄灭。
二 按键原理
大多数的按键都是这两种连接方式,首先看IO口的默认状态,这两张原理图都是默认IO状态为高电平1,按下时按键与GND短接,所以其为低电平0状态,那么我们就可以通过读取按键的IO电平状态来判断按键是否按下了。
三 硬件平台与IO口详情
我们使用的是洋桃1号核心板来跑这次的例程,其芯片型号为STM32F103C8T6,我们来一起看看它的原理图
LED1连接的IO口为PB0 LED2连接的IO口为PB1
KEY1的IO口为PA0
四 代码实现
初始化LED灯
首先我们在led.h中对LED初始定义
在#define LEDPORT GPIOB //IO组
#define LED1 GPIO_Pin_0 //定义LED1
#define LED2 GPIO_Pin_1 //定义LED2
接下来对LED做初始化函数说明
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//构造结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能其所在时钟
GPIO_InitStructure.GPIO_Pin = LED1 | LED2;//定义IO端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//定义IO端口输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//定义IO端口输出速度
GPIO_Init(LEDPORT, &GPIO_InitStructure);//写入其中
}`
按键宏定义
#define KEYPORT GPIOA
#define KEY1 GPIO_Pin_0
初始化按键
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //构造结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能其所在时钟
GPIO_InitStructure.GPIO_Pin = KEY1;//定义IO端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//定义IO端口模式为上啦输入
GPIO_Init(KEYPORT,&GPIO_InitStructure);
}
我们把按键操作分为两个不同的版本:一个为有锁存,另外一个为无锁存。接下来我们来分别解释一下什么是有锁存,什么是无锁存。
比如我们按下按键以后,LED常亮,但是我们想要再次关闭LED灯,那么就再次按一下按键,我们按下第一次按键以后,无论等待多长时间,直到再次按下按键以后才能关闭LED,这种情况我们称为是有锁存,另外一种情况就是无锁存,那么什么是无锁存呢?我们按下按键,LED点亮,松开按键,LED熄灭,这种情况就叫无锁存。
锁存有还是没有并没有孰是孰非,在不同的场合使用不同的程序才是最机智的选择
接下来我们就分别来讨论两种情况都是如何实现的。
无锁存:按下按键,LED点亮,松开按键,LED熄灭。
我们刚才说我们要通过读取IIO端口的电平来判断按键是否按下,那么我们就要调用GPIO库函数,我们来看看库函数使用手册。
while(1)
{
if(!GPIO_ReadInputDataBit(KEYPORT,KEY1))
{
GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1));
}
else
{
GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0));
}
}
通过原理图可知,按键按下的时候MCU读取到的应该是低电平,那么在前面加一个取反的符号,于是按下的时候读取到的电平为0,取反以后得到的为1,于是if条件成立。
那么接着就会执行函数括号里面的内容,GPIO置位函数就会将其位设为1,于是LED接收到高电平,LED被点亮。
如果函数条件不成立,那么就不会执行函数里面的内容。这种代码就是无锁存的情况。
接下来我们再来看看有锁存的情况。
if(!GPIO_ReadInputDataBit(KEYPORT,KEY1))
{
delay_ms(20);
if(!GPIO_ReadInputDataBit(KEYPORT,KEY1))
{
GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1-GPIO_ReadOutputDataBit(LEDPORT,LED1)));
while(!GPIO_ReadInputDataBit(KEYPORT,KEY1));
}
}
我们引入了延时消抖的思想,因为按键是机械开关,所以在按下的时候会产生电平的抖动,这在51单片机中经常使用。我个人认为延时消抖应该是一种思想。
第一步先检查按键是否按下,如果按下了,那么就延时20毫秒,再次判断按键是否按下,确保其不是因为机械抖动造成的误判断。两次判断以后,其结果基本确定,如果按键按下了,就点亮LED灯,然后再加入一个死循环,等待按键被松开。就是通过一个等待按键松开的函数来跳出循环,达到按键锁存的目的。