ESP32 ESP-IDF 點亮LED

要求

使用點觸開關翻轉LED燈的點亮和熄滅。

分析

選用LED的GPIO端口時要注意不能選用34到39管腳,因爲它們僅輸入管腳。點觸開關需要監聽中斷然後來翻轉LED的控制管腳,所有的管腳都可以添加到中斷服務程序中。如果LED顯示翻轉不是很順暢可以添加函數去抖。

接線圖

代碼分析

設置GPIO

將這GPIO設置成全局變量,後期可以根據需求修改GPIO端口。

gpio_num_t gpio_led_num = GPIO_NUM_32;            // 連接LED的GPIO
gpio_num_t gpio_contact_switch_num = GPIO_NUM_33; // 連接觸點開關GPIO

設置控制燈的GPIO

將控制燈的GPIO設置爲輸出模式。

// 設置控制LED的GPIO爲輸出模式
gpio_set_direction(gpio_led_num, GPIO_MODE_OUTPUT);

設置控制開關的GPIO

開關GPIO設置爲輸入模式,中斷模式爲上升沿觸發。

// 設置作爲中斷的GPIO pin爲輸出模式
gpio_set_direction(gpio_contact_switch_num, GPIO_MODE_INPUT);
// 設置作爲中斷模式爲沿上升沿觸發
gpio_set_intr_type(gpio_contact_switch_num, GPIO_INTR_POSEDGE);

註冊中斷

當開關GPIO中斷產生時需要設置回調函數使用LED進行翻轉,每點擊一次cnt加1,然後對cnt對2取模就會產生週期的0、1、0、1、0…。
回調函數要放在app_main()之上。

static void IRAM_ATTR gpio_isr_handler(void *arg)
{
    cnt++;
    // 反轉gpio的電平,讓LED燈出現顯示的反轉
    gpio_set_level(gpio_led_num, cnt % 2);
    uint32_t gpio_num = (uint32_t)arg;
    // 向gpio事件處理的隊列中添加一條消息
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

中斷服務程序啓動,然後給指定的GPIO設置回調

// 初始化全局GPIO的中斷服務程序,並設置中斷的電平等級
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
// 將指定的GPIO掛載到中斷服務上,並設定中斷觸發的回調函數和傳入參數
gpio_isr_handler_add(gpio_contact_switch_num, gpio_isr_handler, (void *)gpio_contact_switch_num);

整體代碼

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"

#define ESP_INTR_FLAG_DEFAULT 0

gpio_num_t gpio_led_num = GPIO_NUM_32;            // 連接LED的GPIO
gpio_num_t gpio_contact_switch_num = GPIO_NUM_33; // 連接觸點開關GPIO

static xQueueHandle gpio_evt_queue = NULL; // 事務隊列

int cnt = 0; // 計數,反轉LED
/**
 * 中斷處理
 */
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
    cnt++;
    // 反轉gpio的電平,讓LED燈出現顯示的反轉
    gpio_set_level(gpio_led_num, cnt % 2);
    uint32_t gpio_num = (uint32_t)arg;
    // 向gpio事件處理的隊列中添加一條消息
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

static void gpio_task_led(void *arg)
{
    uint32_t io_num;
    for (;;)
    {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
        {
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

void app_main(void)
{
    // 設置控制LED的GPIO爲輸出模式
    gpio_set_direction(gpio_led_num, GPIO_MODE_OUTPUT);

    // 設置作爲中斷的GPIO pin爲輸出模式
    gpio_set_direction(gpio_contact_switch_num, GPIO_MODE_INPUT);
    // 設置作爲中斷模式爲沿上升沿觸發
    gpio_set_intr_type(gpio_contact_switch_num, GPIO_INTR_POSEDGE);

    // 創建隊列處理來自isr的gpio事件
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    // 啓動gpio的任務
    xTaskCreate(gpio_task_led, "gpio_task_led", 2048, NULL, 10, NULL);

    // 初始化全局GPIO的中斷服務程序,並設置中斷的電平等級
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    // 將指定的GPIO掛載到中斷服務上,並設定中斷觸發的回調函數和傳入參數
    gpio_isr_handler_add(gpio_contact_switch_num, gpio_isr_handler, (void *)gpio_contact_switch_num);
}

源碼地址

https://github.com/knzjoint/esp32-project/tree/master/gpio

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章