一、前言
FreeRTOS是一个流行的实时操作系统,它支持多任务处理。在FreeRTOS中,任务有不同的状态,这些状态反映了任务在系统中的行为。
二、状态特点
任务可以存在于以下状态中:
-
运行
当任务实际执行时,它被称为处于运行状态。 任务当前正在使用处理器。 如果运行 RTOS 的处理器只有一个内核, 那么在任何给定时间内都只能有一个任务处于运行状态。 -
准备就绪
准备就绪任务指那些能够执行(它们不处于阻塞或挂起状态), 但目前没有执行的任务, 因为同等或更高优先级的不同任务已经处于运行状态。 -
阻塞
如果任务当前正在等待时间或外部事件,则该任务被认为处于阻塞状态。 例如,如果一个任务调用vTaskDelay(),它将被阻塞(被置于阻塞状态), 直到延迟结束-一个时间事件。 任务也可以通过阻塞来等待队列、信号量、事件组、通知或信号量 事件。 处于阻塞状态的任务通常有一个"超时"期, 超时后任务将被超时,并被解除阻塞, 即使该任务所等待的事件没有发生。
“阻塞”状态下的任务不使用任何处理时间,不能 被选择进入运行状态。
- 挂起
与“阻塞”状态下的任务一样, “挂起”状态下的任务不能 被选择进入运行状态,但处于挂起状态的任务 没有超时。 相反,任务只有在分别通过 vTaskSuspend() 和 xTaskResume() API 调用明确命令时 才会进入或退出挂起状态。
以上几种状态中需要注意挂起态和阻塞态,函数可以通过调用vTaskDelay()函数来进入阻塞态,挂起态则通过vTaskSuspend()进入挂起态
三、实例测试
1.相关函数
1)挂起函数vTaskSuspend()
,这个函数可以将任务从就绪、运行、以及阻塞态置入挂起态,输入参数为任务的句柄,将函数写在任务函数的内部可以将自己挂起,此时输入参数无须句柄,为NULL。
2)挂起所有任务函数vTaskSuspendAll()
,这个函数的工作原理是系统维护一个全局变量uxSchedulerSuspended的计数值,对于FreeRTOS来说,task的切换是在中断中发生的,如果中断进来,中断中会对uxSchedulerSuspended这个变量的值进行判断,从而决定是否需要进行Task切换。当其大于0的时候禁止调度,等于0的时候表示允许调度。
如果调度器挂起话,当前正在执行的Task会一直继续执行,内核不再调度(意味着当前任务不会被切换出去),直到该任务调用了xTaskResumeAll()函数。
注意在使用vTaskSuspendAll()
挂起其余任务区间,不允许调用其他FreeRTOS API 函数。
3)恢复函数vTaskResume()
,挂起函数相对,恢复函数可以将处于挂起状态的函数恢复至就绪态,注意只能是就绪态。使用时只需要传入句柄即可。
4)恢复所有函数xTaskResumeAll()
,可与vTaskSuspendAll()
配合使用,将所有函数的挂起态解除。
2.代码测试
测试1:该例子在任务创建之后先将task1挂起,经短暂延迟恢复,所以可以观察到有一段只有task2输出,task1无输出:
#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
void mytask1(void *pvParam)
{
while (1)
{
printf("111-task1 \n");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
}
}
void mytask2(void *pvParam)
{
while (1)
{
printf("222-task2 \n");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
}
}
void app_main(void)
{
TaskHandle_t xHandle = NULL; // 任务句柄
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, &xHandle); // 传入参数
xTaskCreate(mytask2, "mytask2", 1024, NULL, 2, NULL); // 传入参数
vTaskDelay(2000 / portTICK_PERIOD_MS); // 延时
vTaskSuspend(xHandle); // 挂起
vTaskDelay(2000 / portTICK_PERIOD_MS); // 延时
vTaskResume(xHandle); // 恢复
}
测试2:测试vTaskSuspendAll()
与xTaskResumeAll()
,有时我们需要保证某个任务运行期间不被打扰,例如对都某时间点的各传感器数据进行采样,因为要保证传感器数据尽量在同一时刻采集,所以此时我们可以停止其他任务调度,等待采集结束后再恢复。
#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
void mytask1(void *pvParam)
{
printf("task1-begin \n");
vTaskSuspendAll(); // 挂起所有任务
for (int i = 0; i < 9999; i++)
{
for (int j = 0; j < 9999; j++)
{
; // 模拟不可中断任务
}
}
xTaskResumeAll(); // 恢复所有任务
printf("task1-over \n");
vTaskDelete(NULL);
}
void mytask2(void *pvParam)
{
while (1)
{
printf("222-task2 \n");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时
}
}
void app_main(void)
{
TaskHandle_t xHandle = NULL; // 任务句柄
xTaskCreate(mytask1, "mytask1", 2048, NULL, 1, &xHandle); // 传入参数
xTaskCreate(mytask2, "mytask2", 2048, NULL, 2, NULL); // 传入参数
}
测试结果:符合预期。
THE END!
标签:03,Task,函数,Freertos,状态,void,NULL,任务,include From: https://www.cnblogs.com/seekwhale13/p/17506877.html