Software Timer Management
[[FreeRTOS_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf#page=174&selection=7,0,7,25|FreeRTOS_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide, page 174]]
5.3 xTimerCreate()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=259&selection=2,0,4,14|FreeRTOS_Reference_Manual_V10.0.0, page 259]]
Deamon (Time Service) Task,通过定时器命令队列,对定时器任务发送命令,然后定时器任务调用相应的任务程序,执行软件定时器回调函数。所以对于软件定时器来说:
configTIMER_TASK_STACK_DEPTH)和软件的设置,可以有很多软件定时器。xTimerCreate()#include "FreeRTOS.h"
#include "timers.h"
TimerHandle_t xTimerCreate( const char *pcTimerName,
const TickType_t xTimerPeriod,
const UBaseType_t uxAutoReload,
void *const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
函数说明:
xTimerCreateStatic()创建了软件定时器,那么软件定时器所用内存则有程序员所确定。xTimerStart()xTimerStartFromISR()xTimerResetFromISR()xTimerChangePeriod()xTimerChangePeriodFromISR()参数:
pcTimerName:分配给定时器的纯文本名称,纯粹是为了调试。xTimerPeriod:定时器周期。
pdMS_TO_TICKS()宏可以把以毫秒为单位的时间转换为以刻度为单位的时间。xNewPriod可以直接设置为 100。xNewPeriod可以设置为pdMS_TO_TICKS(500),假设configTICK_RATE_HZ小于等于 1000。uxAutoReload:
pdTRUE来定义一个自动重启的定时器。
xTimerPeriod反复到期。pdFALSE来定义一个不自动重启的定时器。
pvTimerID:分配给定时器的标识符。
vTimerSetTimer()函数更新。pxCallbackFunction:定时器过期后调用的回调函数。回调函数必须有被定义的原型。回调函数的返回值必须是void,它的输入参数必须是一个TimerHandle。
void vCallbackFunctionExample( TimerHandle_t xTimer );
返回值:
NULL:软件定时器因为堆中没有足够的内存而无法被创建。Any other value: 软件定时器成功创建,并且返回一个可以引用此定时器的句柄。xTimerStart()#include "FreeRTOS.h"
#include "timers.h"
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
函数说明:
xTimerStartFromISR()是一个等效函数,它可以在 中断 中启动定时器。xTimerStart()时的到期时间。xTimerStart()后的'n'个刻度后被调用,其中'n'是计时器的定义周期。参数:
xTimer:计时器将被重置(reset)、启动(started)或者重启(restarted)。xTicksToWait:计时器函数并非由 FreeRTOS 的核心函数提供,而是由定时器服务( or deamon )提供。FreeRTOS API 发送命令到定时器任务的队列,如果队列已满,xTicksToWait指定任务处于阻塞状态的最长时间,以等待计时器命令上的队列空间可用,设置为portMAX_DELAY为等待无限多的时间。返回值:
pdPASS:成功启动定时器。pdFAIL:因为定时器任务的消息队列已满,消息未能在超时时间之内发送到时间定时器的队列。#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
void vCallbackFunction(TimerHandle_t timer1)
{
printf("[TIMER_1 CALLBACK]: One shot timer.\n");
}
void app_main(void)
{
// 创建一个定时器,定时器名字"Timer 1",周期1s,周期结束之后重新启动,定时器标识符为0,定时器回调函数为 vCallbackFunction
TimerHandle_t xTimer1 = xTimerCreate("Timer 1", pdMS_TO_TICKS(1000), pdTRUE, 0, vCallbackFunction);
// 启动定时器,等待时间为无限
xTimerStart(xTimer1, portMAX_DELAY);
}

根据输出可以观察到定时器(xTimer1)的回调函数在不断被调用。
xTimerStop()#include "FreeRTOS.h"
#include "timers.h"
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
函数说明:
xTimerStopISR()的一个等效函数,可以在中断中使用。参数:
xTimer:定时器句柄。xTicksToWait:超时等待时长。返回值:
pdPASS:成功停止定时器。pdFAIL:未能成功停止定时器,因为定时器守护任务的消息队列已满。#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
void vCallbackFunction(TimerHandle_t timer1)
{
printf("[TIMER_1 CALLBACK]: In timer.\n");
}
void app_main(void)
{
// 创建一个定时器,定时器名字"Timer 1",周期1s,周期结束之后重新启动,定时器标识符为0,定时器回调函数为 vCallbackFunction
TimerHandle_t xTimer1 = xTimerCreate("Timer 1", pdMS_TO_TICKS(1000), pdTRUE, 0, vCallbackFunction);
xTimerStart(xTimer1, portMAX_DELAY);
for (int delay = 5; delay > 0; delay--) {
printf("[MAIN]: The timer will stoped in %d second(s).\n", delay);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
xTimerStop(xTimer1, portMAX_DELAY);
}

定时器在设定for循环结束之后停止。
271 5.1 pcTimerGetName()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=271&selection=0,3,4,16|FreeRTOS_Reference_Manual_V10.0.0, page 271]]
pcTimerGetName()#include "FreeRTOS.h"
#include "timer.h"
const char *pcTimerGetName( TimerHandle_t xTimer );
函数说明:
参数:
xTimer:将要取得定时器名字的句柄。返回值:
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
void vCallbackFunction(TimerHandle_t timer1)
{
const char *timer_name = pcTimerGetName(timer1);
printf("[TIMER_1 CALLBACK]: In timer \"%s\".\n", timer_name);
}
void app_main(void)
{
// 创建一个定时器,定时器名字"Timer 1",周期1s,周期结束之后重新启动,定时器标识符为0,定时器回调函数为 vCallbackFunction
TimerHandle_t xTimer1 = xTimerCreate("Timer 1", pdMS_TO_TICKS(1000), pdTRUE, 0, vCallbackFunction);
xTimerStart(xTimer1, portMAX_DELAY);
for (int delay = 5; delay > 0; delay--) {
printf("[MAIN]: The timer will stoped in %d second(s).\n", delay);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
//
const char *timer_name = pcTimerGetName(xTimer1);
printf("[MAIN]: The timer \"%s\" will stop.\n", timer_name);
xTimerStop(xTimer1, portMAX_DELAY);
}
在实际编写程序时,可以根据定时器名字的不同,来让程序执行不同的代码。
pvGetTimerGetTimerID()#include "FreeRTOS.h"
#include "timer.h"
void *pvTimerGetTimerID( TimerHandle_t xTimer );
函数说明:
参数:
返回值:
(void *):时间定时器的ID。此处可以用
uint32_t强制转换函数返回值,并用uint32_t来接收返回值。
Name和ID:#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
void callback_function(TimerHandle_t timer)
{
// 获取定时器名字
const char *timer_name = pcTimerGetName(timer);
// 获取定时器ID
uint32_t timer_id = (uint32_t)pvTimerGetTimerID(timer);
printf("[CALLBACK FUNCTION]: In timer \"%s\", ID: %ld\n", timer_name, timer_id);
}
void app_main(void)
{
TimerHandle_t timer1 = xTimerCreate("Timer 1", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, callback_function);
TimerHandle_t timer2 = xTimerCreate("Timer 2", pdMS_TO_TICKS(1000), pdTRUE, (void *)1, callback_function);
const char *timer_name = NULL;
xTimerStart(timer1, portMAX_DELAY);
timer_name = pcTimerGetName(timer1);
for (int delay = 5; delay > 0; delay--) {
printf("[MAIN]: Timer \"%s\" will stop in %d second(s).\n", timer_name, delay);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
xTimerStop(timer1, portMAX_DELAY);
xTimerStart(timer2, portMAX_DELAY);
timer_name = pcTimerGetName(timer2);
for (int delay = 5; delay > 0; delay--) {
printf("[MAIN]: Timer \"%s\" will stop in %d second(s).\n", timer_name, delay);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
xTimerStop(timer2, portMAX_DELAY);
}
![[14. 软件定时器(Software Timer)-20240615182443875.webp|1000]]
Timer 1 和 Timer 2 分别启动运行停止,因为时间定时器调用了相同的回调函数,所以回调函数打印出了不同的时间定时器名称和ID。
xTimerReset()#include "FreeRTOS.h"
#include "timer.h"
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );
函数说明:
xTimerResetISR()可以用。参数:
xTimer:时间定时器句柄。xTicksToWait:超时等待时间。返回值:
pdPASS:重启时间定时器成功。pdFAIL:重启时间定时器失败。xTimerChangePeriod()#include "FreeRTOS.h"
#include "timer.h"
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, TickType_t xNewPeriod, TickType_t xTicksToWait );
函数说明:
xTimerChangePeriodISR()可以用。参数:
xTimer:需要改变定时器周期的定时器句柄。xNewPeriod:新的周期。xTicksToWait:超时等待时间。返回值:
pdPASS:定时器周期成功修改。pdFAIL:定时器周期修改失败。#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
void callback_function(TimerHandle_t timer)
{
const char *timer_name = pcTimerGetName(timer);
uint32_t *timer_id = (uint32_t *)pvTimerGetTimerID(timer);
printf("[CALLBACK FUNCTION]: In timer \"%s\", ID: %ld\n", timer_name, *timer_id);
}
void app_main(void)
{
static uint32_t timer1_id = 1;
TimerHandle_t timer1 = xTimerCreate("Timer 1", pdMS_TO_TICKS(1000), pdTRUE, (void *)&timer1_id, callback_function);
xTimerStart(timer1, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(5000)); // 让 timer1 运行 5s
xTimerChangePeriod(timer1, pdMS_TO_TICKS(500), portMAX_DELAY); // 改变定时器周期
vTaskDelay(pdMS_TO_TICKS(5000)); // 再让 timer1 运行 5s
xTimerStop(timer1, portMAX_DELAY);
}