要求
使用點觸開關翻轉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