一、Freertos介绍
FreeRTOS是一个开源的实时操作系统内核,它是由英国的Real Time Engineers Ltd.开发的。它提供了一些基本的内核功能,如任务管理、时间管理、信号量、队列和软件定时器等,可以帮助开发人员更容易地构建嵌入式系统。FreeRTOS是一个非常流行的实时操作系统内核,因为它是免费的、可移植的、可扩展的,并且可以在多种处理器架构上运行。它已经被广泛地应用于许多嵌入式系统中,如工业自动化、医疗设备、消费电子、汽车电子等。
Freertos最低移植需task、queue、list三个组件。
二、任务介绍
使用 RTOS 的实时应用程序可以被构建为一组独立的任务。每个任务在自己的上下文中执行,不依赖于系统内的其他任务或 RTOS 调度器本身。在任何时间点,应用程序中只能执行一个任务,实时 RTOS 调度器负责决定所要执行的任务。因此, RTOS 调度器可以在应用程序执行时重复启停每个任务(将任务调入或调出)。由于任务不了解 RTOS 调度器活动,因此实时 RTOS 调度器负责确保任务调入时的处理器上下文(寄存器值、堆栈内容等)与任务调出时的处理器上下文完全相同。为实现这一点,每个任务都分配有自己的堆栈。当任务调出时,执行上下文被保存到该任务的堆栈中,以便以后再调入相同的任务时可以准确地恢复其执行上下文。
在这里的介绍中我们可以总结任务的几个特点:
(1)任务是独立的实体:在FreeRTOS中,每个任务都是独立的实体,它们有自己的堆栈和上下文。这使得任务之间的通信和同步变得更加容易。
(2)任务具有优先级:FreeRTOS中的任务可以设置不同的优先级。这使得高优先级任务可以在低优先级任务之前执行,从而提高系统的响应能力。
(3)任务的调度:FreeRTOS使用抢占式调度算法,这意味着当一个高优先级任务准备好运行时,它可以抢占当前正在运行的低优先级任务。这种调度算法可以确保高优先级任务及时地得到执行。
(4)任务的堆栈:FreeRTOS中的任务有自己的堆栈,这使得任务之间的数据不会相互干扰。同时,堆栈的大小也可以根据任务的需要进行配置。
二、任务创建与删除
1.xTaskCreate()函数
该函数的功能是创建一个任务,该函数返回值类型为BaseType_t ,即boolean 类型,有两个常量值,true 和 false,共有六个输入参数:
参数 | 描述 |
---|---|
pvTaskCode | 任务函数,所要执行的具体任务 |
*pcName | 任务名,创建任务时给该任务起个别名 |
usStackDepth | 任务栈大小,以字为单位 |
* pvParameters | 任务参数,传递参数至任务函数中 |
uxPriority | 任务优先级,0是最低优先级,数字越大,优先级越高 |
*pxCreatedTask | 任务句柄,创建任务时产生,类似于PID号 |
TaskHandle_t xTask2Handle = NULL; // 储藏 task 2 的句柄
xTaskCreate(blinke_13,"mytask",1024,NULL,1,&xTask2Handle); //函数举例,
为blinke_13()函数创建一个任务,
该任务名称为mytask,
分配任务栈大小为1024字,
无传入参数,
任务优先级为1,
为任务句柄xTask2Handle赋值
1.vTaskDelete()函数
该函数的作用是删除一个用函数xTaskCreate()或者xTaskCreateStatic()创建的任务,被删除了的任务不再存在,也就是说再也不会进入运行态,任务被删除以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放掉,即内核分配给任务的内存才会在任务被删除以后自动的释放掉,用户分配给任务的内存需要用户自行释放掉,比如某个任务中用户调用函数pvPortMalloc()分配了500 字节的内存,那么在此任务被删除以后用户也必须调用函数vPortFree()将这500 字节的内存释放掉,否则会导致内存泄露。
参数 | 描述 |
---|---|
pxTask | 所要删除的任务的句柄 |
vTaskDelete(xTask2Handle); //xTask2Handle为上文中创建"mytask"任务的句柄
该函数也有另一种用法,即不用传入句柄,直接将函数放入。任务函数内部,当该任务执行完毕后,该任务也将自行删除。
void blinke_13(void *pvparam)
{
gpio_set_level(GPIO_NUM_13, 1);//高低电平
printf("靓仔\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);//延时
gpio_set_level(GPIO_NUM_13, 0);//高低电平
vTaskDelay(1000 / portTICK_PERIOD_MS);//延时
vTaskDelete(NULL); //删除任务
}
三、代码测试
1.仅创建任务,并不删除
#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#define LED1_IO 12
#define LED1_IO_PIN (1ULL << 12)
TaskHandle_t xTask2Handle = NULL; // 储藏 task 2 的句柄
void blinke_13(void *pvparam)
{
while (1)
{
gpio_set_level(LED1_IO, 1); // 高电平
printf("靓仔\n");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
gpio_set_level(LED1_IO, 0); // 低电平
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
}
}
void Ledconfig(void)
{
/*------------------ LED1的IO配置 -------------------------------*/
gpio_config_t LED_cof;
// 设置配置IO为12
LED_cof.pin_bit_mask = LED1_IO_PIN;
// 设置为输出模式
LED_cof.mode = GPIO_MODE_OUTPUT;
// 禁止上拉
LED_cof.pull_up_en = 0;
// 禁止下拉
LED_cof.pull_down_en = 0;
// 禁用中断
LED_cof.intr_type = 0;
// 将配置写入
gpio_config(&LED_cof);
}
void app_main(void)
{
Ledconfig();
xTaskCreate(blinke_13, "mytask", 1024, NULL, 1, xTask2Handle); // 函数举例,
}
测试效果:
任务已经成功执行。
2.创建任务并删除
#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#define LED1_IO 12
#define LED1_IO_PIN (1ULL << 12)
TaskHandle_t xTask2Handle = NULL; // 储藏 task 2 的句柄
void blinke_13(void *pvparam)
{
while (1)
{
gpio_set_level(LED1_IO, 1); // 高电平
printf("靓仔\n");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
gpio_set_level(LED1_IO, 0); // 低电平
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
}
}
void Ledconfig(void)
{
/*------------------ LED1的IO配置 -------------------------------*/
gpio_config_t LED_cof;
// 设置配置IO为12
LED_cof.pin_bit_mask = LED1_IO_PIN;
// 设置为输出模式
LED_cof.mode = GPIO_MODE_OUTPUT;
// 禁止上拉
LED_cof.pull_up_en = 0;
// 禁止下拉
LED_cof.pull_down_en = 0;
// 禁用中断
LED_cof.intr_type = 0;
// 将配置写入
gpio_config(&LED_cof);
}
void app_main(void)
{
Ledconfig();
xTaskCreate(blinke_13, "mytask", 1024, NULL, 1, &xTask2Handle); // 函数举例,
vTaskDelay(2000 / portTICK_PERIOD_MS); // 延时
vTaskDelete(xTask2Handle); //删除任务
}
使用vTaskDelete()函数删除已创建的任务,传入参数为任务句柄,上述代码中创建函数后短暂段延迟后再接着删除函数,是为了给一小段时间让任务执行一两次,代码效果如下,任务执行一小段时间就被删除了,无法继续执行。
3.创建任务并在任务内删除任务
#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#define LED1_IO 12
#define LED1_IO_PIN (1ULL << 12)
TaskHandle_t xTask2Handle = NULL; // 储藏 task 2 的句柄
void blinke_13(void *pvparam)
{
gpio_set_level(LED1_IO, 1); // 高电平
printf("靓仔\n");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
gpio_set_level(LED1_IO, 0); // 低电平
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
vTaskDelete(NULL); // 删除任务
}
void Ledconfig(void)
{
/*------------------ LED1的IO配置 -------------------------------*/
gpio_config_t LED_cof;
// 设置配置IO为12
LED_cof.pin_bit_mask = LED1_IO_PIN;
// 设置为输出模式
LED_cof.mode = GPIO_MODE_OUTPUT;
// 禁止上拉
LED_cof.pull_up_en = 0;
// 禁止下拉
LED_cof.pull_down_en = 0;
// 禁用中断
LED_cof.intr_type = 0;
// 将配置写入
gpio_config(&LED_cof);
}
void app_main(void)
{
Ledconfig();
xTaskCreate(blinke_13, "mytask", 1024, NULL, 1, &xTask2Handle); // 函数举例,
}
代码效果如下,函数仅执行一次就被删除。