ESP32開發之路(3)— 點亮第一個LED燈及按鍵輸入
本次開發是在Ubuntu下的,使用的模塊是GOOUUU-ESP32,使用VSCode編輯項目。基於工程:ESP32開發之路(2)— HelloWorld工程分析和優化
一、點亮第一個LED燈
複製hello_world文件並命名爲led_key,修改hello_world_main.c爲app_main.c;
然後將工作區保存在led_key文件夾下:
通過硬件原理圖查詢可得,LED連在GPIO2上;所以首先宏定義LED的引腳編號:
#define GPIO_LED_NUM 2
然後定義一個gpio配置結構體
/* 定義一個gpio配置結構體 */
gpio_config_t gpio_config_structure;
對該結構體進行初始化,配置並使能
/* 初始化gpio配置結構體*/
gpio_config_structure.pin_bit_mask = (1ULL << GPIO_LED_NUM);/* 選擇gpio2 */
gpio_config_structure.mode = GPIO_MODE_OUTPUT; /* 輸出模式 */
gpio_config_structure.pull_up_en = 0; /* 不上拉 */
gpio_config_structure.pull_down_en = 0; /* 不下拉 */
gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE; /* 禁止中斷 */
/* 根據設定參數初始化並使能 */
gpio_config(&gpio_config_structure);
然後將其設爲高電平,點亮該LED燈:
/* 輸出高電平,點亮LED*/
gpio_set_level(GPIO_LED_NUM, 1);
然後我們可以看到開發板上的藍色LED已經亮起來了:
二、LED閃爍
我們編寫一個while循環,讓LED一秒閃爍一次
while(1)
{
gpio_set_level(GPIO_LED_NUM, 0); /* 熄滅 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延時500ms*/
gpio_set_level(GPIO_LED_NUM, 1); /* 點亮 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延時500ms*/
}
燒錄,運行結果:
三、按鍵電平檢測
查看硬件原理圖,BOOT按鍵連在GPIO0上,並且已經上拉;所以首先宏定義BOOT按鍵的引腳編號
#define GPIO_KEY_NUM 0
然後對gpio配置結構體進行初始化,配置並使能
/* 初始化gpio配置結構體*/
gpio_config_structure.pin_bit_mask = (1ULL << GPIO_KEY_NUM);/* 選擇gpio0 */
gpio_config_structure.mode = GPIO_MODE_INPUT; /* 輸入模式 */
gpio_config_structure.pull_up_en = 0; /* 不上拉 */
gpio_config_structure.pull_down_en = 0; /* 不下拉 */
gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE; /* 禁止中斷 */
/* 根據設定參數初始化並使能 */
gpio_config(&gpio_config_structure);
然後我們1s查詢一次按鍵電平,並打印出來
while(1)
{
printf("Boot_key Level is : %d \n",gpio_get_level(GPIO_KEY_NUM)); /* 獲取BOOT按鍵電平並打印 */
vTaskDelay(1000 / portTICK_PERIOD_MS); /* 延時1000ms*/
}
運行結果,檢測成功
四、循環檢測按鍵是否按下
我們創建一個按鍵檢測任務檢測是否有按鍵按下,在主任務裏執行LED的閃爍
首先我們查看一下這個freeRTOS的優先級可選範圍,查詢得知configMAX_PRIORITIES=25
,所以任務優先級可選範圍爲0~24
,且數字越大,優先級越高!
/* 定義按鍵檢測任務的任務句柄*/
TaskHandle_t Key_Task_Handler;
/* 聲明按鍵檢測任務函數 */
void key_task(void *pvParameters);
然後在主任務裏創建按鍵檢測任務,
/* 創建按鍵檢測任務 */
xTaskCreatePinnedToCore((TaskFunction_t )key_task, /* 任務函數 */
(const char* )"key task", /* 任務名稱*/
(uint16_t )2048, /* 任務堆棧大小,單位爲字節*/
(void* )NULL, /* 傳遞給任務函數的參數*/
(UBaseType_t )20, /* 任務優先級,最高優先級爲24 */
(TaskHandle_t* )&Key_Task_Handler, /* 任務句柄*/
(const BaseType_t)tskNO_AFFINITY); /* 指定運行任務的CPU,使用這個宏表示不會固定到任何核上*/
然後我們實現按鍵檢測任務函數,注意,portTICK_PERIOD_MS
的值爲10,即RTOS的一個時間片爲10ms,則使用vTaskDelay()函數進行延時,不能小於10ms
/* 按鍵檢測任務函數 */
void key_task(void *pvParameters)
{
static int key_up = 1; /* 按鍵鬆開標誌 */
while (1)
{
/* 檢測按鍵是否按下 */
if (key_up && (gpio_get_level(GPIO_KEY_NUM) == 0) )
{
vTaskDelay(50 / portTICK_PERIOD_MS); /* 延時50ms消抖*/
key_up = 0;
if (gpio_get_level(GPIO_KEY_NUM) == 0)
{
/* 按鍵BOOT按下,按鍵按下處理*/
printf("BOOT Key pressed!\n");
}
}
else if(gpio_get_level(GPIO_KEY_NUM) == 1 )
{
key_up = 1; /* 按鍵已鬆開 */
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
燒錄後的實現效果如下,同時LED正常閃爍
五、補充
說一下任務創建函數,因爲我之前看的freeRTOS,任務創建函數是xTaskCreate,然後我特意找了一下idf裏的xTaskCreate函數,發現是調用了xTaskCreatePinnedToCore()函數,
所以以後創建任務在不需要指定哪個內核運行的時候,可以使用xTaskCreate()函數
/* 創建按鍵檢測任務 */
xTaskCreate((TaskFunction_t )key_task, /* 任務函數 */
(const char* )"key task", /* 任務名稱*/
(uint16_t )2048, /* 任務堆棧大小,單位爲字節*/
(void* )NULL, /* 傳遞給任務函數的參數*/
(UBaseType_t )20, /* 任務優先級,最高優先級爲24 */
(TaskHandle_t* )NULL); /* 任務句柄,在不需要使用任務句柄時,可以填入NULL*/
六、代碼
最後貼上整個app_main.c
的代碼
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "driver/gpio.h"
#define GPIO_LED_NUM 2
#define GPIO_KEY_NUM 0
/* 定義按鍵檢測任務的任務句柄*/
TaskHandle_t Key_Task_Handler;
/* 聲明按鍵檢測任務函數 */
void key_task(void *pvParameters);
void app_main(void)
{
/* 打印Hello world! */
printf("Hello world!\n");
/* 定義一個gpio配置結構體 */
gpio_config_t gpio_config_structure;
/* 初始化gpio配置結構體*/
gpio_config_structure.pin_bit_mask = (1ULL << GPIO_LED_NUM);/* 選擇gpio2 */
gpio_config_structure.mode = GPIO_MODE_OUTPUT; /* 輸出模式 */
gpio_config_structure.pull_up_en = 0; /* 不上拉 */
gpio_config_structure.pull_down_en = 0; /* 不下拉 */
gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE; /* 禁止中斷 */
/* 根據設定參數初始化並使能 */
gpio_config(&gpio_config_structure);
/* 初始化gpio配置結構體*/
gpio_config_structure.pin_bit_mask = (1ULL << GPIO_KEY_NUM);/* 選擇gpio0 */
gpio_config_structure.mode = GPIO_MODE_INPUT; /* 輸入模式 */
gpio_config_structure.pull_up_en = 0; /* 不上拉 */
gpio_config_structure.pull_down_en = 0; /* 不下拉 */
gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE; /* 禁止中斷 */
/* 根據設定參數初始化並使能 */
gpio_config(&gpio_config_structure);
/* 輸出高電平,點亮LED*/
gpio_set_level(GPIO_LED_NUM, 1);
#if 1
/* 創建按鍵檢測任務 */
xTaskCreate((TaskFunction_t )key_task, /* 任務函數 */
(const char* )"key task", /* 任務名稱*/
(uint16_t )2048, /* 任務堆棧大小,單位爲字節*/
(void* )NULL, /* 傳遞給任務函數的參數*/
(UBaseType_t )20, /* 任務優先級,最高優先級爲24 */
(TaskHandle_t* )NULL); /* 任務句柄,在不需要使用任務句柄時,可以填入NULL*/
#else
/* 創建按鍵檢測任務 */
xTaskCreatePinnedToCore((TaskFunction_t )key_task, /* 任務函數 */
(const char* )"key task", /* 任務名稱*/
(uint16_t )2048, /* 任務堆棧大小,單位爲字節*/
(void* )NULL, /* 傳遞給任務函數的參數*/
(UBaseType_t )20, /* 任務優先級,最高優先級爲24 */
(TaskHandle_t* )&Key_Task_Handler, /* 任務句柄*/
(const BaseType_t)tskNO_AFFINITY); /* 指定運行任務的CPU,使用這個宏表示不會固定到任何核上*/
#endif
while(1)
{
gpio_set_level(GPIO_LED_NUM, 0); /* 熄滅 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延時500ms*/
gpio_set_level(GPIO_LED_NUM, 1); /* 點亮 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延時500ms*/
}
while(1)
{
printf("Boot_key Level is : %d \n",gpio_get_level(GPIO_KEY_NUM)); /* 獲取BOOT按鍵電平並打印 */
vTaskDelay(1000 / portTICK_PERIOD_MS); /* 延時1000ms*/
gpio_set_level(GPIO_LED_NUM, 0); /* 熄滅 */
}
}
/* 按鍵檢測任務函數 */
void key_task(void *pvParameters)
{
static int key_up = 1; /* 按鍵鬆開標誌 */
while (1)
{
/* 檢測按鍵是否按下 */
if (key_up && (gpio_get_level(GPIO_KEY_NUM) == 0) )
{
vTaskDelay(50 / portTICK_PERIOD_MS); /* 延時50ms消抖*/
key_up = 0;
if (gpio_get_level(GPIO_KEY_NUM) == 0)
{
/* 按鍵BOOT按下,按鍵按下處理*/
printf("BOOT Key pressed!\n");
}
}
else if(gpio_get_level(GPIO_KEY_NUM) == 1 )
{
key_up = 1; /* 按鍵已鬆開 */
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}