目录
一. 在应用程序中,FreeRTOS 如何为各任务分配处理时间。
二· 在任意给定时刻,FreeRTOS 如何选择任务投入运行。
一. 在应用程序中,FreeRTOS 如何为各任务分配处理时间。
1.设置FreeRTOSConfig.h 中的常量 configTICK_RATE_HZ,设置系统心跳周期
2.假设心跳周期为10ms,同优先级任务(无空闲延时且不进入阻塞),任务调度器会调用其中一个任务运行,10ms期间任务会不断运行,10ms的时候会产生中断,任务调度器会选择新的任务进行运行
3.此时添加一个高优先级任务,在等待完高优先级任务的阻塞时间到了,高优先级任务会打断低优先级任务进行运行
4.如果低优先级的任务有空闲时间也会进如阻塞,则空闲时间将会运行空闲函数
FreeRTOSConfig.h 中的配置常量 configUSE_IDLE_HOOK 必须定义为 1,这样空闲任务钩子函数才会被调用
空闲任务钩子函数:
void vApplicationIdleHook( void );
二· 在任意给定时刻,FreeRTOS 如何选择任务投入运行。
freeRTOS调度器在不同的风格下,任意时刻选择任务运行情况是不同的,大概分为下面几种情况。
1.优先级抢占式调度
低优先级任务在运行时,高优先级任务切除阻塞态,任务调度器将让高优先级任务运行。
2.单速率调度
周期执行频率低的优先级低,周期执行频率高的优先级高
3.协作式调度
该调度方式,任务不会被抢占,同优先级的任务也不会轮流被任务任务调度器调用,任务从运行态进入阻塞态,或者运行态中的任务显式调用taskYIELD()时,任务将被切换。
4.混合调度
一种高效的、常用的、没有时间片机制的抢占系统, 需要在中断中进行显式调用切换上下文,允许同步事件产生抢占行为。
三· 任务优先级如何影响系统行为
系统会根据任务的优先级高低去执行任务,优先级最低的空闲任务会被低优先级(优先级高于0)任务打断,中优先级任务会打断低优先级任务和空闲任务,高优先级任务可以打断中优先级任务、低优先级任务和空闲任务。其中硬实时任务高于软实时任务优先级。
四· 任务存在哪些状态
就绪态、阻塞态、运行态
五·如何实现一个任务
1.任务是由C语言函数实现的,如下
void ATaskFunction( void *pvParameters );
{
/* 可以像普通函数一样定义变量。用这个函数创建的每个任务实例都有一个属于自己的 iVarialbleExample变量。但如果iVariableExample被定义为static,这一点则不成立 – 这种情况下只存在一个变量,所有的任务实例将会共享这个变量。 */
int iVariableExample = 0;
/* 任务通常实现在一个死循环中。 */
for( ;; )
{
/* 完成任务功能的代码将放在这里。 */
}
/* 如果任务的具体实现会跳出上面的死循环,则此任务必须在函数运行完之前删除。传入NULL参数表示删除
的是当前任务 */
vTaskDelete( NULL );
}
2.任务是没有返回值的
3. 任务一般是死循环的(如果要跳出死循环最后得先删掉此任务)
六· 如何创建一个或多个任务的实例。
1.在main()函数中创建一个或者多个任务
2.创建一个开始任务,在开始任务函数中创建一个或多个任务函数
portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode,
const signed portCHAR * const pcName,
unsigned portSHORT usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pxCreatedTask );
pvTaskCode | 函数名(指向任务的实现函数的指针) |
pcName | 任务名(不会被freeRTOS使用,作辅助调试用,量 config_MAX_TASK_NAME_LEN可以设置任务名长度) |
usStackDepth | 栈深度(32位系统,申请内存为X*32bytes, 应用程序通过定义常量 configMINIMAL_STACK_SIZE 来决定空闲 任务任用的栈空间大小) |
pvParameters | 可以传递到任务中的参数 |
uxPriority | 优先级(0、1、……、configMAX_PRIORITIES – 1) |
pxCreatedTask | 用于传出任务的句柄(对创建的任务进行引用,删除或者改变优先级,也可以设置为null) |
返回值 | pdTRUE:任务创建成功 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:内存空间不足 |
七· 如何使用任务参数。
1.创建任务的时候,传递参数不为NULL
例如:
xTaskCreate( vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2, 1, NULL );
2.任务中传递参数为形参,任务中定义变量获取传递参数的数据
例如:
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
/* 需要打印输出的字符串从入口参数传入。强制转换为字符指针。 */
pcTaskName = ( char * ) pvParameters;
for( ;; )
{
vPrintString( pcTaskName );
}
}
八· 如何让任务进入阻塞态以及如何设置阻塞的时间。
使高优先级任务进入阻塞态
void vTaskDelay( portTickType xTicksToDelay );
xTicksToDelay | 心跳周期(xTicksToDelay/数 portTICK_RATE_MS可以转换为以毫秒为单位) |
例如:设置300ms循环周期
vTaskDelay( 300 / portTICK_RATE_MS );
将阻塞时间设置更加精准
void vTaskDelayUntil( portTickType * pxPreviousWakeTime, portTickType xTimeIncrement );
pxPreviousWakeTime | 保存了任务上一次离开阻塞态(被唤醒)的时刻 |
xTimeIncrement | 心跳周期(xTimeIncrement/数 portTICK_RATE_MS可以转换为以毫秒为单位) |
例如:
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount(); //记录任务切除阻塞态的时间
vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) );
九· 如何改变一个已创建任务的优先级。
在调度器启动后使用下面函数改变任务优先级
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
pxTask | 被修改优先级的任务的句柄 |
uxNewPriority | 优先级 |
十· 如何查询任务优先级。
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
pxTask | 被查询任务的句柄 |
返回值 | 被查询任务的优先级 |
十一· 如何删除任务。
使用任务删除函数vTaskDelete( NULL ); //在任务会跳出无限循环的时候使用,NULL代表删除本任务
void vTaskDelete( xTaskHandle pxTaskToDelete );
pxTaskToDelete | 被删除任务的句柄 |
十二· 如何实现周期性处理。
设置FreeRTOSConfig.h 中的常量 configTICK_RATE_HZ
例如:
configTICK_RATE_HZ 设为 100(HZ),则时间片长度为 10ms,每间隔10ms进入一次中断切换任务
十三· 空闲任务何时运行,可以用来干什么。
所有的任务都在处于阻塞态的时候运行,空闲任务是由任务调度器生成的,为了保证程序每个时刻都在运行任务
十四.参考文献
FreeRTOS实时内核使用指南-中文
十五.技术交流
公众号:橘入式技术交流