这一节我们来学习使用按键操作。包括带消抖和不带消抖。
由于之前已经学习过FreeRtos使用任务的方式,所以不再过多赘述、
如果你对使用任务存有疑惑,你可以跳转到文章末尾学习第三节
开发环境:ESP-IDF 4.3
操作系统:Windows10 专业版
开发板:自制的ESP32-WROOM-32E
查看原理图,发现GPIO引脚是连接在GPIO0引脚,也就是我们的 boot 按键上
先把前期要准备的工作先准备好,如下:
#include
#include
#include
#include "esp_log.h"
#define BUTTON_PIN GPIO_NUM_0
static const char *TAG = "Key_Input";
不带消抖的按键触发很简单:在一个死循环中,只要连接在 IO0 上的按键按下(IO0 接收到低电平),那么就视为触发了按键,演示代码如下:
#include
#include
#include
#include "esp_log.h"
#define BUTTON_PIN GPIO_NUM_0
static const char *TAG = "Key_Input";
void button_task(void *arg)
{
gpio_pad_select_gpio(BUTTON_PIN);
gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
while (1) {
if (gpio_get_level(BUTTON_PIN) == 0) {
ESP_LOGI(TAG,"Button Pressed!\n");
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void app_main()
{
xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
}
上面的示例你可以看到每隔10ms就触发了一次函数,这样的高频操作甚至让我触发了堆栈空间溢出导致重启,所以我们使用按键还是需要使用消抖的,代码如下:
#include
#include
#include
#include "esp_log.h"
#define BUTTON_PIN GPIO_NUM_0
static const char *TAG = "Key_Input";
void button_task(void *arg)
{
int button_state = 0;
int button_debounce = 0;
int button_pressed = 0;
while (1) {
button_state = gpio_get_level(BUTTON_PIN);
if (button_state == 0) {
button_debounce++;
if (button_debounce >= 10) {
if (!button_pressed) {
ESP_LOGI(TAG,"Button Pressed!\n");
button_pressed = 1;
}
}
} else {
button_debounce = 0;
button_pressed = 0;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void app_main()
{
gpio_pad_select_gpio(BUTTON_PIN);
gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
}
演示效果如下,我连续按动,触发的间隔变短,也没有出现持续触发的情况,所以我们的按键消抖代码就写好了
长按和短按的识别就是根据低电平的持续时间来判断是低电平还是高电平:
#include
#include
#include
#include "esp_log.h"
#define BUTTON_PIN GPIO_NUM_0
static const char *TAG = "Key_Input";
#define LONG_PRESS_TIME_MS 1000
static void button_task(void *arg)
{
gpio_pad_select_gpio(BUTTON_PIN);
gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
TickType_t press_start_time = 0;
bool is_button_pressed = false;
while (1) {
bool button_state = gpio_get_level(BUTTON_PIN);
if (button_state && !is_button_pressed) {
// Button is pressed
is_button_pressed = true;
press_start_time = xTaskGetTickCount();
} else if (!button_state && is_button_pressed) {
// Button is released
is_button_pressed = false;
TickType_t press_duration = xTaskGetTickCount() - press_start_time;
if (press_duration >= pdMS_TO_TICKS(LONG_PRESS_TIME_MS)) {
// 长按
ESP_LOGI(TAG,"长按");
} else {
// 短按
ESP_LOGI(TAG,"短按");
}
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void app_main()
{
xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
}
经过测试发现如果按键比较小不太好按的话,会容易出现抖动导致识别错误:
还有以上文章值得你一览
基于Freertos的ESP-IDF开发——0.Windows下espidf的环境搭建
基于Freertos的ESP-IDF开发——1.HelloWorld
基于Freertos的ESP-IDF开发——2.点亮一颗LED
基于Freertos的ESP-IDF开发——3.使用任务(上)
基于Freertos的ESP-IDF开发——3.使用任务(中)
基于Freertos的ESP-IDF开发——3.使用任务(下)
基于Freertos的ESP-IDF开发——4.使用任务的方式来点亮LED灯