【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

FBshark發表於2024-07-02

簡單不看版——esp-idf元件管理步驟

  1. ESP-IDF 元件管理器網頁https://components.espressif.com/搜尋我們需要的元件,比如【button】,然後 點開相應的元件,比如 espressif/button 元件。
  2. 【關鍵步驟】複製相關元件介面上配置元件的命令 ,形如:idf.py add-dependency "espressif/button^3.2.0" ,並在 esp-idf 終端視窗中輸入。
  3. 生成 idf_component.yml 檔案後,使用命令 idf.py build 或者外掛上面的編譯按鈕對整個工程進行一次編譯,編譯完成後,元件就會出現在 managed_components 目錄下。
  4. managed_components 目錄下有元件檔案後,元件便新增成功了;接下來可以引用元件內的標頭檔案,在自己的.c檔案中編寫程式了。

ESP32使用iot-button元件實現按鍵檢測的功能

    • ESP-IDF 元件管理
    • iot-button 元件簡介
    • 測試button元件
    • 寫在最後

ESP-IDF 元件管理

IDF 元件管理器工具用於下載 ESP-IDF CMake 專案的依賴項,該下載在 CMake 執行期間自動完成(也就是說,不是事先下載好,而是準備編譯的時候下載的)。IDF 元件管理器可以從自動從元件登錄檔 或 Git 倉庫獲取元件,具體的使用和介紹,請檢視官方文件,需要注意的是 ESP-IDF 管理器是 IDF4.4 以後引入的特性,使用IDF框架時,建議儘量使用最新的 release 版本 IDF 構建自己的專案。

要獲取元件列表,請參閱 https://components.espressif.com/

iot-button 元件簡介

  1. 我們從 ESP-IDF 元件管理器網頁搜尋我們需要的元件【button】,然後 點開 espressif/button 元件

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

2. button 元件簡介

Button按鍵元件實現了 GPIO 和 ADC 兩種按鍵,並允許同時建立兩種不同的按鍵。下圖顯示了兩種按鍵的硬體設計:

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

圖 GPIO按鍵

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

圖 ADC按鍵

GPIO 按鍵優點有:每一個按鍵佔用獨立的 IO,之間互不影響,穩定性高;缺點有:按鍵數量多時佔用太多 IO 資源。

ADC 按鍵優點有:可多個按鍵共用一個 ADC 通道,佔用 IO 資源少;缺點有:不能同時按下多按鍵,當按鍵因氧化等因素導致閉合電阻增大時,容易誤觸,穩定性不高。

每個按鍵擁有下表的 8 個事件:

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

每個按鍵可以有 回撥 和 輪詢 兩種使用方式:

  • 回撥:一個按鍵的每個事件都可以為其註冊一個回撥函式,產生事件時回撥函式將會被呼叫。這種方式的效率和實時性高,不會丟失事件。
  • 輪詢:在程式中週期性呼叫 :ciot_button_get_event 查詢按鍵當前的事件。

這種方式使用簡單,適合任務簡單的場合,當然你也可以將以上兩種方式組合使用。

注意:回撥函式中不能有 TaskDelay 等阻塞的操作

具體功能和使用方法,請檢視官方文件

測試button元件

1. 使用 VSCODE 的 ESP-IDF 外掛建立一個 helloword 的工程

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

2. 【關鍵步驟】複製button元件介面上配置元件的命令 idf.py add-dependency "espressif/button^3.2.0" 在當前 helloworld 工程下增加 button元件

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

  

PS:遇到的一些問題及解決方法:

idf.py 的命令無法執行,提示 idf.py : 無法將 “idf.py ”項識別為 cmet、函式、指令碼檔案或可執行程式的名稱。請檢査名稱的拼寫,如果包括路徑,請確保路徑正確,然後再試一次。 或者只會開啟 idf.py 這個檔案而不執行這個檔案的內容.

解決方法:

指令只能在 ESP-IDF Terminal 中執行,不能在系統自帶的 powershell 等工具中執行

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

生成 idf_component.yml 檔案後,使用命令 idf.py build 或者外掛上面的編譯按鈕對整個工程先進行一次編譯,編譯完成後,元件就會出現在 managed_components 目錄下

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

4. 此處我們測試最簡單GPIO控制LED的功能;將\managed_components\espressif__button\examples\button_power_save\main\main.c 檔案裡面的內容全部複製到 hello_world_main.c 中

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

並對 hello_world_main.c 的內容進行稍微的修改,因為我們不測試低功耗的相關功能,故刪除低功耗測試的相關程式碼,並且修改 GPIO 及按鍵按下的有效電平;以下使用IO0作為按鍵輸入,且有效電平為低電平。

