stm32f103——按键检测(轮询方式)

我们下面来讲一讲,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; } } }

这里提出一个问题:

请问红框部分可以写成1==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灯不会关闭。

经验分享 程序员 微信小程序 职场和发展