FreeRTOS 系统时钟节拍和时间管理
1 时钟节拍
时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳。中断之间的时间间隔取决于不同的应用,一般是 1ms – 100ms。时钟的节拍中断使得内核可以将任务延迟若干个时钟节拍,以及当任务等待事件发生时,提供等待超时等依据。时钟节拍率越快,系统的额外开销就越大。
FreeRTOS 的系统时钟节拍可以在配置文件 FreeRTOSConfig.h 里面设置:
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
如上所示的宏定义配置表示系统时钟节拍是 1KHz,即 1ms.
2 时间管理
1 时间延迟
FreeRTOS 中的时间延迟函数主要有以下两个作用:
◆ 为周期性执行的任务提供延迟。
◆ 对于抢占式调度器,让高优先级任务可以通过时间延迟函数释放 CPU 使用权,从而让低优先级任务可以得到执行
下面我们通过如下的框图来说明一下延迟函数对任务运行状态的影响

运行条件:
◆ 仅对任务 Task1 的运行状态做说明。
◆ 调度器支持时间片调度和抢占式调度。
运行过程描述如下:
◆ 起初任务 Task1 处于运行态,调用 vTaskDelay 函数后进入到阻塞状态.
◆ vTaskDelay 函数设置的延迟时间到,由于任务 Task1 不是当前就绪的最高优先级任务,所以不能进入到运行状态,只能进入到就绪状态,也就是 ready 状态。
◆ 一段时间后,调度器发现任务 Task1 是当前就绪的最高优先级任务,从而任务从就绪态切换到运行态。
◆ 由于时间片调度,任务 Task1 由运行态切换到就绪态。 上面就是一个简单的任务运行状态的切换过程。
2 FreeRTOS 的时间相关函数
FreeRTOS 时间相关的函数主要有以下 4 个:
◆ vTaskDelay ()
◆ vTaskDelayUntil ()
◆ xTaskGetTickCount()
◆ xTaskGetTickCountFromISR()
◆ 参数 xTicksToDelay 用于设置延迟的时钟节拍个数,范围 1- 0xFFFFFFFF。
延迟时间的最大值在 portmacro.h 文件里面有定义:
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t )0xffffffffUL
即延迟时间的范围是:1- 0xFFFFFFFF
xTaskGetTickCount 用于获取系统当前运行的时钟节拍数。
使用这个函数要注意以下问题:
1. 此函数用于在任务代码里面调用,如果在中断服务程序里面调用的话,需要使用函数 xTaskGetTickCountFromISR,这两个函数切不可混用
xTaskGetTickCountFromISR 用于获取系统当前运行的时钟节拍数。
使用这个函数要注意以下问题:
1. 此函数用于在中断服务程序里面调用,如果在任务里面调用的话,需要使用函数 xTaskGetTickCount, 这两个函数切不可混用。
函数 vTaskDelayUntil 用于周期性延迟。
◆ 第 1 个参数,存储任务上次处于非阻塞状态时刻的变量地址。
◆ 第 2 个参数,周期性延迟时间。
使用这个函数要注意以下问题:
1. 使用此函数需要在 FreeRTOSConfig.h 配置文件中配置如下宏定义为 1
#define INCLUDE_vTaskDelayUntil 1
函数 vTaskDelayUntil 实现的是周期性延迟,而函数 vTaskDelay 实现的是相对性延迟,反映到实际应用上有什么区别呢?
运行条件:
◆ 有一个 bsp 函数,这个函数处理时间大概耗时 2ms。
◆ 有两个任务,一个任务 Task1 是用的 vTaskDelay 延迟,延迟 10ms,另一个任务 Task2 是用的 vTaskDelayUntil 延迟,延迟 10ms。
◆ 不考虑任务被抢占而造成的影响
◆ Task1:
bsp+ vTaskDelay (10) ---> bsp + vTaskDelay (10)
|----2ms + 10ms 为一个周期------| |----2ms + 10ms 为一个周期----|
◆ Task2:
bsp + vTaskDelayUntil ---------> bsp + vTaskDelayUntil
|----10ms 为一个周期(2ms 包含在 10ms 内)---| |----10ms 为一个周期------|
使用:
用vTaskDelay实现vTaskDelayUntil():