STM32F1+HAL库+FreeTOTS学习11——延时函数API
STM32F1+HAL库+FreeTOTS学习11——延时函数API
- 延时函数API
- 1. vTaskDelay()
- 2. vTaskDelayUntil()
- 3. xTaskDelayUntil()
- 相对延时和绝对延时的区别
- 4. xTaskAbortDelay()
上一期,我们学习了任务相关API使用,这一期我们开始学习FreeRTOS延时函数的API使用
延时函数API
在FreeRTOS官方提供的技术文档中,一共提供了三种延时的函数,他们的功能都只有一种:延时,但是又存在一定的差异,让我们来看一下:
1. vTaskDelay()
函数 vTaskDelay()用于对任务进行延时,延时的时间单位为系统时钟节拍,使用此函数,需要将宏 INCLUDE_vTaskDelay 配置为 1。其函数原型如下:
/**
* @brief vTaskDelay
* @param xTicksToDelay : 需要延时的时间,延时单位为系统节拍
* @retval 无
*/
void vTaskDelay( const TickType_t xTicksToDelay );
//使用示例如下:
/**
* @brief task2
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task1(void *pvParameters)
{
while(1)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
/* LED0闪烁 */
vTaskDelay(500); /* 延时1000ticks */
}
}
需要注意以下两点
- vTaskDelay延时的单位是系统节拍,具体长度由宏 configTICK_RATE_HZ 决定,在FreeRTOS默认的源码里面,该值为1000 HZ,那么一个系统节拍对应的时间就是1/1000s = 1ms ,500个系统节拍就是500ms。
- vTaskDelay函数的延时时间,是从调用该函数开始的,由于vTaskDelay前面的代码运行时间不确定,所以实际上下一次运行任务1的时间并不是准确的500ms,只能是大概500ms。
2. vTaskDelayUntil()
函数vTaskDelayUntil()用于以一个绝对的时间阻塞任务,适用于需要按照一定频率运行的任务,函数vTaskDelayUntil()实际上是一个宏,在task.h文件中有定义,具体的代码如下所示:
#define vTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ) \
{ \
( void ) xTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ); \
}
通过观察代码,我们发现vTaskDelayUntil内部是直接调用了 xTaskDelayUntil() 函数,所以我们直接来介绍xTaskDelayUntil() 函数
3. xTaskDelayUntil()
和vTaskDelayUntil() 函数相同,xTaskDelayUntil()也是用于一个绝对的时间阻塞任务,适用于需要按照一定频率运行的任务,其函数原型如下:
/**
* @brief xTaskDelayUntil
* @param pxPreviousWakeTime: 用于记录上一次任务解除阻塞的系统节拍数(系统时间),改变量首次使用前必须初始化,
* 后续会在xTaskDelayUntil()中自动更新。
* @param xTimeIncrement : 周期时间段。任务将在 (*pxPreviousWakeTime + xTimeIncrement) 时间取消阻塞。
* 使用 相同的 xTimeIncrement 参数值调用 xTaskDelayUntil 将导致任务以固定的间隔周期执行 。
* @retval 返回值为pdTRUE表示任务实际延时,如果为pdFALSE表示下一个预计唤醒的时间已过,无法执行延时,任务将不延时。
*/
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement );
//使用示例如下:
/**
* @brief task2
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task2(void *pvParameters)
{
TickType_t xLastWakeTime; /*定义上一次解除阻塞的时间*/
const TickType_t xFrequency = 500; /*定义周期时间段*/
BaseType_t xWasDelayed;
xLastWakeTime = xTaskGetTickCount ();
while(1)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); /* LED0闪烁 */
xWasDelayed = xTaskDelayUntil(&xLastWakeTime,xFrequency);
}
}
相对延时和绝对延时的区别
- vTaskDelay() 函数是相对延时,指每次延时都是从执行函数vTaskDelay()开始,直到延时指定的时间结束。在这个过程中,如果vTaskDelay() 函数前面的内容执行了一段时间(我们这里举个栗子:50ms) ,并且我们通过vTaskDelay() 函数延时了500个系统节拍,那么这个任务实际运行的间隔就是550ms。
- vTaskDelayUntil() 和 xTaskDelayUntil() 函数是绝对延时,指将整个任务的运行周期看成一个整体,适用于需要按照一定频率运行的任务,比如我们这里使用xTaskDelayUntil()函数延时500ms,那么整个任务的运行间隔就是500ms(前提是任务里面的代码整体运行实际不能超过500ms)。
下面我简单的看一段代码,深入了解以下:
void task1(void *pvParameters)
{
while(1)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_0); /* LED0闪烁 */
HAL_Delay(250); /*强制延时250ms,模拟代码运行*/
/*在freeRTSO的任务里面本不应该出现整个延时函数*/
/*这里出现时为了做演示,让效果更明显*/
vTaskDelay(500); /* 延时500没事、*/
}
}
/**
* @brief task2
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task2(void *pvParameters)
{
TickType_t xLastWakeTime; /*定义上一次解除阻塞的时间*/
const TickType_t xFrequency = 500; /*定义周期时间段*/
BaseType_t xWasDelayed;
xLastWakeTime = xTaskGetTickCount ();
while(1)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1); /* LED0闪烁 */
HAL_Delay(250); /*强制延时250ms,模拟代码运行*/
/*在freeRTSO的任务里面本不应该出现整个延时函数*/
/*这里出现时为了做演示,让效果更明显*/
xWasDelayed = xTaskDelayUntil(&xLastWakeTime,xFrequency); /*绝对延时500ms*/
}
}
- 在任务1当中,我们先调用HAL_Delay() 进行强制延时,模拟代码正在运行,如何调用vTaskDelay(500)执行了时长为500ms的相对延时,那么任务1的执行周期应该就是750ms
- 在任务2当中,我们先调用HAL_Delay() 进行强制延时,模拟代码正在运行,如何调用xTaskDelayUntil(500)执行了时长为500ms的绝对延时,那么任务1的执行周期应该就是500ms
以上是我们分析得到的,下面我们来看一下实际情况:
和理论一致,没有问题!
4. xTaskAbortDelay()
函数 xTaskAbortDelay()用于终止处于阻塞态任务的阻塞,此函数在 task.c 文件中有定义。函数原型如下:
/**
* @brief xTaskAbortDelay
* @param xTask : 将被强制退出阻塞状态的任务的句柄。
* @retval 如果 xTask 引用的任务不在“阻塞”状态,则返回 pdFAIL。否则返回 pdPASS。
*/
BaseType_t xTaskAbortDelay( TaskHandle_t xTask );