# 定时器应用指导 ***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可以唤醒模块,使其正常运行。 ## **硬件定时器软件定时器的区别?** - 硬件定时器系统个数是有限的,软件定时器理论上只要系统资源足够,没有个数限制。 - 软件定时器基于硬件定时器实现。