本次开发是在Ubuntu下的,使用的模块是GOOUUU-ESP32,使用VSCode编辑项目。基于工程:ESP32开发之路(2)— HelloWorld工程分析和优化
复制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已经亮起来了:
我们编写一个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);
}
}
说一下任务创建函数,因为我之前看的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
#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);
}
}