基于Freertos的ESP-IDF开发——5.使用按键[不带消抖、带消抖、长按短按识别]
- 0. 前言
- 1. 确定GPIO引脚
- 2. 触发函数(不带消抖)
- 3. 触发函数(带消抖)
- 4. 长按和短按识别
- 5.其他FreeRtos文章
0. 前言
这一节我们来学习使用按键操作。包括带消抖和不带消抖。
由于之前已经学习过FreeRtos使用任务的方式,所以不再过多赘述、
如果你对使用任务存有疑惑,你可以跳转到文章末尾学习第三节
开发环境:ESP-IDF 4.3
操作系统:Windows10 专业版
开发板:自制的ESP32-WROOM-32E
1. 确定GPIO引脚
查看原理图,发现GPIO引脚是连接在GPIO0引脚,也就是我们的 boot 按键上
先把前期要准备的工作先准备好,如下:
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#include "esp_log.h"
#define BUTTON_PIN GPIO_NUM_0
static const char *TAG = "Key_Input";
2. 触发函数(不带消抖)
不带消抖的按键触发很简单:在一个死循环中,只要连接在 IO0 上的按键按下(IO0 接收到低电平),那么就视为触发了按键,演示代码如下:
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#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);
}
效果如下,只要按下去了就会检测到很多次触发:
3. 触发函数(带消抖)
上面的示例你可以看到每隔10ms就触发了一次函数,这样的高频操作甚至让我触发了堆栈空间溢出导致重启,所以我们使用按键还是需要使用消抖的,代码如下:
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#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);
}
演示效果如下,我连续按动,触发的间隔变短,也没有出现持续触发的情况,所以我们的按键消抖代码就写好了
4. 长按和短按识别
长按和短按的识别就是根据低电平的持续时间来判断是低电平还是高电平:
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#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);
}
经过测试发现如果按键比较小不太好按的话,会容易出现抖动导致识别错误:
5.其他FreeRtos文章
还有以上文章值得你一览
基于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灯