/*
 * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "iot_button.h"
#include "esp_sleep.h"
#include "esp_idf_version.h"

/* Most development boards have "boot" button attached to GPIO0.
 * You can also change this to another pin.
 */
//這裡設定你要初始化的按鍵的PIN號
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6
#define BOOT_BUTTON_NUM         9
#else
#define BOOT_BUTTON_NUM         0 
#endif

#define BUTTON_ACTIVE_LEVEL     0     //這裡設定按鍵按下之後的有效電平

static const char *TAG = "button_test";

const char *button_event_table[] = {
    "BUTTON_PRESS_DOWN",
    "BUTTON_PRESS_UP",
    "BUTTON_PRESS_REPEAT",
    "BUTTON_PRESS_REPEAT_DONE",
    "BUTTON_SINGLE_CLICK",
    "BUTTON_DOUBLE_CLICK",
    "BUTTON_MULTIPLE_CLICK",
    "BUTTON_LONG_PRESS_START",
    "BUTTON_LONG_PRESS_HOLD",
    "BUTTON_LONG_PRESS_UP",
};

static void button_event_cb(void *arg, void *data)
{
    ESP_LOGI(TAG, "Button event %s", button_event_table[(button_event_t)data]);
    #if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE
    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    if (cause != ESP_SLEEP_WAKEUP_UNDEFINED) {
        ESP_LOGI(TAG, "Wake up from light sleep, reason %d", cause);
    }
    #endif
}

void button_init(uint32_t button_num)
{
    button_config_t btn_cfg = {
        .type = BUTTON_TYPE_GPIO,
        .gpio_button_config = {
            .gpio_num = button_num,
            .active_level = BUTTON_ACTIVE_LEVEL,
#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE
            .enable_power_save = true,
#endif
        },
    };
    button_handle_t btn = iot_button_create(&btn_cfg);
    assert(btn);
    esp_err_t err = iot_button_register_cb(btn, BUTTON_PRESS_DOWN, button_event_cb, (void *)BUTTON_PRESS_DOWN);
    err |= iot_button_register_cb(btn, BUTTON_PRESS_UP, button_event_cb, (void *)BUTTON_PRESS_UP);
    err |= iot_button_register_cb(btn, BUTTON_PRESS_REPEAT, button_event_cb, (void *)BUTTON_PRESS_REPEAT);
    err |= iot_button_register_cb(btn, BUTTON_PRESS_REPEAT_DONE, button_event_cb, (void *)BUTTON_PRESS_REPEAT_DONE);
    err |= iot_button_register_cb(btn, BUTTON_SINGLE_CLICK, button_event_cb, (void *)BUTTON_SINGLE_CLICK);
    err |= iot_button_register_cb(btn, BUTTON_DOUBLE_CLICK, button_event_cb, (void *)BUTTON_DOUBLE_CLICK);
    err |= iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, button_event_cb, (void *)BUTTON_LONG_PRESS_START);
    err |= iot_button_register_cb(btn, BUTTON_LONG_PRESS_HOLD, button_event_cb, (void *)BUTTON_LONG_PRESS_HOLD);
    err |= iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, button_event_cb, (void *)BUTTON_LONG_PRESS_UP);
    ESP_ERROR_CHECK(err);
}
#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
void power_save_init(void)
{
    esp_pm_config_t pm_config = {
        .max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
        .min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
        .light_sleep_enable = true
#endif
    };
    ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
}
#else
void power_save_init(void)
{
#if CONFIG_IDF_TARGET_ESP32
    esp_pm_config_esp32_t pm_config = {
#elif CONFIG_IDF_TARGET_ESP32S2
    esp_pm_config_esp32s2_t pm_config = {
#elif CONFIG_IDF_TARGET_ESP32C3
    esp_pm_config_esp32c3_t pm_config = {
#elif CONFIG_IDF_TARGET_ESP32S3
    esp_pm_config_esp32s3_t pm_config = {
#elif CONFIG_IDF_TARGET_ESP32C2
    esp_pm_config_esp32c2_t pm_config = {
#endif
        .max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
        .min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
        .light_sleep_enable = true
#endif
    };
    ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
}
#endif
#endif

void app_main(void)
{
    
#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE
    power_save_init();
#endif
    button_init(BOOT_BUTTON_NUM);
}

對修改完成的功能進行編譯,並下載到測試的開發板上,按下接到 IO0 上的按鍵,就可以透過日誌參看按鍵的事件:

【esp32 學習筆記】esp-idf學會呼叫元件管理——以button

相關文章