本文目标:学习与使用FreeRTOS中的延迟函数,主要是学习两个函数的使用。
按照本文的描述,应该可以跑通实验并举一反三。
本文实验条件:拥有C语言基础,装有编译和集成的开发环境,比如:Keil uVision5
在freertos中的时间延迟有两个:vTaskDelayUntil和vTaskDelay,区别如下:
vTaskDelay是相对延时函数,它指定的是从调用该函数后开始计算的延时时间,单位是系统节拍时钟周期。这个函数适合需要固定时间间隔的延时操作,但是它可能受到其他任务和中断的影响,导致下一次执行的时间不准确。
vTaskDelayUntil是绝对延时函数,它指定的是一个绝对的唤醒时间,单位也是系统节拍时钟周期。这个函数适合实现周期性的延时操作,它可以保证任务以固定的频率执行,不受其他因素的干扰。但是如果指定的唤醒时间已经过去,那么该函数会立即返回,不会有延时效果。
void vTaskDelay( const TickType_t xTicksToDelay );
函数描述:
函数 vTaskDelay 用于任务的延迟。
参数 xTicksToDelay 用于设置延迟的时钟节拍个数,范围 1- 0xFFFFFFFF。延迟时间的最大值在portmacro.h 文件里面有定义:
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t )0xffffffffUL
即延迟时间的范围是:1- 0xFFFFFFFF
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime,
const TickType_t xTimeIncrement );
函数描述:
函数 vTaskDelayUntil 用于周期性延迟。
第 1 个参数,存储任务上次处于非阻塞状态时刻的变量地址。
第 2 个参数,周期性延迟时间。
使用这个函数要注意的点:
使用此函数需要在 FreeRTOSConfig.h 配置文件中配置如下宏定义为 1
#define INCLUDE_vTaskDelayUntil 1
这个两个的函数使用举例可以看我下面的代码片段
void PrintTask(void *params)
{
struct TaskPrintInfo *pInfo = params;
uint32_t cnt = 0;
OLED_Init();
TickType_t ticks;
BaseType_t preTime;
uint64_t t1, t2;
preTime = xTaskGetTickCount();
while (1)
{
/* 打印信息 */
if (g_LCDCanUse)
{
g_LCDCanUse = 0;
OLED_ShowString(pInfo->x,pInfo->y,pInfo->name,16);
OLED_ShowNum((pInfo->x + 8 * 6),pInfo->y,cnt++,4,16);
g_LCDCanUse = 1;
mdelay(cnt & 0x07); // 简单限制 模拟干一些活 使得运行PrintTask这个函数有不一样的时长
}
t1 = system_get_ns();
ticks = 500 / portTICK_PERIOD_MS;
vTaskDelayUntil(&preTime, ticks); // 绝对延迟 打印出来的时间差是跟下面的时间差有区别
// vTaskDelay(ticks); // 相对延迟函数 会进行Block
t2 = system_get_ns();
OLED_ShowNum((pInfo->x + 8),pInfo->y + 16,t2-t1,9,16);
OLED_Refresh();
}
}
xTaskCreate(PrintTask, "task1", 128, &g_Task1Info, osPriorityNormal, NULL);
static struct TaskPrintInfo g_Task1Info = {0, 0, "Task1"};
下载代码到板子上,使用vTaskDelay的相对延迟函数时,我显示的时间差始终是稳定的,我使用vTaskDelayUntil的绝对延迟时,我显示的时间差就有部分变化。