一、前言
在Lora例程中,为我们提供了三个按键标志位,我们不需要手动再次初始化按键,即可完成按键的读取。
二、代码实现
首先,我们一起来阅读hal_key.c中的代码:
/* Includes ------------------------------------------------------------------*/
#include "stm32l1xx_hal.h"
#include "hal_key.h"char light_status = GPIO_PIN_RESET;
char fan_status = GPIO_PIN_RESET;void light_ctl_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = LIGHT_CTL_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(LIGHT_CTL_GPIO, &GPIO_InitStruct);HAL_GPIO_WritePin(LIGHT_CTL_GPIO, LIGHT_CTL_GPIO_PIN, (GPIO_PinState)light_status);
}void light_ctl(char is_light_on)
{light_status = is_light_on;HAL_GPIO_WritePin(LIGHT_CTL_GPIO, LIGHT_CTL_GPIO_PIN, (GPIO_PinState)light_status);
}void fan_ctl_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = FAN_CTL_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(FAN_CTL_GPIO, &GPIO_InitStruct);HAL_GPIO_WritePin(FAN_CTL_GPIO, FAN_CTL_GPIO_PIN, (GPIO_PinState)fan_status);
}void fan_ctl(char is_fan_on)
{fan_status = is_fan_on;HAL_GPIO_WritePin(FAN_CTL_GPIO, FAN_CTL_GPIO_PIN, (GPIO_PinState)fan_status);
}void keys_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = KEY2_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(KEY2_GPIO, &GPIO_InitStruct);GPIO_InitStruct.Pin = KEY3_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(KEY3_GPIO, &GPIO_InitStruct);GPIO_InitStruct.Pin = KEY4_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(KEY4_GPIO, &GPIO_InitStruct);
}volatile char is_key2_down = 0;
volatile char is_key3_down = 0;
volatile char is_key4_down = 0;char isKey2Pressed(void){return is_key2_down;
}char isKey3Pressed(void){return is_key3_down;
}char isKey4Pressed(void){return is_key4_down;
}void resetKey2(void){is_key2_down = 0;
}void resetKey3(void){is_key3_down = 0;
}void resetKey4(void){is_key4_down = 0;
}#define DEBOUNCE_CNT 2
void scan_keys(void)
{static char key2_status = KEY_UP, key2_down_cnt = 0, key2_up_cnt = 0;static char key3_status = KEY_UP, key3_down_cnt = 0, key3_up_cnt = 0;static char key4_status = KEY_UP, key4_down_cnt = 0, key4_up_cnt = 0;char new_status;//KEY2new_status = HAL_GPIO_ReadPin(KEY2_GPIO, KEY2_GPIO_PIN);if((key2_status == KEY_UP) && (new_status == KEY_DOWN)) {key2_down_cnt++;if(key2_down_cnt >= DEBOUNCE_CNT) {is_key2_down = 1;key2_status = KEY_DOWN;}} else {key2_down_cnt = 0;}if((key2_status == KEY_DOWN) && (new_status == KEY_UP)) {key2_up_cnt++;if(key2_up_cnt >= DEBOUNCE_CNT) {is_key2_down = 0;key2_status = KEY_UP;;}} else {key2_up_cnt = 0;}//KEY3new_status = HAL_GPIO_ReadPin(KEY3_GPIO, KEY3_GPIO_PIN);if((key3_status == KEY_UP) && (new_status == KEY_DOWN)) {key3_down_cnt++;if(key3_down_cnt >= DEBOUNCE_CNT) {is_key3_down = 1;key3_status = KEY_DOWN;}} else {key3_down_cnt = 0;}if((key3_status == KEY_DOWN) && (new_status == KEY_UP)) {key3_up_cnt++;if(key3_up_cnt >= DEBOUNCE_CNT) {is_key3_down = 0;key3_status = KEY_UP;;}} else {key3_up_cnt = 0;}//KEY4new_status = HAL_GPIO_ReadPin(KEY4_GPIO, KEY4_GPIO_PIN);if((key4_status == KEY_UP) && (new_status == KEY_DOWN)) {key4_down_cnt++;if(key4_down_cnt >= DEBOUNCE_CNT) {is_key4_down = 1;key4_status = KEY_DOWN;}} else {key4_down_cnt = 0;}if((key4_status == KEY_DOWN) && (new_status == KEY_UP)) {key4_up_cnt++;if(key4_up_cnt >= DEBOUNCE_CNT) {is_key4_down = 0;key4_status = KEY_UP;;}} else {key4_up_cnt = 0;}
}
上述.c文件中,已经为我们初始化了相关引脚,并完成了配置工作。我们使用这个库主要是使用在库中的isKey_Pressed()和resetKey_()函数。
isKey_Pressed()是在按键被按下后,对应的is_key_down标志位的值发生改变,因此我们读取该标志位的值即可。
resetKey_()是将其对应的标志位的值重置,这常用在我们已经做完按键的反馈的事件之后进行,以便接受下一次的按键事件。因此,如果我们长时间没有处理按键的事件,标志位反应的仅仅是按过,而并非按下多少次。
具体使用:
以上的含义是读取KEY2是否被按下,如果被按下则LED1亮。如果KEY3被按下,则LED1灭。
int main( void )
{Init();while( 1 ){if(isKey2Pressed()){GpioWrite(&Led1,0);resetKey2();}if(isKey3Pressed()){GpioWrite(&Led1,1);resetKey3();}}
}
按键进阶:
双击:
双击的原理,即在短时间内完成两次点击,即可完成双击操作。因此,代码的核心将放在对本次按下与上一次松开之间的时间的判断。
长按:
长按同时也是我们程序开发中,十分重要的一环,通常分为两个部分:按下时与松开后。长按与单击的区别就是按下时间的不同,因此我们需要将代码的核心放到按下的计时上。
关于单击、双击和长按,推荐大家可以借鉴我的这一篇文章,里边有更详细的表达:
Zigbee单片机开发板-实现单击、双击、长按的识别反馈-超简单方法-新大陆物联网-物联网竞赛-Zigbee&STM32开发板
这种关于单击、双击与长按的思想不局限与任何芯片,在所有系统中通用。