点击跳转FreeRTOS介绍
ESP32的FreeRTOS使用
这里我们只介绍常用的API其他API自行查询官方文档 官方文档介绍
创建任务
使用xTaskCreate来创建任务
函数定义如下:
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode,//任务函数
const char * const pcName,//任务名称
const uint32_t usStackDepth,//堆栈大小 单位字节
void * const pvParameters, //传入的参数
UBaseType_t uxPriority,//任务优先级
TaskHandle_t * const pxCreatedTask)//任务句柄指针
pvTaskCode:任务函数 类型为void 函数名 (void* 参数名){}类型pcName:任务名称 不能使用中文usStackDepth:堆栈大小 单位字节,常见取值范围是[128-8192]pvParameters:传入的参数指针 不需要时传入 nullptruxPriority:任务优先级 数字越大优先级越高 0为最小优先级 普通任务优先级建议为5pxCreatedTask:任务句柄指针 不需要时传入 nullptr
注意xTaskCreate创建的任务是运行在多核上的
xTaskCreatePinnedToCore可以指定运行在那个核心(0-1)

删除任务
void vTaskDelete( TaskHandle_t xTaskToDelete )
FreeRTOS中对任务进行操作都是用任务句柄
- xTaskToDelete 要删除的任务句柄,为NULL时删除当前任务
任务中延时
标准延时
FreeRTOS标准的任务中延时应该用
void vTaskDelay(const TickType_t xTicksToDelay)
但是ESP32的Arduino SDK中的delay函数定义如下:
可以看到和vTaskDelay是等价的,所以esp32使用delay函数是不阻塞CPU的
注意主动delay最小时间为一个时间片,正常情况下是1ms,小于1ms不可用delay实现
而是使用delayMicroseconds(uint32_t us):注意该函数会阻塞CPU
控制频率的延时
首先我们看一个示例
// 控制任务函数
void DMMotorSpeedPos::DMmotortask(void* _motor) {
DMMotorSpeedPos* motor =reinterpret_cast<DMMotorSpeedPos*>(_motor);
while (1) {
motor->sendSpeedPospakage(); // 每次循环发送数据包
delay(1000 / motor->DataRateHz); // 根据数据频率设置延时
}
}
这是一个典型的循环任务,目的是以固定频率执行某些任务
我们很容易理解
- 每次循环体执行的时间是1ms 那么整体频率就是1000HZ
真的是这样吗?
大多数的情况下我们执行的任务时间复杂度并不高,在1000个cpu周期以下
那么正常情况语句只需要
实际频率约为
和预期相差不大可以接受
但是如果语句的执行时间为ms级别,或者会不定阻塞CPU 这时实际频率和预期频率就会差很多,并且一些涉及控制的场景还会影响控制 此时我们就需要使用
xTaskDelayUntil
函数原型
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,const TickType_t xTimeIncrement )
- pxPreviousWakeTime :上次更新的时间,传入
TickType_t的指针 - xTimeIncrement :延时的tick数,一般为
configTICK_RATE_HZ /{控制频率}。configTICK_RATE_HZ是FreeRTOS的系统频率宏定义 此时改写上面的示例为:
// 控制任务函数
void DMMotorSpeedPos::DMmotortask(void* _motor) {
DMMotorSpeedPos* motor =reinterpret_cast<DMMotorSpeedPos*>(_motor);
// 获取当前时间
auto xLastWakeTime = xTaskGetTickCount ();
while (1) {
// 每次循环发送数据包
motor->sendSpeedPospakage();
// 根据数据频率设置延时
xTaskDelayUntil(&xLastWakeTime, configTICK_RATE_HZ / motor->DataRateHz);
}
}
让出CPU
正常情况下任务中有delay或者非阻塞函数的使用,是不需要主动释放CPU的。
vPortYield():主动让出当前CPU,让CPU执行其他任务