第一章-任务管理
1.任务函数
1.1任务函数返回值必须为void 且带有一个void *参数 void ATaskFunction( void *pvParameters );
1.2任务函数决不能有return,也不能执行到末尾。
2.创建任务
portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, //Pointer to the task to achieve function
const signed portCHAR *const pcName, //the of the task and nvever used
unsigned portSHORT usStackDepth, //Task stack size ,the max stack size by configMINIMAL_STACK_SIZE defination
void *pvParameters, //the parameter of the task function througn the pvParameters pointer passed
unsigend portBASE_TYPE uxPriority, //the priority of tht task which maximun by configMAX_PRIORITIES
xTaskHandle *pxCreatedTask ) //used to spread the task of the handle
RETURN VALUE : pdTRUE:create success
:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY :insufficient memory space
3.任务优先级
1.xTaskCreate()API函数为创建的任务赋予一个初始化优先级。这个优先级可以在调度器启动后通过vTaskPrioritySet()API函数进行修改。
2.最大优先级通过configMAX_PRIORITES定义,有效优先级号范围从 0~configMAX_PRIORITES-1.
3.同一优先级的任务通过时间片来调度,时间片通过心跳频率来控制,心跳频率通过configTICK_RATE_HZ进行配置。FreeRTOS API函数中指定的时间总是以心跳中断为单位,常亮portTICK_RATE_MS用于将心跳为单位的时间转化为毫秒时间。
4.非运行状态
不同优先级的任务,低优先级任务只有等高优先级任务执行完后才能执行,那么如果高优先级任务一直在循环执行,那么低优先级任务就会无法执行(饿死)。
阻塞状态
任务如果正在等待某个事件,则称这个任务处于阻塞状态。阻塞态是非运行态的一个子状态。
任务可以进入阻塞态等待以下两种不同事件
- 定时事件--这类事件可以延迟到期或者绝对时间到点。
- 同步事件--源于其他任务或中断时间。比如某个任务可以进入阻塞等待队列中有数据到来,同步时间囊括了所有扳级范围内的事件类型。
FreeRTOS的队列,二值信号量,计数信号量,互斥信号量和互斥量,都可以实现同步事件。
任务可以在进入阻塞态设置一个等待超时时间,这个可以有效的实现阻塞态下等待两种事件。
利用阻塞实现延迟
一般延迟方法都是原地使用空循环,查询循环变量的值。但是一直保持在运行态中的空循环,导致其他任务饿死。其实以任何方式查询都不仅仅是低效的,在查询过程中,依然会消耗处理器资源。所以FreeRTOS中通过调用vTaskDelay()来带起空循环。
xTicksToDelay()延迟多少个心跳周期。
xTaskDelayUntil()函数类似上面,不过参数是离开阻塞态的精准时间。
挂起状态
调用vTASKSuspend()函数,让一个任务进入挂起状态。调用vTaskResume()或者vTaskResumeFromISR()函数唤醒挂起。
就绪状态
就绪态的任务等待时间片到来得以运行。
空闲任务和空闲钩子函数
空闲任务会自动创建,优先级最低,保证处理器始终有代码执行。负责回收系统资源
空闲钩子函数
空闲钩子函数会在空闲任务每次循环一次就自动调用一次。通常有以下作用
- 执行低优先级,后台需要不断处理的功能代码
- 测试系统处理负载
- 将处理器配置为低功耗
钩子函数实现限制
- 绝不能阻塞或者挂起。空闲任务只会在其他任务不允许时才运行。
- 如果应用程序调用了vTaskDelete()空闲钩子函数要尽快返回。因为空闲任务负责回收系统资源。