#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define CONFIG_LOG_MAXIMUM_LEVEL 5
#define LED_PIN GPIO_NUM_13
#define BUTTON_PIN GPIO_NUM_35
#define DEBOUNCE_TIME 30 // 消除彈跳時間 (ms)
static const char *TAG = "SWITCH_LED";
// 全域變數標記:必須加上 volatile 關鍵字
// 告訴編譯器「這個變數隨時會被中斷改變,不要做暫存器優化快取」
static volatile bool g_button_pressed = false;
// 中斷處理函式:只負責修改全域變數標記
static void IRAM_ATTR isr_handler(void* arg) {
g_button_pressed = true; // 設置按鍵按下標記
}
void led_task(void* arg) {
bool led_state = false;
while (1) {
// 任務必須一直定期檢查全域變數(輪詢)
if (g_button_pressed) {
g_button_pressed = false; // 清除標記
vTaskDelay(pdMS_TO_TICKS(DEBOUNCE_TIME)); // 等待電位穩定
// 確認按鍵是否仍然處於按下狀態(低電位)
if (gpio_get_level(BUTTON_PIN) == 0) {
led_state = !led_state;
gpio_set_level(LED_PIN, led_state);
ESP_LOGI(TAG, "LED:%s", led_state ? "開" : "關");
}
}
// 強制延遲:避免 while(1) 迴圈把 CPU 效能吃滿 100%
// 這意味著即使按鍵按下,任務最多需要等待 10ms 才會反應
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void app_main(void) {
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
gpio_config_t led_conf = { // LED 接腳配置
.pin_bit_mask = (1ULL << LED_PIN),
.mode = GPIO_MODE_OUTPUT,
};
gpio_config(&led_conf);
gpio_config_t btn_conf = { // 按鍵接腳配置
.pin_bit_mask = (1ULL << BUTTON_PIN),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.intr_type = GPIO_INTR_NEGEDGE, // 下降邊緣觸發
};
gpio_config(&btn_conf);
// 安裝 GPIO 中斷服務
gpio_install_isr_service(0);
// 註冊中斷處理函式
gpio_isr_handler_add(BUTTON_PIN, isr_handler, NULL);
// 建立輪詢任務
xTaskCreate(led_task, "led_task", 3000, NULL, 10, NULL);
}Loading
esp32-s3-devkitc-1
esp32-s3-devkitc-1