任务的概念:
从系统的角度看,任务是竞争系统资源的最小运行单元,FreeRTOS是一个支持多任务的操作系统。如果宏定义configUSE_TIME_SLICING为1 则处于就绪态的多个相同优先级任务会以时间片切换的方式共享处理器。
每个FreeRTOS任务都有自己的栈空间,当任务切换时,他的执行环境会被保存在该任务的栈空间中,当这个任务再次运行时,直接从堆栈中正确恢复上下次的运行环境,任务越多,需要的堆栈空间越大,系统能运行多少个任务取决于系统可用的SRAM。
任务还可以利用内核的IPC通信资源,实现任务之间的通信。
任务通常会云翔在一个死循环中,如果一个任务不再需要,可以调用FreeRTOS的任务删除API函数接口将其删除。
任务状态迁移:
就绪态:任务被创建之后就进入就绪态 表明任务已经准别就绪 随时可以运行
就绪态->运行态:发生任务切换时 就绪列表中优先级最高的任务进入运行态
运行态->就绪态:有优先级更高的任务被创建或者恢复后,会发生任务调度,此时就绪列表中优先级最高的任务会变成运行态,原先运行的任务变成就绪态。
运行态->阻塞态:正在运行的任务发生阻塞 该任务会从就绪列表中删除
就绪态,阻塞态,运行态->挂起态:任务可以通过vTaskSuspend()API函数将处于任何状态的任务挂起,被挂起的任务得不到CPU的使用权,也不会参与调度,除非把他从挂起态中解除。
挂起态->就绪态:把一个挂起的任务通过vTaskResume()或者vTaskResumeFormISR()API函数,如果此时被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换。
任务挂起函数:
如果要使用任务挂起函数vTaskSuSPend必须将宏定义 INCLUDE_vTaskSuspend配置为1
xTaskToSuspend是挂起指定任务的句柄,任务必须已创建,可以通过传递NULL来挂起任务自己。
//任务挂起函数的实例
static TaskHandle_t LED_Task_Handle=NULL; //LED任务句柄
static void KEY_Task(void * parameter)
{
while(1)
{
if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==KEY_ON)
{
vTaskSchedule(LED_Task_Handle);
}
vTaskDelay(20);
}
}
vTaskSuspendAll():将所有任务都挂起。
任务恢复函数:
vTaskReusume函数让挂起的函数恢复就绪态。使用这个函数需要将宏定义INCLUDE_vTASKsUSpend配置为1,无论任务在挂起时调用过多少次vTaskSuspend也只需要调用一次vTaskResume即可。
//任务恢复函数实例
static TaskHandle_t LED_Task_Handle=NULL;
static void KEY_Task(void * parameter)
{
while(1)
{
if(Key_Scan(KEY_GPIO_PORT,KEY2_GPIO_PIN)==KEY_ON)
{
vTaskResume(LED_Task_Handle);
}
vTaskDelay(20);
}
}
xTaskResumeFromISR():专门用于将在中断服务函数中将被挂起任务恢复 如果想使用次函数需要将INCLUDE_vTaskSuspend和INCLUDE_vTaskResumeFromISR都设置为1
//实例
void vAnExampleISR(void)
{
BaseType_t xYieldRequired;
xYieldRequired=xTaskResumeFromISR(xHandle);
if(xYieldRequired==pdTURE)
{
portYIELD_FROM_ISR();//执行上下问切换 返回的时候运行另外一个任务
}
}
任务删除函数
用于删除一个任务,形参为要删除的任务创建时返回的句柄,如果删除自身,形参为NULL。
需要配置宏定义INCLUDE_vTaskDelete为1.
//创建一个任务 将创建任务的句柄存储在DeleteHandle中
TaskHandle_t DeleteHandle;
if(xTaskCreate(DeleteTask,"DeleteTask",STACK_SIZE,NULL,PRIORITY,&DeleteHandle)!=pdPASS)
{}
void DeleteTask(void)
{
vTaskDelete(NULL); //删除任务本身
}
//在其他任务中删除
vTaskDelete(DeleteHandle);
任务延时函数
任务函数中应该有阻塞的情况,否则优先级低的任务就无法运行。使用此函数要是宏定义INCLUDE_vTaskDelay为1.
//实例
void vTaskA(void * pvParameters)
{
while(1)
{
//任务主体代码
vTaskDelay(1000);
}
}
vTaskDelayUntil()函数:绝对延时函数,常用于较精确的周期运行任务,任务从上次运行开始到下一次运行的时间间隔是绝对的,不是相对的,需要将宏定义INCLUDE_vTaskDelayUntil为1
void vTaskA(void * pvParameters)
{
//用于保存上次的时间 调用后系统自动更新
static portTickType PreviousWakeTime;
//设置延时时间 将时间转为节拍数
const portTickType TimeIncrement=pdMS_TO_TICKS(1000);
//获取系统当前时间
PreviousWakeTime=xTaskGetTickCount();
while(1)
{
vTaskDelayUntil(&PreviousWakeTime,TimeIncrement);
//任务主体代码
}
}
任务的设计要点:
任务设计的几点因素:任务运行的上下文环境,任务执行的时间合理设计
程序运行中的上下文包括:
中断服务函数 普通任务 空闲任务
中断服务函数:最好保持精简短小 快进快出 要考虑中断的频率 处理时间灯重要因素 以便配合对应中断处理任务的工作