vTaskDelayUntil()类似于vTaskDelay()。
可以用于实现一个固定执行周期的需求。由于调用此函数的任务解除阻塞的时间是绝对时刻,比起相对于
调用时刻的相对时间更精确(即比调用vTaskDelay()可以实现更精确的周期性)。
void vTaskDelayUntil( portTickType * pxPreviousWakeTime, portTickType xTimeIncrement );
pxPreviousWakeTime : 这个参数保存了任务上一次离开阻塞态的时刻。这个时刻被用作一个参考点来计算
该任务下一次离开阻塞态的时刻。调用的过程中自动更新,应用程序除了该变量第一次初始化外,通常都不需要修改它的值。
xTimeIncrement : 单位是心跳周期,可以使用常量portTICK_RATE_MS 将毫秒转换为心跳周期。
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
portTickType xLastWakeTime;
pcTaskName = ( char * ) pvParameters;
//唯一一次被显式赋值,之后将自动更新
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
vPrintString( pcTaskName );
vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) );
}
}
合并阻塞和非阻塞任务
空闲任务与空闲任务钩子函数
为了保证这
一点,当调用vTaskStartScheduler()时,调度器会自动创建一个空闲任务。
通常空闲任务钩子函数被用于:
1、执行低优先级,后台或需要不停处理的功能代码。
2、测试处系统处理裕量
3、将处理器配置到低功耗模式——提供一种自动省电方法,使得在没有任何应用功能
需要处理的时候,系统自动进入省电模式。
空闲任务钩子函数必须遵从以下规则
1、绝不能阻或挂起
2、如果应用程序用到了vTaskDelete() AP 函数,则空闲钩子函数必须能够尽快返回。
空闲任务钩子函数必须具有
void vApplicationIdleHook( void );
FreeRTOSConfig.h 中的配置常量configUSE_IDLE_HOOK 必须定义为1,这样空
闲任务钩子函数才会被调用。
1.8 改变任务优先级
vTaskPrioritySet() 可以用于在调度启动后改变任何任务的优先级。
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
pxTask 被修改优先级的任务句柄
uxNewPriority 目标任务将被设置到哪个优先级上。
uxTaskPriorityGet() API 函数用于查询一个任务的优先级。
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
pxTask 被查询任务的句柄(目标任务)
返回值 被查询任务的当前优先级。
1.9 删除任务
任务可以使用API 函数vTaskDelete()删除自己或其它任务。
任务被删除后就不复存在,也不会再进入运行态。
空闲任务的责任是要将分配给已删除任务的内存释放掉。因此有一点很重要,那就
是使用vTaskDelete() API 函数的任务千万不能把空闲任务的执行时间饿死。
1.10 调度算法
调度器总是在所有处于就绪态的任务中选择具有最高优先级的任务来执行。
队列管理
基于FreeRTOS 的应用程序由一组独立的任务构成——每个任务都是具有独立权
限的小程序。这些独立的任务之间很可能会通过相互通信以提供有用的系统功能。
FreeRTOS 中所有的通信与同步机制都是基于队列实现的。
2.2 队列的特性
数据存储
在队列创建时需要设定其深度和每个单元的大小。通常情况下,队列被作为FIFO(先进先出)使用
往队列写入数据是通过字节拷贝把数据复制存储到队列中;从队列读出数据使得把
队列中的数据拷贝删除。
读队列时阻塞
由于队列可以被多个任务读取,所以对单个队列而言,也可能有多个任务处于阻塞
状态以等待队列数据有效。这种情况下,一旦队列数据有效,只会有一个任务会被解除
阻塞,这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级
相同,那么被解除阻塞的任务将是等待最久的任务。
写队列时阻塞
同读队列一样,任务也可以在写队列时指定一个阻塞超时时间。这个时间是当被写
队列已满时,任务进入阻塞态以等待队列空间有效的最长时间。
2.3 队列的使用
xQueueCreate()用于创建一个队
列,并返回一个xQueueHandle 句柄以便于对其创建的队列进行引用。
如果内存堆中没有足够的空间来创建队列,
xQueueCreate()将返回NULL。
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize );
uxQueueLength 队列能够存储的最大单元数目,即队列深度。
uxItemSize 队列中数据单元的长度,以字节为单位。
xQueueSendToBack() 用于将数据发送到队列尾
xQueueSendToFront() 用于将数据发送到队列首。
xQueueSend()完全等同于xQueueSendToBack()。
但切记不要在中断服务例程中调用xQueueSendToFront() 或
xQueueSendToBack()。
可以用于实现一个固定执行周期的需求。由于调用此函数的任务解除阻塞的时间是绝对时刻,比起相对于
调用时刻的相对时间更精确(即比调用vTaskDelay()可以实现更精确的周期性)。
void vTaskDelayUntil( portTickType * pxPreviousWakeTime, portTickType xTimeIncrement );
pxPreviousWakeTime : 这个参数保存了任务上一次离开阻塞态的时刻。这个时刻被用作一个参考点来计算
该任务下一次离开阻塞态的时刻。调用的过程中自动更新,应用程序除了该变量第一次初始化外,通常都不需要修改它的值。
xTimeIncrement : 单位是心跳周期,可以使用常量portTICK_RATE_MS 将毫秒转换为心跳周期。
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
portTickType xLastWakeTime;
pcTaskName = ( char * ) pvParameters;
//唯一一次被显式赋值,之后将自动更新
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
vPrintString( pcTaskName );
vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) );
}
}
合并阻塞和非阻塞任务
空闲任务与空闲任务钩子函数
为了保证这
一点,当调用vTaskStartScheduler()时,调度器会自动创建一个空闲任务。
通常空闲任务钩子函数被用于:
1、执行低优先级,后台或需要不停处理的功能代码。
2、测试处系统处理裕量
3、将处理器配置到低功耗模式——提供一种自动省电方法,使得在没有任何应用功能
需要处理的时候,系统自动进入省电模式。
空闲任务钩子函数必须遵从以下规则
1、绝不能阻或挂起
2、如果应用程序用到了vTaskDelete() AP 函数,则空闲钩子函数必须能够尽快返回。
空闲任务钩子函数必须具有
void vApplicationIdleHook( void );
FreeRTOSConfig.h 中的配置常量configUSE_IDLE_HOOK 必须定义为1,这样空
闲任务钩子函数才会被调用。
1.8 改变任务优先级
vTaskPrioritySet() 可以用于在调度启动后改变任何任务的优先级。
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
pxTask 被修改优先级的任务句柄
uxNewPriority 目标任务将被设置到哪个优先级上。
uxTaskPriorityGet() API 函数用于查询一个任务的优先级。
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
pxTask 被查询任务的句柄(目标任务)
返回值 被查询任务的当前优先级。
1.9 删除任务
任务可以使用API 函数vTaskDelete()删除自己或其它任务。
任务被删除后就不复存在,也不会再进入运行态。
空闲任务的责任是要将分配给已删除任务的内存释放掉。因此有一点很重要,那就
是使用vTaskDelete() API 函数的任务千万不能把空闲任务的执行时间饿死。
1.10 调度算法
调度器总是在所有处于就绪态的任务中选择具有最高优先级的任务来执行。
队列管理
基于FreeRTOS 的应用程序由一组独立的任务构成——每个任务都是具有独立权
限的小程序。这些独立的任务之间很可能会通过相互通信以提供有用的系统功能。
FreeRTOS 中所有的通信与同步机制都是基于队列实现的。
2.2 队列的特性
数据存储
在队列创建时需要设定其深度和每个单元的大小。通常情况下,队列被作为FIFO(先进先出)使用
往队列写入数据是通过字节拷贝把数据复制存储到队列中;从队列读出数据使得把
队列中的数据拷贝删除。
读队列时阻塞
由于队列可以被多个任务读取,所以对单个队列而言,也可能有多个任务处于阻塞
状态以等待队列数据有效。这种情况下,一旦队列数据有效,只会有一个任务会被解除
阻塞,这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级
相同,那么被解除阻塞的任务将是等待最久的任务。
写队列时阻塞
同读队列一样,任务也可以在写队列时指定一个阻塞超时时间。这个时间是当被写
队列已满时,任务进入阻塞态以等待队列空间有效的最长时间。
2.3 队列的使用
xQueueCreate()用于创建一个队
列,并返回一个xQueueHandle 句柄以便于对其创建的队列进行引用。
如果内存堆中没有足够的空间来创建队列,
xQueueCreate()将返回NULL。
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize );
uxQueueLength 队列能够存储的最大单元数目,即队列深度。
uxItemSize 队列中数据单元的长度,以字节为单位。
xQueueSendToBack() 用于将数据发送到队列尾
xQueueSendToFront() 用于将数据发送到队列首。
xQueueSend()完全等同于xQueueSendToBack()。
但切记不要在中断服务例程中调用xQueueSendToFront() 或
xQueueSendToBack()。