# 定时器应用指导
***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.***
---
# 功能概述
定时器通常指SoC或MCU内部的硬件外设,可周期性地触发系统中断。系统可依据该中断信号切换任务,或实现分频输出。
从硬件层面上,定时器可分为以下几类:
- **SysTick**
系统滴答定时器,用于周期性地提供计时功能。该定时器可以周期性地产生中断信号,是系统的心跳时钟,用于切换任务或为任务分配时间片。
- **通用定时器**
除了具备基本定时器功能外,还可以提供输入捕捉、输出比较和连接其他传感器接口的功能。
- **基本定时器**
无外部输入或输出引脚,主要用于时基计数和定时。
- **高级定时器**
除了具备通用定时器功能外,还可以提供电机控制、数字电源应用、死区时间可编程的互补输出等功能。
- **RTC**
提供实时时间和日期。
- **看门狗**
监测系统是否出现异常。
## 定时器背景
### 介绍
定时器可以产生中断,通知CPU特定事件已发生。这样CPU无需阻塞等待某一任务的结果,在等待期间可以运行其他功能。这种方式提高了效率,使系统整体运行更流畅、更高效、响应更快,从而提升用户体验并拓展应用范围。
### 定时器分类
定时器从广义上可分为硬件定时器和软件定时器。硬件定时器是软件定时器的基础。软件定时器在硬件定时器的基础上进行软件上的扩展,理论上没有个数限制,但其计时精度较低,且数量越多,差值越大。
#### 硬件定时器
硬件定时器分为SysTick、基本定时器、通用定时器、高级定时器、RTC定时器和看门狗定时器等。在系统稳定运行过程中,这些定时器各司其职。
硬件定时器工作原理框图如下所示:
```{image} images/image_Cj8gbNWS8oq0WQxGj57cMefOnZf.webp
:width: 762px
:height: 469px
```
图 1:硬件定时器工作原理框图
**定时器工作原理如下:**
- 时钟信号(CLK)输入至触发控制器。
- 触发控制器将信号输出到预分频器。
- 预分频后的信号被输入至计数器。
- 当计数器数值达到自动装载器数值时(根据定时器类型判断处理),若已使能中断,则定时器产生溢出中断。
上述流程即为定时器的工作原理概述,以下几类定时器的工作原理与此基本一致。
##### SysTick
SysTick(系统滴答定时器)又称心跳定时器。每次产生SysTick中断时,系统会切换任务,以此完成对任务的时间片分配以及任务切换。切换任务示意图见 **图2**。
```{image} images/image_VU3UbRg7coNHPmxsEkNcisyvnln.webp
:width: 1241px
:height: 400px
```
图 2:切换任务示意图
内部结构简图见 **图3。** RCC使用AHB时钟经8分频后,为 SysTick提供外部时钟源。
```{image} images/image_SsBobfEHcoSZKPx9E67cDUX5nGh.webp
:width: 470px
:height: 202px
```
图 3:内部结构简图
##### 基本定时器
基本功能如下:
- 自动装载的累加计数器。
- 触发DAC的同步电路。
- 更新时间产生中断请求。
- 可编程预分频器。
原理概念图见 **图1。** 时钟从内部或者外部提供给预分频器,经过分频将信号提供给计数寄存器。当计数器达到自动重装载寄存器中的数值时,即满足中断产生的条件。如果已开启中断功能,此时即可触发中断,完成定时任务。由上可知,定时是通过预分频器和自动重装载寄存器的设置完成的。
##### 通用定时器
除具备基本定时器功能外,还具有以下功能:
- 支持向上计数、向下计数、向上或向下计数的自动装载计数器。
- 独立通道。
- 使用外部信号控制定时器和定时器互连的同步电路。
- 支持针对定位的增量编码器和霍尔传感器电路。
- 触发输入可作为外部时钟,或者用于按周期进行电流管理。
原理概念图见 **图1。** 通用定时器和基本定时器的基本原理相同,其扩展功能只是在基本功能上进行了一些简单扩展,属于定时器的应用范畴,此处不再赘述。
##### 高级定时器
除具备通用定时器功能外,还具有以下功能:
- 死区时间可编程的互补输出。
- 仅在指定周期数后更新定时计数器。
- 中断信号输入,使计时器的输出信号处于重置状态或已知状态。
- 设置循环次数,实现重复计数。
原理概念图见 **图1。** 高级定时器和通用定时器、基本定时器的基本原理相同,同样是对基本功能的扩展。其中,死区时间功能对PWM应用非常实用。
##### RTC定时器
实时时钟(RTC)是一个独立的BCD定时器或计数器。它可以将设备从休眠态唤醒,用于管理设备的低功耗模式。在相应配置下,可提供时钟日历功能。模块重启后,RTC时间将被重置。当注网成功后,RTC时间将会更新。其硬件框图如下所示:
```{image} images/image_WhqtbQLsjoOsQXxsKETcBoagnWg.webp
:width: 899px
:height: 776px
```
图 4:硬件框图
##### 看门狗定时器
看门狗用于监测和处理由软件错误导致的故障。当计数器递减到0(或者递增到设定的计数值)时,将触发系统复位。它有专用的低速时钟驱动,即使主时钟发生故障也依然有效。通过可配置的时间窗口,可以调整看门狗的时间。所谓“喂狗”,即是对计数器重新赋初值(或计数器清零)。其原理框图如下:
```{image} images/image_UiJ0bVjWFoFV7dx1bjPcxrA6ncf.webp
:width: 1010px
:height: 413px
```
图 5:原理框图
#### 软件定时器
软件定时器实现的基础是硬件支持定时任务设置。
其实现逻辑是建立一个链表(或二叉树等其他数据结构)。设置新的软件定时器时,记录到期时间并将其加入到链表中(或者二叉树中)。每次选取最近的软件定时器到期时间,并将其设置到硬件定时器中。当硬件定时器中断触发时,即可执行到期的硬件定时任务,并在其中处理相应的软件定时器任务。下次到期后,选取最近的软件定时器到期时间重新设置到硬件定时器中。如此循环,即可实现软件定时器。从上述原理可以看出,软件定时器无法达到硬件定时器的精准,但是可以突破硬件定时器的数量限制。实现逻辑框图如下:
```{image} images/image_V2rSbcGWCoYNSAxbMnIcNZmandc.webp
:width: 432px
:height: 549px
```
图 6:逻辑框图
- **步骤 1**
记录当前添加的软件定时器的到期时间,并加入到软件定时器链表中。
- **步骤 2**
遍历软件定时器链表并排序,选取最小的到期时间,将其设置到硬件定时器中。
- **步骤 3**
硬件定时器到期后,遍历软件定时器链表,执行此定时器注册的事件,并将到期的节点从软件定时器链表中删除。
- **步骤 4**
判断软件定时器链表是否为空。若为空,则退出流程。
以上仅为软件定时器实现的一种简单方式,并非最佳方式。针对不同场景,实际实现会进行数据结构的选型和优化。以上只是介绍其实现的基本原理。
UniRTOS模块定时器分为两种:硬件定时器和软件定时器。硬件定时器用于内核侧,软件定时器开放给应用层使用。
# 定时器API
## 头文件
*qosa_sys.h*
## 函数概览
| **函数名** | **功能描述** |
| --- | --- |
| *qosa_timer_create()* | 创建定时器 |
| *qosa_timer_start()* | 启动定时器 |
| *qosa_timer_stop()* | 停止定时器 |
| *qosa_timer_is_running()* | 检查定时器运行状态 |
| *qosa_timer_delete()* | 删除定时器 |
## 函数详解
### qosa_timer_create
- **功能描述**
创建定时器,并进行初始化,为定时器分配内存并设置回调函数。
- **函数原型**
```c
int qosa_timer_create(qosa_timer_t* timerRef,
void (*callBackRoutine)(void*),
void* argv)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *timerRef* | 输出 | qosa_timer_t* | 指向定时器句柄指针的地址,用于接收创建的定时器 |
| *callBackRoutine* | 输入 | void (*)(void*) | 定时器回调函数指针,定时器到期时调用 |
| *argv* | 输入 | void * | 传递给回调函数的用户参数 |
- **返回值说明**
*QOSA_ERROR_OK*:函数执行成功
*QOSA_ERROR_PARAM_INVALID*:定时器参数无效
*QOSA_ERROR_NO_MEMORY*:申请空间失败
```{note}
1. 回调函数应尽量简短,避免执行耗时操作。
2. 创建失败时不会分配任何资源,无需清理。
```
### qosa_timer_start
- **功能描述**
启动定时器,设置定时时间和循环模式。定时器到期后会调用创建时注册的回调函数。
- **函数原型**
```c
int qosa_timer_start(qosa_timer_t timerRef,
qosa_uint32_t set_Time,
qosa_bool_t cyclicalEn)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *timerRef* | 输入 | qosa_timer_t | 定时器句柄,由 *qosa_timer_create()* 创建。 |
| *set_Time* | 输入 | qosa_uint32_t | 定时时间。单位:毫秒。 |
| *cyclicalEn* | 输入 | qosa_bool_t | 循环模式使能。
*QOSA_TRUE*:循环定时器;
*QOSA_FALSE*:单次定时器。 |
- **返回值说明**
*QOSA_ERROR_OK*:函数执行成功
*QOSA_ERROR_PARAM_IS_NULL*:定时器参数无效
*QOSA_ERROR_GENERAL*:中断定时器执行失败
*QOSA_ERROR_TIMER_START_ERR*:普通定时器执行失败
```{note}
1. 循环定时器每次到期后自动重启,直至调用 ***qosa_timer_stop()*** 进行停止。
2. 单次定时器触发一次回调后自动停止。
3. 支持动态修改定时参数。重复调用 ***qosa_timer_start()*** 会覆盖之前的设置。
```
### qosa_timer_stop
- **功能描述**
停止定时器。停止后定时器状态变为 *QOSA_FALSE*,不再触发回调函数。
- **函数原型**
```c
int qosa_timer_stop(qosa_timer_t timerRef)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *timerRef* | 输入 | qosa_timer_t | 定时器句柄 |
- **返回值说明**
*QOSA_ERROR_OK*:函数执行成功
*QOSA_ERROR_PARAM_IS_NULL*:定时器参数无效
*QOSA_ERROR_GENERAL*:中断定时器停止失败
*QOSA_ERROR_TIMER_DELETE_ERR*:普通定时器停止失败
```{note}
1. 未启动的定时器调用此函数不会产生错误。
2. 停止后,定时器可通过调用 ***qosa_timer_start()*** 重新启动。
```
### qosa_timer_is_running
- **功能描述**
检查定时器运行状态。
- **函数原型**
```c
qosa_bool_t qosa_timer_is_running(qosa_timer_t timerRef)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *timerRef* | 输入 | qosa_timer_t | 定时器句柄 |
- **返回值说明**
*QOSA_TRUE*:定时器正在运行
*QOSA_FALSE*:定时器未运行或参数无效
### qosa_timer_delete
- **功能描述**
删除定时器,并释放所有相关资源。
- **函数原型**
```c
int qosa_timer_delete(qosa_timer_t timerRef)
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *timerRef* | 输入 | qosa_timer_t | 定时器句柄 |
- **返回值说明**
*QOSA_ERROR_OK*:函数执行成功
*QOSA_ERROR_PARAM_IS_NULL*:定时器参数无效
*QOSA_ERROR_TIMER_DELETE_ERR*:定时器删除失败
```{note}
1. 删除前会自动停止定时器。
2. 删除后的定时器句柄不可再使用。
3. 应在不再使用定时器时调用此函数,避免资源泄露。
```
## 枚举定义
### qosa_errcode_os_e
结果码枚举定义如下:
```plaintext
typedef enum
{
QOSA_ERROR_PARAM_INVALID
QOSA_ERROR_NO_MEMORY
QOSA_ERROR_PARAM_IS_NULL
QOSA_ERROR_GENERAL
QOSA_ERROR_TIMER_START_ERR
QOSA_ERROR_TIMER_DELETE_ERR
...
}qosa_errcode_os_e;
```
| **成员** | **说明** |
| --- | --- |
| *QOSA_ERROR_PARAM_INVALID* | 参数无效 |
| *QOSA_ERROR_NO_MEMORY* | 内存不足 |
| *QOSA_ERROR_PARAM_IS_NULL* | 参数为空 |
| *QOSA_ERROR_GENERAL* | 通用错误 |
| *QOSA_ERROR_TIMER_START_ERR* | 定时器启动失败 |
| *QOSA_ERROR_TIMER_DELETE_ERR* | 定时器删除失败 |
# 应用逻辑流程图
```{figure} images/board_IKQOwIVPihHjaYbTMiccuNVWnjf.jpg
:align: center
:alt: image
```
# 示例代码
完整示例代码请查看 https://github.com/UniRTOS/UniRTOS-Doc-Examples/blob/main/system/timer/timer_demo.c 。
运行结果输出:
```c
定时器创建成功
定时器启动成功,模式:循环,间隔:1000ms
定时器正在运行
主程序运行中...
[定时器回调] 测试定时器: 第1次触发
主程序运行中...
主程序运行中...
[定时器回调] 测试定时器: 第2次触发
主程序运行中...
主程序运行中...
[定时器回调] 测试定时器: 第3次触发
主程序运行中...
主程序运行中...
[定时器回调] 测试定时器: 第4次触发
主程序运行中...
主程序运行中...
[定时器回调] 测试定时器: 第5次触发
定时器已停止
定时器已删除
```
# 常见问题
## **定时器失效有哪些可能?**
- 系统压力过大,导致定时器回调函数未能正常执行。
- 定时器已经被删除或停止。
## **定时器是否会因为更新网络时间导致定时器超时时间错乱?**
- 不会。定时器的超时时间不受网络时间更新影响。
## **关机和深休眠情况下定时器表现怎样?**
- **关机后:** 定时器不再工作。重启后需要重新创建并启用定时器。
- **深休眠后:** 定时器不再运行,唤醒后也不再起作用,需要重新设置。
- 在深休眠情况下,RTC可以唤醒模块,使其正常运行。
## **硬件定时器软件定时器的区别?**
- 硬件定时器系统个数是有限的,软件定时器理论上只要系统资源足够,没有个数限制。
- 软件定时器基于硬件定时器实现。