#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define CONFIG_LOG_MAXIMUM_LEVEL 5
#define LED_PIN GPIO_NUM_13 // LED接腳
#define BUTTON_PIN GPIO_NUM_35 // 按鍵的接腳
#define DEBOUNCE_TIME 30 // 彈跳延遲時間
static const char *TAG = "BUTTON_APP";
static QueueHandle_t btn_queue; // 宣告按鍵佇列的指標
static void led_task(void *pv) { // LED任務
bool led_state = false; // LED的初始狀態
int data;
while (1) {
if (xQueueReceive(btn_queue, &data, portMAX_DELAY)) { // 等待按鍵資料
led_state = !led_state; // 切換LED狀態
gpio_set_level(LED_PIN, led_state); // 設定LED狀態
ESP_LOGI(TAG, "LED:%s", led_state ? "開" : "關");
}
}
}
static void button_task(void *pv) { // 按鍵任務
int last = 1; // 上拉電阻的預設狀態為1
while (1) {
int curr = gpio_get_level(BUTTON_PIN); // 讀取按鍵狀態
// 若上次狀態為1,而且目前狀態為0。
if (last == 1 && curr == 0) {
// 延遲一下,消除彈跳。
vTaskDelay(pdMS_TO_TICKS(DEBOUNCE_TIME));
// 若還是按下狀態…
if (gpio_get_level(BUTTON_PIN) == 0) {
int val = 1; // 設定按鍵值
xQueueSend(btn_queue, &val, 0); // 立即送至佇列
// 等待按鍵放開(避免連續觸發)
while (gpio_get_level(BUTTON_PIN) == 0) {
vTaskDelay(pdMS_TO_TICKS(10));
}
}
}
last = curr;
vTaskDelay(pdMS_TO_TICKS(10)); // 讓出時間給CPU
}
}
void app_main(void){
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
btn_queue = xQueueCreate(1, sizeof(int)); // 建立佇列
gpio_config_t led_conf = { // 初始化LED GPIO
.pin_bit_mask = 1ULL << LED_PIN,
.mode = GPIO_MODE_OUTPUT, // 輸出模式
};
gpio_config(&led_conf);
gpio_config_t btn_conf = { // 初始化按鍵 GPIO
.pin_bit_mask = 1ULL << BUTTON_PIN,
.mode = GPIO_MODE_INPUT, // 輸入模式
.pull_up_en = GPIO_PULLUP_ENABLE, // 啟用內建上拉
.pull_down_en = GPIO_PULLDOWN_DISABLE, // 取消內建下拉
};
gpio_config(&btn_conf);
// 建立任務
xTaskCreate(button_task, "button_task", 2000, NULL, 5, NULL);
xTaskCreate(led_task, "led_task", 3000, NULL, 5, NULL);
}