#if( configSUPPORT_STATIC_ALLOCATION == 1 )
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, /* 任务函数 */
const char * const pcName, /* 任务名称 */
const uint32_t ulStackDepth, /* 任务栈大小 */
void * const pvParameters, /* 传递给任务函数的参数 */
UBaseType_t uxPriority, /* 任务优先级 */
StackType_t * const puxStackBuffer, /* 任务栈 */
StaticTask_t * const pxTaskBuffer ) /* 任务控制块 */
返回值: 创建成功:返回指向任务控制块的指针 TaskHandle_t类型
创建失败:返回NULL
相关注意事项:
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, /* 任务函数 */
const char * const pcName, /* 任务名称 */
const uint16_t usStackDepth, /* 任务栈大小 */
void * const pvParameters, /* 传递给任务函数的参数 */
UBaseType_t uxPriority, /* 任务优先级 */
TaskHandle_t * const pxCreatedTask ) /* 任务控制块指针 */
返回值: 创建成功:pdPass
创建失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
相关注意事项:
void vTaskStartScheduler( void )
这个任务是真正进入实时操作系统世界的入口。执行完毕后开始调度
调用该函数后会自动创建空闲任务,如果启用了configUSE_TIMERS宏定义,那么定时器任务也会被在其中自动创建。
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
注意事项:
void vTaskSuspendAll(void)
void vTaskResume(TaskHandle_t xTaskToResume)
任务恢复函数会让挂起的任务重新进入就绪状态,恢复的任务会保留挂起前的状态信息,在恢复时根据挂起时的状态继续运行。如果被恢复任务在所有就绪态任务中处于最高优先级列表的第一位,那么系统将进行任务上下文的切换
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
该函数专门用在中断服务程序中,无论调用过多少次vTaskSuspend函数而挂起的任务,只需要调用一次xTaskResumeFromISR函数即可解挂。
注意事项:
BaseType_t xTaskResumeAll(void)
调用多少次vTaskSuspendAll函数就必须调用相同次数的xTaskResumeAll函数来解挂
#if ( INCLUDE_vTaskDelete == 1 )
void vTaskDelete( TaskHandle_t xTaskToDelete )
注意事项:
#if ( INCLUDE_vTaskDelay == 1 )
void vTaskDelay( const TickType_t xTicksToDelay )
注意事项:
#if ( INCLUDE_vTaskDelayUntil == 1 )
void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
注意事项:
FreeRTOS有两种启动的流程:
在main函数中将硬件、RTOS系统初始化,所有任务创建完毕,此之谓“万事俱备”。“东风”即为启动RTOS的调度器,开始多任务调度
在main函数中将硬件和RTOS系统先初始化好,然后创建一个启动任务后就启动调度器。在启动任务中创建各种应用任务,当所有任务都创建好了之后,启动任务将自己删除。
如果我们要使用FreeRTOS的时候我们要怎么样开启任务? 我们以“万事俱备只欠东风”法来举例
看看configSUPPORT_STATIC_ALLOCATION是否开启(置为1),如果没有,将其置为1
准备好一个TaskHandle_t类型变量来承接我们静态创建任务所返回的任务句柄
static TaskHandle_t Task1_Handle = NULL;
定义任务栈
static StackType_t Task1_Stack[128];
定义任务控制块
static StaticTask_t Task1_TCB = NULL;
调用xTaskCreateStatic函数 静态创建任务
Task1_Handle = xTaskCreateStatic( (TaskFunction_t) Task1,
(const char *) "Task1",
(uint32_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(StackType_t *) Task1_Stack,
(StaticTask_t *) &Task1_TCB );
调用vTaskStartScheduler()函数启动调度
if(Task1_Handle!=NULL)
{
vTaskStartScheduler();
}
查看宏定义 configSUPPORT_DYNAMIC_ALLOCATION 将其开启(置为1)
准备一个BaseType_t类型变量来承接动态创建函数的返回值,不创建也行,只是创建了以后可以更方便地知道是否创建成功
static BaseType_t xReturn;
准备任务句柄变量,这个经过动态创建函数后会指向我们要创建的任务
static TaskHandle_t Task1_Handle = NULL;
调用xTaskCreateStatic()函数动态创建任务
xReturn = xTaskCreate( (TaskFunction_t) Task1,
(const char *) "Task1",
(uint16_t) 512,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t *) Task1_Handle )
调用vTaskStartScheduler()启动调度
if(xReturn == pdPASS)
{
vTaskStartScheduler();
}
绝对延时函数vTaskDelayUntil示例
void Task1(void * pvParameters)
{
/* 用于保存上次时间,调用后系统自动更新 */
static portTickType PreviousWakeTime;
/* 设置延时时间,将时间转为节拍数 */(也可以不用这么麻烦)
const portTickType TimeIncrement = pdMS_TO_TICKS(1000);
/* 获取当前系统时间 */
PreviousWakeTime = xTaskGetTickCount();
while(1)
{
/* 调用绝对延时函数,任务时间间隔为1000个tick */
vTaskDelayUntil(&PreviousWakeTime,TimeIncrement);
//...
//任务主体代码
}
}
任务执行的时间一般指两个方面,一是任务从开始到结束的时间,二是任务的周期。
在设计系统时对这两个时间我们都需要考虑,例如对于事件A对应的服务任务Ta,系统要切的实时响应指标是10ms,而Ta的最大运行时间是1ms,那么10ms就是任务Ta的周期,1ms则是任务的运行时间。简单来说,任务Ta在10ms内完成对事件A的响应即可。此时系统中还存在以50ms为周期的另一个任务Tb,他每次运行的最大时间长度是100us。在这种情况下,即使把任务Tb的优先级设置的比Ta还要高,对系统的实时性指标也没什么影响,因为即使在Ta的运行过程中,Tb抢占了Ta的资源,等到Tb执行完毕,消耗的时间也不过是100us,还是在事件A规定的响应时间内,Ta能够安全地完成对事件A 的相应。但是如果系统中还存在任务Tc,其运行时间为20ms,加入Tc的优先级比Ta高,那么在Ta运行时突然间被Tc打断,等到Tc执行完毕,Ta已经错过了对事件A的相应了,这是不允许的。
因此,在设计时必须要考虑任务的时间,一般来说处理时间更短的任务,其优先级应设置得更高一些。