我们下面来讲一讲,GPIO在输入模式下检测按键是否被按下:
首先我们来看看按键按下时,K1处电压的变化情况是什么:
我们看到,按键按下时,K1处的电压并不是立马就下降为0v,因为按键有机械的弹性形变,导致按键被按下时,会发生抖动。我们用GPIO来读取K1处的电压是否为0,如果为低电平,则表示按键被按下。被按下后,如果为高电平,则表示按键被抬起来了。
但是,在这个按键抖动的过程中,电平有上升沿也有下降沿,电压有高电平也有低电平。所以,在这一段抖动的部分的时间段内,如果我们用GPIO去判断,由于电平忽高忽低,我们的程序就会识别出来,按键在被按下后马上就抬起来了。但是,实际上并不是这样。所以,我们需要跳过按键被按下时的前50ms,在K1处电压稳定时,再来对K1处电压进行判断。这个过程我们称为按键"消抖"。
读取PA0的按键值,编程步骤:
1,打开时钟----GPIOA
2,初始化GPIOA
---GPIO_Pin_0
---上拉输入
3,判断PA0是否为低电平
4,如果为低电平,延时50ms,消除抖动
5,再次判断PA0是否为低电平---结合第3步,判断是否为按键按下过程
6,如果是为低电平,等待按键抬起----耗尽按键按下的时间
7,确认按键按下,执行按键按下相应的操作
编程:
//按键按下后,LED灯的状态反转
void KEY_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 1,打开时钟----GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 2,初始化GPIOA
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_0; //注意:在输入模式下,不用设置I/O口的速度
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IPU; //按键检测时,选择上拉输入模式
GPIO_Init( GPIOA,&GPIO_InitStruct);
}uint8_t KEY_isPress(void)
{
uint8_t ret=0;
// 3,判断PA0是否为低电平
if(0==GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){
// 4,如果为低电平,延时50ms,消除抖动
Systick_NmsDelay(50);
// 5,再次判断PA0是否为低电平---结合第3步,判断是否为按键按下过程
if(0==GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){
// 6,如果是为低电平,等待按键抬起----耗尽按键按下的时间
while(0==GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))
;
// 7,确认按键按下,执行按键按下相应的操作
ret=1;
}
}
return ret;
}uint8_t ledflag=0;
int main(void)
{
LED_Config();
RCC_ConfigTo72M();//将系统时钟配置成72MHZ
Systick_Config(72);
KEY_Config(); while(1){
if(0==ledflag){
LED_CTRL(LEDR,LED_CLOSE);
}else{
LED_CTRL(LEDR,LED_OPEN);
}
if( 1==KEY_isPress() ){
ledflag=~ledflag;
}
}
}
这里提出一个问题:
ledflag=~ledflag,ledflag一开始为0,"~"(反)一下不就是1了吗?1的时候LED灯关闭。
不行,因为ledflag虽然一开始是0,但是uint8_t 类型,uint8_t类型的0实际上是0000 0000(即0x00),所以~(0000 0000) = 1111 1111 (即:0xff)其不等于1,所以,此时LED灯不会关闭。