目录
4.uxTaskPriorityGet(获取任意任务的优先级)
5.vTaskPrioritySet(设置任何任务的优先级)
8.xTaskResumeFromISR(在中断服务函数中恢复一个任务)
9.xTaskAbortDelay(强制任务离开阻塞状态,进入就绪状态)
任务控制(Task Control)
1.vTaskDelay(延迟相对时间)
void vTaskDelay( const TickType_t xTicksToDelay );
INCLUDE_vTaskDelay必须定义为1,该函数才可用。
在给定的时间间隔内延迟任务。任务保持阻塞的实际时间取决于tick rate。恒定的portTICK_PERIOD_MS可用于从tick rate计算实时时间——分辨率为一个tick period。
vTaskDelay()指定任务希望解除阻塞的时间,相对于vTaskDelay()被调用的时间。例如,指定100个节拍的阻塞周期将导致任务在调用vTaskDelay()后解除100个节拍的阻塞。因此,vTaskDelay()并不是一个控制周期性任务频率的好方法,因为通过代码的路径以及其他任务和中断活动将影响调用vTaskDelay()的频率,从而影响任务下一次执行的时间。请参阅vTaskDelayUntil()获取用于促进固定频率执行的替代API函数。它通过指定调用任务应该解除阻塞的绝对时间(而不是相对时间)来实现这一点。
参数:
xTicksToDelay | 调用任务应该阻塞的时间,以滴答周期为单位。 |
使用示例:
void vTaskFunction( void * pvParameters )
{
/* Block for 500ms. */
const TickType_t xDelay = 500 / portTICK_PERIOD_MS;
for( ;; )
{
/* Simply toggle the LED every 500ms, blocking between each toggle. */
vToggleLED();
vTaskDelay( xDelay );
}
}
2.vTaskDelayUntil(延迟绝对时间)
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime,
const TickType_t xTimeIncrement );
INCLUDE_vTaskDelayUntil必须定义为1,该函数才可用。
延迟任务到指定时间。周期性任务可使用此功能,保证任务的执行频率恒定。
此函数与vTaskDelay()在一个重要的方面不同:vTaskDelay()指定任务希望解除阻塞的时间,相对于vTaskDelay()被调用的时间,而vTaskDelayUntil()指定任务希望解除阻塞的绝对时间。
vTaskDelay()将导致从调用vTaskDelay()开始的指定时间间隔内任务阻塞。因此,很难单独使用vTaskDelay()来生成固定的执行频率,因为任务在调用vTaskDelay()后解除阻塞,而下一次调用vTaskDelay()的任务之间的时间可能不固定[任务可能在调用之间采用不同的代码路径,或者每次执行时可能被中断或抢占不同的次数]。
vTaskDelay()指定相对于调用函数的时间的唤醒时间,vTaskDelayUntil()指定希望解除阻塞的绝对(确切)时间。
应该注意的是,如果vTaskDelayUntil()用于指定一个已经是过去的唤醒时间,它将立即返回(不阻塞)。因此,使用vTaskDelayUntil()定期执行的任务如果由于任何原因(例如,任务被临时放置到Suspended状态)而导致任务错过一次或多次定期执行,则必须重新计算它所需的唤醒时间。这可以通过检查作为pxPreviousWakeTime参数通过引用传递的变量来检测当前的tick计数。然而,在大多数使用场景下,这并不是必需的。
恒定的portTICK_PERIOD_MS可用于从tick rate计算实时时间——分辨率为一个tick period。
当调用vTaskSuspendAll()暂停RTOS调度器时,这个函数不能被调用。
参数:
pxPreviousWakeTime | 指向一个变量的指针,该变量保存任务最后一次解除阻塞的时间。在第一次使用变量之前,必须用当前时间初始化变量(参见下面的示例)。接下来,变量将在vTaskDelayUntil()中自动更新。 |
xTimeIncrement | 周期时间段。该任务将在时间点(*pxPreviousWakeTime + xTimeIncrement)被解除阻塞。使用相同的xTimeIncrement参数值调用vTaskDelayUntil将导致任务以固定的间隔周期执行。 |
使用示例:
// 每10个节拍执行一个动作。
void vTaskFunction( void * pvParameters )
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
// 用当前时间初始化xLastWakeTime变量。
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
// 等待下一个周期。
vTaskDelayUntil( &xLastWakeTime, xFrequency );
// 执行动作。
}
}
3.xTaskDelayUntil(延迟绝对时间)
BaseType_t xTaskDelayUntil( TickType_t *pxPreviousWakeTime,
const TickType_t xTimeIncrement );
INCLUDE_xTaskDelayUntil必须定义为1,该函数才可用。
延迟任务到指定时间。周期性任务可使用此功能,保证任务的执行频率恒定。
此函数与vTaskDelay()在一个重要的方面不同:vTaskDelay()将导致任务从调用vTaskDelay()的时间开始阻塞指定的tick数,而xTaskDelayUntil()将导致任务从pxPreviousWakeTime参数中指定的时间开始阻塞指定的tick数。单独使用vTaskDelay()来生成固定的执行频率是很困难的,因为任务开始执行和任务调用vTaskDelay()之间的时间可能不是固定的[任务在调用之间可能采用不同的代码路径,或者每次执行时可能被中断或抢占不同的次数]。xTaskDelayUntil()可用于生成一个固定的执行频率。
vTaskDelay()指定了相对于函数调用时间的唤醒时间,而xTaskDelayUntil()指定了它希望解除阻塞的绝对(确切)时间。
宏pdMS_TO_TICKS()可用于计算以毫秒为单位指定的时间的滴答数,分辨率为一个滴答周期。
参数:
pxPreviousWakeTime | 指向一个变量的指针,该变量保存任务最后一次解除阻塞的时间。在第一次使用变量之前,必须用当前时间初始化变量(参见下面的示例)。接下来,变量将在xTaskDelayUntil()中自动更新。 |
xTimeIncrement | 周期时间段。该任务将在时间点(*pxPreviousWakeTime + xTimeIncrement)被解除阻塞。使用相同的xTimeIncrement参数值调用xTaskDelayUntil将导致任务以固定的间隔周期执行。 |
返回值:
一个值,可以用来检查任务是否真的被延迟了:如果是任务延迟了,pdTRUE,否则是pdFALSE。如果下一个预期唤醒时间已经过去,任务不会被延迟。
使用示例:
// 每10个节拍执行一个动作
void vTaskFunction( void * pvParameters )
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
BaseType_t xWasDelayed;
// 用当前时间初始化xLastWakeTime变量。
xLastWakeTime = xTaskGetTickCount ();
for( ;; )
{
// 等待下一个周期。
xWasDelayed = xTaskDelayUntil( &xLastWakeTime, xFrequency );
// 执行动作。如果这里的代码花费的时间太长,xWasDelayed值可以用来确定是否错过了最后期限。
}
}
4.uxTaskPriorityGet(获取任意任务的优先级)
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );
INCLUDE_uxTaskPriorityGet必须定义为1,该函数才可用。
获取任意任务的优先级。
参数:
xTask | 待查询任务的句柄。传递NULL句柄会导致返回调用任务的优先级。 |
返回值:
xTask的优先级。
使用示例:
void vAFunction( void )
{
TaskHandle_t xHandle;
// 创建一个任务,存储该句柄。
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
// 使用句柄获取已创建任务的优先级。
// 它是用tskIDLE_PRIORITY创建的,但是可能已经改变了它本身
if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
{
// 任务已经改变了优先级。
}
// ...
// vTaskCode的优先级比vAFunction优先级高吗?
if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
{
// vAFunction的优先级(使用NULL句柄获得)更高。
}
}
5.vTaskPrioritySet(设置任何任务的优先级)
void vTaskPrioritySet( TaskHandle_t xTask,
UBaseType_t uxNewPriority );
INCLUDE_vTaskPrioritySet必须定义为1,该函数才可用。
设置任何任务的优先级。
如果设置的优先级高于当前正在执行的任务,则在函数返回之前将发生上下文切换。
参数:
xTask | 正在设置优先级的任务的句柄。NULL句柄设置调用任务的优先级。 |
uxNewPriority | 任务将被设置的优先级。断言优先级小于configMAX_PRIORITIES。如果configASSERT未定义,则优先级被静默地限制为(configMAX_PRIORITIES - 1)。 |
使用示例:
void vAFunction( void )
{
TaskHandle_t xHandle;
// 创建一个任务,存储该句柄。
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
// 使用句柄提升已创建任务的优先级。
vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 )
// ...
// 使用NULL句柄将vAFunction优先级提高到相同的值。
vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
}
6.vTaskSuspend(暂停任何任务)
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
INCLUDE_vTaskSuspend必须定义为1,该函数才可用。
暂停任何任务。当一个任务被挂起时,无论它的优先级是什么,它都不会得到任何微控制器的处理时间。
对vTaskSuspend的调用不是累计的——即在同一个任务上调用两次vTaskSuspend()仍然只需要调用一次vTaskResume()来准备被挂起的任务。
参数:
xTaskToSuspend | 被挂起任务的句柄。传递NULL句柄会导致调用任务被挂起。 |
使用示例:
void vAFunction( void )
{
TaskHandle_t xHandle;
// 创建一个任务,存储该句柄。
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
// 使用句柄暂停已创建的任务。
vTaskSuspend( xHandle );
// ...
// 创建的任务在此期间不会运行,除非另一个任务调用vTaskResume(xHandle)。
//...
// 暂停vAFunction本身
vTaskSuspend( NULL );
// 除非另一个任务用vAFunction的句柄作为参数调用vTaskResume,否则我们无法到达这里。
}
7.vTaskResume(恢复挂起的任务)
void vTaskResume( TaskHandle_t xTaskToResume );
INCLUDE_vTaskSuspend必须定义为1,该函数才可用。
恢复挂起的任务。
被一次或多次调用vTaskSuspend()挂起的任务将通过一次调用vTaskResume()重新运行。
参数:
xTaskToResume | 已就绪的任务的句柄 |
使用示例:
void vAFunction( void )
{
TaskHandle_t xHandle;
// 创建一个任务,存储该句柄。
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
// 使用句柄暂停已创建的任务。
vTaskSuspend( xHandle );
// ...
// 创建的任务在此期间不会运行,除非另一个任务调用vTaskResume(xHandle)。
//...
// 自己恢复挂起的任务。
vTaskResume( xHandle );
// 创建的任务将再次根据其在系统中的优先级获得微控制器处理时间。
}
8.xTaskResumeFromISR(在中断服务函数中恢复一个任务)
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );
INCLUDE_vTaskSuspend和INCLUDE_xTaskResumeFromISR必须定义为1,该函数才可用。
一个函数,用来恢复可以从ISR内部调用的挂起的任务。
一个被多个vTaskSuspend()调用挂起的任务将通过调用xTaskResumeFromISR()重新运行。
xTaskResumeFromISR()通常被认为是一个危险的函数,因为它的操作没有锁存。由于这个原因,如果中断有可能在任务挂起之前到达,从而丢失中断,那么肯定不应该使用它来同步任务和中断。使用信号量(最好是直接通知任务)可以避免这种情况的发生。使用示例提供了一个使用直接到任务通知的工作示例。
参数:
xTaskToResume | 已就绪的任务句柄 |
返回值:
如果恢复任务会导致上下文切换,则为pdTRUE,否则为pdFALSE。这被ISR用来确定是否需要在ISR之后进行上下文切换。
使用示例:
TaskHandle_t xHandle;
void vAFunction( void )
{
// 创建一个任务,存储该句柄。
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ... 剩下的代码.
}
void vTaskCode( void *pvParameters )
{
for( ;; )
{
// ... 在这里执行一些函数
// 任务挂起。
vTaskSuspend( NULL );
// 任务现在被暂停,所以直到ISR恢复它才会到达这里
}
}
void vAnExampleISR( void )
{
BaseType_t xYieldRequired;
// 恢复挂起的任务
xYieldRequired = xTaskResumeFromISR( xHandle );
// 我们应该切换上下文,使ISR返回到不同的任务。
// 注意:这取决于您所使用的端口。查看您的端口的文档和示例。
portYIELD_FROM_ISR( xYieldRequired );
}
9.xTaskAbortDelay(强制任务离开阻塞状态,进入就绪状态)
BaseType_t xTaskAbortDelay( TaskHandle_t xTask );
强制任务离开阻塞状态,进入就绪状态,即使任务处于要等待的阻塞状态的事件没有发生,并且任何指定的超时还没有过期。
INCLUDE_xTaskAbortDelay必须定义为1,该函数才可用。
参数:
xTask | 将被强制退出阻塞状态的任务句柄。 |
返回值:
如果xTask引用的任务不在阻塞状态,则返回pdFAIL。否则返回pdPASS。