软件定时器
9.1 软件定时器特性¶
9.1.1 软硬件定时器¶
硬件定时器:
- 芯片本身自带的定时器模块,硬件定时器的精度一般很高,每次在定时时间到达之后就会自动触发一个中断,用户在中断服务函数中处理信息。
软件定时器:
- 是指具有定时功能的软件,可设置定时周期,当指定时间到达后要调用回调函数(也称超时函数),用户在回调函数中处理信息。
9.1.2 软件定时器特性¶
软件定时器可以设置为 单次定时器 和 周期定时器 :
- 单次定时器,即当指定时间到达后只调用一次超时函数,之后软件定时器不再工作,但 可以被手动重新开启 。
- 周期定时器,即会周期性的循环调用超时函数。
如下图所示:
软件定时器有两种状态, 休眠态 和 运行态 :
- 休眠态,即软件定时器可以通过其句柄被引用,但因为没有运行,所以其定时超时回调函数不会被执行。
- 运行态,运行态的定时器,当指定时间到达之后,它的超时回调函数会被调用。
单次定时器状态转换图:
周期定时器状态转换图:
9.1.3 软件定时器的使用¶
- 如果要使能软件定时器,需在
FreeRTOSConfig.h
文件中将configUSE_TIMERS
配置成 1 。 - 软件定时器以Tick为基准,但软件定时器的超时回调函数是由 软件定时器服务任务 调用的。
- 在开启任务调度器时,软件定时器服务任务
prvTimerTask()
与空闲任务一起被创建。 - 软件定时器服务任务的作用:
- 负责软件定时器超时的逻辑判断
- 调用超时软件定时器的超时回调函数
- 处理软件定时器命令队列
- 软件定时器服务任务的优先级默认配置为
configTIMER_TASK_PRIORITY
= 31 。 - 用户通过命令队列与软件定时器服务任务交互,命令队列长度默认配置为
configTIMER_QUEUE_LENGTH
= 5 。 - 定时器的超时时间是基于调用
xTimerStart()
的时刻,xTimerStart()
只是把开启定时器命令发给"定时器命令队列",至于服务任务能否马上执行,取决于它的优先级。
用户调用FreeRTOS的软件定时器相关的 API 函数,API 函数往软件定时器命令队列中写消息,实现用户与定时器服务任务的交互:
9.1.4 回调函数¶
函数原型:
定时器的回调函数是在守护任务中被调用的,守护任务不是专为某个定时器服务的,它还要处理其他定时器。
所以,定时器的回调函数不要影响其他人:
- 回调函数要尽快实行,不能进入阻塞状态。
- 不要调用会导致阻塞的API函数,比如 vTaskDelay() 。
- 可以调用 xQueueReceive() 之类的函数,但是超时时间要设为0:即刻返回,不可阻塞。
9.2 软件定时器函数¶
9.2.1 创建定时器¶
C
TimerHandle_t xTimerCreate(
const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
C
TimerHandle_t xTimerCreateStatic(
const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t *pxTimerBuffer );
9.2.2 删除定时器¶
9.2.3 启动/停止定时器¶
C
BaseType_t xTimerStart(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
BaseType_t xTimerStartFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken );
BaseType_t xTimerStop(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
BaseType_t xTimerStopFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken );
9.2.4 复位定时器¶
C
BaseType_t xTimerReset(
TimerHandle_t xTimer,
TickType_t xTicksToWait );
BaseType_t xTimerResetFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken );
9.2.5 修改周期¶
C
BaseType_t xTimerChangePeriod(
TimerHandle_t xTimer,
TickType_t xNewPeriod,
TickType_t xTicksToWait );
BaseType_t xTimerChangePeriodFromISR(
TimerHandle_t xTimer,
TickType_t xNewPeriod,
BaseType_t *pxHigherPriorityTaskWoken );
9.2.6 软件定时器结构体¶
C
typedef struct tmrTimerControl
{
const char *pcTimerName; /* 定时器名称 */
ListItem_t xTimerListItem; /* 软件定时器列表项 */
TickType_t xTimerPeriodInTicks;/* 软件定时器的周期 */
UBaseType_t uxAutoReload; /* 自动重启pdTRUE/pdFALSE */
void *pvTimerID; /* 软件定时器的ID */
TimerCallbackFunction_t pxCallbackFunction; /* 软件定时器的回调函数 */
#if( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerNumber; /* 软件定时器的编号,调试用 */
#endif
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /* 软件定时器的状态 */
#endif
} xTIMER;
9.3 软件定时器示例¶
用软件定时器控制蜂鸣器发声,并在200ms后关闭。
蜂鸣器功能封装
C
static TimerHandle_t g_SoftTimerHandle;
/* 软件定时器超时函数 */
static void rtCallbackFunc(TimerHandle_t xTimer) {
Buzzer_OFF();
}
/* 软件定时器控制蜂鸣器 */
void rtBuzzerSoftTimer_Init(void) {
g_SoftTimerHandle = xTimerCreate(
"BuzzerSound",
200,
pdFALSE,
NULL,
rtCallbackFunc
);
}
/* 调用蜂鸣器,开启定时器 */
void rtBuzzerON(TickType_t period) {
Buzzer_ON();
xTimerChangePeriod(g_SoftTimerHandle, period, 0);
}
初始化与创建任务
C
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
rtBuzzerSoftTimer_Init();
/* USER CODE END Init */
...
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
xTaskCreate(OLED_PrintTask, "Task1", 128, NULL, osPriorityNormal, NULL);
/* USER CODE END RTOS_THREADS */
...
}
任务函数