ESP32開發之路(3)--- 點亮第一個LED燈及按鍵輸入

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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章