第一章
1.1任务函数
任务的函数原型必须返回void,而且带有一个void指针参数。原型:
void ATaskFunction(void *pvParrameters);
FreeRTOS任务不允许以任何方式从实现函数中返回——它们绝不能有“return”语句,也不能执行到函数末尾。如果一个任务不再需要,可以vTaskDeltete()显式地将其删除。
1.2 xTaskCreate() API函数
pvTaskCode:一个指向任务的实现函数的指针(效果上仅仅是函数名)
pcName:具有描述性的任务名。
定义常量config_MAX_TASK_NAME_LEN来定义任务明的最大长度——包括”\0”结束符。
usStackDepth:任务分配多大的栈空间,指定的是栈空间可以保存多少个字(32位:1word = 4bytes)。栈的深度不能超过一个size_t类型变量所能表达的最大值。
定义常量configMINIMAL_STACK_SIZE来决定空闲任务人用的栈空间大小。
pvParameter:任务函数接收一个指向void的指针(void*),pvParaneters的值即是传递到任务中的值。
uxPriority:指定任务执行的优先级。优先级的取值范围可以从最低优先级0级到最高优先级(configMAX_PRIORITIES - 1)。
pxCreatedTask:用于传出任务的句柄。
pdTRUE:表示任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:表示内存堆空间不足,FreeRTOS无法分配足够的空火箭来保存任务结构数据和任务堆栈。
1.3任务优先级
低优先级号表示任务的优先级低,优先级号0表示最低优先级。有效的优先级号范围从0到(configMAX_PRIORITIES - 1)
调度器保证总是在所有可运行的任务中选择具有最高优先级的任务,并使其进入运行态。
两个测试任务被创建在同一个优先级上,并且一直是可运行的。所以每个人物都执行一个”时间片”,任务在时间片起始时刻进入运行态,在时间片结束时刻又退出运行态。
左图t1与t2之间的时段就等于一个时间片。
时间片的长度通过心跳中断的频率进行设定,心跳中断频率由FreeRTOSConfig.h中的编译时配置常量configTICK_RATE_HZ进行配置。FreeRTOS API函数调用中指定的时间总是以心跳中断为单位。
1.4扩充“非运行态”
调度器总是选择所有能够进入运行态的任务中具有最高优先级的任务。
阻塞任务:如果一个任务正在等待某个事件,则称这个任务处于“阻塞态。”
任务可以进入阻塞态以等待一下两种不同类型的事件:
1.定时(时间相关)事件
2.同步事件——源于其它任务或中断的事件
挂起状态:一个任务进入挂起状态的唯一办法就是调用vTaskSuspend() API函数,把一个挂起状态的任务唤醒的唯一途径就是调用vTaskResume()或VTaskResumeFromISR() API函数
就绪状态:如果任务处于非运行状态,但既没有阻塞也没有挂起,则这个任务处于就绪状态。
void vTaskDelay(portTickType xTicksToDelay);
xTicksToDelay:延迟多少个心跳周期。调用该延迟函数的任务将进入阻塞态,经延迟指定的心跳周期数后,在转移到就绪态。
void vTaskDelayUntil( portTickType * pxPreviousWakeTime, portTickType xTimeIncrement );
vTaskDelayUntil()的参数就是用来指定任务离开阻塞态进入就绪态那一刻的精确心跳计数值。
pxPreviousWakeTime:保存了任务上一次离开阻塞态的时刻,这个时刻被用作一个参考点来计算该任务下一次离开阻塞态的时刻。pxPreviousWakeTime指向的变量会在API函数vTaskDelayUntil()调用过程中自动更新。
xTimeIncrement:实现某个任务以固定频率周期性执行
1.5空闲任务与空闲任务钩子函数
空闲任务拥有最低优先级(优先级0)以保证其不会妨碍具有更高优先级的应用任务进入运行态。
空闲钩子函数:通过空闲任务钩子函数,可以直接在空闲任务中添加应用程序相关的功能,
通常空闲任务钩子函数被用于:
·执行低优先级,后台或需要不停处理的功能代码
·测试系统处理裕量
·将处理器配置到低功耗模式
空闲任务钩子函数的实现限制:
绝不能阻或挂起
如果应用程序用到了vTaskDelete() API函数,则空闲钩子函数必须尽快返回。
定义一个空闲任务钩子函数:
void vApplicationIdleHook( void );
FreeRTOSConfig.h中的配置常量configUSE_IDLE_HOOK必须定义为1,这样空闲任务钩子函数才会被调用。
1.6改变任务优先级
vTaskPrioritySet() API函数:用于在调度器启动后改变人和任务的优先级
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
pxTask:被修改优先级的任务句柄
uxNewPriority:目标任务将被设置到那个优先级上。如果设置的值超过了最大可用优先级(configMAX_PRIORITIES - 1),则会被自动封顶为最大值
uxTaskPriorityGet() API函数:用于查询一个任务的优先级
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
1.7删除任务
vTaskDelete() API函数
void vTaskDelete( xTaskHandle pxTaskToDelete );
pxTaskToDelete:被删除任务的句柄
1.8调度算法
优先级抢占式调度
所谓“固定优先级”是指每个任务都被赋予了一个优先级,这个优先级不能被内核本身改变。“抢占式”是指当人物进就绪态被改变时,如果处于运行态的任务优先级更低,则该任务总是抢占当前任务的任务。
选择任务优先级
单调速率优先级,根据任务周期性执行的速率来分配一个唯一的优先级。具有最高执行频率的任务赋予高最优先级;具有最低周期执行频率的任务赋予最低优先级。
协作调度
只可能在运行态任务进入阻塞态或是运行任务显式taskYIELD()时,才会进行上下文切换。任务永远不会被抢占,而具有相同优先级的任务也不会自动共享处理器时间。