ESP8266 RTOS开发之路(3)— 点亮第一个LED灯及按键输入
一、前言
本次开发基于虚拟机下的Ubuntu18系统,ESP8266_RTOS_SDK版本为v3.4-rc,使用的模块是ESP8266-NodeMcu,其板载模组为ESP12E,flash大小为32Mbit,图片如下:
二、点亮第一个LED灯
在上一个hello_world工程的基础上复制文件并命名为01_led_key
,修改hello_world_main.c
为app_main.c
,
通过查询硬件原理图可得,ESP12E上自带的LED连在GPIO2上;所以首先宏定义LED的引脚编号:
#define GPIO_LED_NUM 2
添加gpio头文件包含
#include "driver/gpio.h"
然后定义一个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_INTR_DISABLE; /* 禁止中断 */
/* 根据设定参数初始化并使能 */
gpio_config(&gpio_config_structure);
然后将其设为高电平,点亮该LED灯:
/* 输出低电平,点亮LED*/
gpio_set_level(GPIO_LED_NUM, 0);
即app_mian.c
修改为如下所示
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.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
void app_main()
{
printf("Hello world!\n");
/* 1.定义一个gpio配置结构体 */
gpio_config_t gpio_config_structure;
/* 2.初始化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_INTR_DISABLE; /* 禁止中断 */
/* 3.根据设定参数初始化并使能 */
gpio_config(&gpio_config_structure);
/* 4.输出低电平,点亮LED*/
gpio_set_level(GPIO_LED_NUM, 0);
while (1)
{
printf("Hello world!\n");
printf("SDK version:%s\n", esp_get_idf_version());
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
然后编译烧录运行,我们可以看到ESP12E模组上的蓝色LED已经亮起来了:
三、LED闪烁
我们编写一个while循环,让LED一秒闪烁一次
while(1)
{
gpio_set_level(GPIO_LED_NUM, 1); /* 熄灭 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延时500ms*/
gpio_set_level(GPIO_LED_NUM, 0); /* 点亮 */
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_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=15
,所以任务优先级可选范围为0~14
,且数字越大,优先级越高!
/* 定义按键检测任务的任务句柄*/
TaskHandle_t Key_Task_Handler;
/* 声明按键检测任务函数 */
void key_task(void *pvParameters);
然后在主任务里创建按键检测任务,
/* 创建按键检测任务 */
xTaskCreate((TaskFunction_t )key_task, /* 任务函数 */
(const char* )"key task", /* 任务名称*/
(uint16_t )2048, /* 任务堆栈大小,单位为字节*/
(void* )NULL, /* 传递给任务函数的参数*/
(UBaseType_t )10, /* 任务优先级,最高优先级为24 */
(TaskHandle_t* )Key_Task_Handler); /* 任务句柄,在不需要使用任务句柄时,可以填入NULL*/
然后我们实现按键检测任务函数,注意,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正常闪烁
/* 创建按键检测任务 */
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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "driver/uart.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_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_INTR_DISABLE; /* 禁止中断 */
/* 根据设定参数初始化并使能 */
gpio_config(&gpio_config_structure);
/* 输出低电平,点亮LED*/
gpio_set_level(GPIO_LED_NUM, 0);
/* 创建按键检测任务 */
xTaskCreate((TaskFunction_t )key_task, /* 任务函数 */
(const char* )"key task", /* 任务名称*/
(uint16_t )2048, /* 任务堆栈大小,单位为字节*/
(void* )NULL, /* 传递给任务函数的参数*/
(UBaseType_t )10, /* 任务优先级,最高优先级为24 */
(TaskHandle_t* )Key_Task_Handler); /* 任务句柄,在不需要使用任务句柄时,可以填入NULL*/
while(1)
{
gpio_set_level(GPIO_LED_NUM, 1); /* 熄灭 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延时500ms*/
gpio_set_level(GPIO_LED_NUM, 0); /* 点亮 */
vTaskDelay(500 / portTICK_PERIOD_MS); /* 延时500ms*/
}
#if 0
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); /* 熄灭 */
}
#endif
}
/* 按键检测任务函数 */
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);
}
}
六、附录
上一篇:ESP8266 RTOS开发之路(1)— 搭建在Ubuntu下的开发环境
下一篇: