ESP32外设-3.硬件定时器入门
说明:
- 本文档由DuRuofu撰写,由DuRuofu负责解释及执行。
- 本文档介绍ESP32硬件定时器的使用。(其他型号也可参考)
修订历史:
文档名称 | 版本 | 作者 | 时间 | 备注 |
---|---|---|---|---|
ESP32外设-硬件定时器入门 | v1.0.0 | DuRuofu | 2024-03-04 | 首次建立 |
ESP32外设-硬件定时器入门
若不必使用硬件定时器,则建议使用软件定时器:ESP 定时器
一、介绍:
通用定时器是 ESP32 定时器组外设的驱动程序。ESP32 硬件定时器分辨率高,具有灵活的报警功能。定时器内部计数器达到特定目标数值的行为被称为定时器报警。定时器报警时将调用用户注册的不同定时器回调函数。
通用定时器通常在以下场景中使用:
- 如同挂钟一般自由运行,随时随地获取高分辨率时间戳;
- 生成周期性警报,定期触发事件;
- 生成一次性警报,在目标时间内响应。
ESP32 内置 4 个 64-bit 通用定时器。每个定时器包含一个 16-bit 预分频器和一个 64-bit 可自动重新加载向上 /向下计数器。 ESP32 的定时器分为 2 组,每组 2 个。TIMGn_Tx 的 n 代表组别,x 代表定时器编号。
定时器特性:
• 16-bit 时钟预分频器,分频系数为 2-65536
• 64-bit 时基计数器
• 可配置的向上/向下时基计数器:增加或减少
• 暂停和恢复时基计数器
• 报警时自动重新加载
• 当报警值溢出/低于保护值时报警
• 软件控制的即时重新加载
• 电平触发中断和边沿触发中断
二、使用:
ESP32内置了两个定时器组 Timer Group
,每个定时器组都有两个64位定时器Timer
。支持向上、向下两个方向计数。支持设置警报阈值。
1、定时器初始化
通用定时器实例由 gptimer_handle_t
表示。
要初始化一个定时器实例,需要提前提供配置结构体 gptimer_config_t
,参数如下:
gptimer_config_t::clk_src
选择定时器的时钟源。gptimer_clock_source_t
中列出多个可用时钟,仅可选择其中一个时钟。gptimer_config_t::direction
设置定时器的计数方向,gptimer_count_direction_t
中列出多个支持的方向,仅可选择其中一个方向。gptimer_config_t::resolution_hz
设置内部计数器的分辨率。计数器每滴答一次相当于 1 / resolution_hz 秒。gptimer_config::intr_priority
设置中断的优先级。如果设置为0
,则会分配一个默认优先级的中断,否则会使用指定的优先级。- 选用
gptimer_config_t::intr_shared
设置是否将定时器中断源标记为共享源。
配置好结构体,将结构传递给 gptimer_new_timer()
,用以实例化定时器实例并返回定时器句柄。
如已不再需要之前创建的通用定时器实例,应通过调用 gptimer_del_timer()
回收定时器(在删除通用定时器句柄之前,请通过 gptimer_disable()
禁用定时器,或者通过 gptimer_enable()
确认定时器尚未使能。)
初始化示例:创建分辨率为 1 MHz 的通用定时器句柄
1 |
|
2、定时器设置和获取计数值
创建通用定时器时,内部计数器将默认重置为零。计数值可以通过 gptimer_set_raw_count()
异步更新。最大计数值取决于硬件定时器的位宽,这也会在 SOC 宏 SOC_TIMER_GROUP_COUNTER_BIT_WIDTH
中有所反映。当更新活动定时器的原始计数值时,定时器将立即从新值开始计数。
计数值可以随时通过 gptimer_get_raw_count()
获取。
3、设置警报动作
对于大多数通用定时器使用场景而言,应在启动定时器之前设置警报动作,但不包括简单的挂钟场景,该场景仅需自由运行的定时器。设置警报动作,需要根据如何使用警报事件来配置 gptimer_alarm_config_t
的不同参数:
gptimer_alarm_config_t::alarm_count
设置触发警报事件的目标计数值。设置警报值时还需考虑计数方向。尤其是当gptimer_alarm_config_t::auto_reload_on_alarm
为 true 时,gptimer_alarm_config_t::alarm_count
和gptimer_alarm_config_t::reload_count
不能设置为相同的值,因为警报值和重载值相同时没有意义。gptimer_alarm_config_t::reload_count
代表警报事件发生时要重载的计数值。此配置仅在gptimer_alarm_config_t::auto_reload_on_alarm
设置为 true 时生效。gptimer_alarm_config_t::auto_reload_on_alarm
标志设置是否使能自动重载功能。如果使能,硬件定时器将在警报事件发生时立即将gptimer_alarm_config_t::reload_count
的值重载到计数器中。
要使警报配置生效,需要调用 gptimer_set_alarm_action()
。特别是当 gptimer_alarm_config_t
设置为 NULL
时,报警功能将被禁用。
4、注册事件回调函数
定时器启动后,可动态产生特定事件(如“警报事件”)。如需在事件发生时调用某些函数,请通过 gptimer_register_event_callbacks()
将函数挂载到中断服务例程 (ISR)。gptimer_event_callbacks_t
中列出了所有支持的事件回调函数:
gptimer_event_callbacks_t::on_alarm
设置警报事件的回调函数。由于此函数在 ISR 上下文中调用,必须确保该函数不会试图阻塞(例如,确保仅从函数内调用具有ISR
后缀的 FreeRTOS API)。函数原型在gptimer_alarm_cb_t
中有所声明。
此功能将为定时器延迟安装中断服务,但不使能中断服务。所以,请在 gptimer_enable()
之前调用这一函数,否则将返回 ESP_ERR_INVALID_STATE
错误。了解详细信息,请查看章节 使能和禁用定时器。
5、使能和禁用定时器
在对定时器进行 IO 控制之前,需要先调用 gptimer_enable()
使能定时器。此函数功能如下:
- 此函数将把定时器驱动程序的状态从 init 切换为 enable。
- 如果
gptimer_register_event_callbacks()
已经延迟安装中断服务,此函数将使能中断服务。
调用 gptimer_disable()
会进行相反的操作,即将定时器驱动程序恢复到 init 状态,禁用中断服务并释放电源管理锁。
6、启动和停止定时器
启动和停止是定时器的基本 IO 操作。调用 gptimer_start()
可以使内部计数器开始工作,而 gptimer_stop()
可以使计数器停止工作。下文说明了如何在存在或不存在警报事件的情况下启动定时器。
调用 gptimer_start()
将使驱动程序状态从 enable 转换为 run, 反之亦然。注意确保 start 和 stop 函数成对使用,否则,函数可能返回 ESP_ERR_INVALID_STATE
。
三、示例:
1 |
|
上面的示例程序,包含了三个案例:
- 案例1:定时器触发警报事件后立即停止计时器,并将事件数据发送到队列中。
- 案例2:定时器触发警报事件后自动重新加载计数值,并将事件数据发送到队列中。
- 案例3:定时器触发警报事件后动态更新报警值,并将事件数据发送到队列中。
在每个案例中,程序初始化 gptimer,注册相应的定时器事件回调函数,启动定时器并设置报警事件,然后通过队列接收数据并进行相应的处理。
效果: