OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 291|回复: 0

《ESP32-P4开发指南— V1.0》第十六章 TIMG实验

[复制链接]

1218

主题

1232

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5244
金钱
5244
注册时间
2019-5-8
在线时间
1328 小时
发表于 12 小时前 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2025-12-19 09:46 编辑

第十六章 TIMG实验

1)实验平台:正点原子DNESP32P4开发板

2)章节摘自【正点原子】ESP32-P4开发指南— V1.0

3)购买链接:https://detail.tmall.com/item.htm?id=873309579825

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子DNESP32S3开发板技术交流群:132780729


2.jpg

3.png

在本章中,我们将深入探索ESP32-P4芯片中的定时器组(TIMG)功能。定时器不仅用于精确计时,还可用于生成中断和实现定时控制,为嵌入式系统的实时性能提供了重要支持。我们将详细介绍TIMG的结构、特性以及使用方法,通过一系列实验来展示如何配置和操作定时器。通过这些实验,读者将能够理解定时器的基本原理,并掌握在实际应用中如何高效利用这些功能。准备好进入定时器的世界吧!
16.1 TIMG简介
16.2 硬件设计
16.3 程序设计
16.4 下载验证


16.1 TIMG简介
通用定时器可用于精确计时、在特定时间后触发中断(可周期性或非周期性)或作为硬件时钟。ESP32-P4芯片包含两个定时器组,分别是定时器组0和定时器组1(以下简称TIMGn,其中n可以是0或1)。每个定时器组由两个通用定时器(以下简称Tx,其中x可以是0或1)和一个主系统看门狗定时器(MWDT)组成,如下图为TIMG定时器组的简图。

第十六章 TIMG实验422.png
图16.1.1 TIMG定时器组简图

TIMG定时器组定时器的特性总结如下:
1)54位时间基准计数器:支持递增或递减配置,提供高精度的时间计量。
2)多种时钟源:可选择PLL_F80M_CLK、XTAL_CLK或RC_FAST_CLK作为时钟源。
3)16位时钟预分频器:预分频器范围从2到65536,允许用户根据具体要求调整计时精度。
4)实时计数器读取:可以实时读取时间基准计数器的当前值,方便监控和控制。
5)暂停与恢复功能:支持在需要时暂停和恢复计数器的计数,适应动态场景需求。
6)可编程报警生成:能够根据计时值生成可编程的报警,提高应用的灵活性。
7)定时器值重载:支持在报警时自动重载或通过软件控制进行即时重载。
8)时钟频率计算:根据晶体时钟测得的频率,可计算并生成TIMG0_CALI_CLK。
9)电平中断生成:能够生成电平中断,便于与其他系统组件进行有效协作。
10)支持多任务和事件:可同时支持多个ETM任务和事件,提升系统的并行处理能力。
在这里,我们已经大致了解了TIMG定时器组的相关特性。接下来,笔者将深入讲解这些定时器组的计时原理,以便读者能够更好地理解定时器的工作机制和应用场景。

16.1.1 定时器组的结构和原理
下图16.1.1.1展示了定时器组TIMGn中的定时器Tx。Tx包含一个16位整数分频器作为预分频器、一个基于定时器的计数器和一个用于报警生成的比较器。

第十六章 TIMG实验1030.png
图16.1.1.1 定时器组架构

上图展示了定时器组TIMGn的结构,包括定时器Tx的工作原理和各个组件。该架构被分为三个主要部分:时钟源配置、计时器的分频与配置、比较器的警报机制和定时中断。接下来,笔者分别详细说明每一部分的功能和原理。
1,时钟源配置
定时器组可以从三种时钟源中选择一个作为输入时钟:XTAL_CLK、RC_FAST_CLK或PLL_F80M_CLK。通过设置寄存器HP_SYS_CLKRST_PERI_CLK_CTRL20_REG或HP_SYS_CLKRST_PERI_CLK_CTRL21_REG中的HP_SYS_CLKRST_TIMERGRPn_Tx_SRC_SEL字段,可以选择所需的时钟源。这些寄存器位描述如下所示。


第十六章 TIMG实验1357.png
图16.1.1.2 配置哪个定时器组的哪个定时器时钟源

上图中,定时器的时钟源选择通过一个多路复用器来实现,配置范围为0~1。具体来说,定时器组0的0号定时器的时钟源可以通过HP_SYS_CLKRST_TIMERGRP0_T0_SRC_SEL寄存器进行配置。此寄存器的设置方式如下:
1)0:选择XTAL_CLK(晶体振荡器时钟)作为定时器的时钟源。
2)1:选择RC_FAST_CLK作为定时器的时钟源。
3)2:选择PLL_F80M_CLK作为定时器的时钟源。
注意:上图的字段名称是由笔者根据多个类似的寄存器总结得出的,所以用户请根据《ESP32-P4技术参考手册》的寄存器命名为准。
2,计时器的分频与配置
默认情况下,当定时器选择XTAL_CLK作为时钟源时,输入时钟经过图 16.1.1.1 中的16位预分频器进行分频操作,分频系数范围为2至63336。该分频器由TIMG_TxCONFIG_REG寄存器中的TIMG_Tx_DIVIDER字段决定,该寄存器描述如下所示。


第十六章 TIMG实验1801.png
图16.1.1.3 配置分频系数

上图中的TIMG_Tx_DIVCNT_RST字段用于重置预分频器。如果此位被置为1,则必须先禁用计数器,然后通过TIMG_Tx_DIVIDER字段配置预分频数值。时钟频率经过预分频器得到分频的时钟TB_CLK,该时钟作为计数器计数的基准。随后,通过TIMG_TxCONFIG_REG寄存器中的TIMG_Tx_INCREASE和TIMG_Tx_EN字段使能计数器的工作,这两个字段的描述如下所示。

第十六章 TIMG实验2018.png
图16.1.1.4 配置计数器的方向与使能计数器

上图中,我们通过配置TIMG_Tx_INCREASE字段来设置当前计数器的计数方向(0:向下计数;1:向上计数),而通过TIMG_Tx_EN字段来开启计数器。这样,我们就可以得到计数器在规定时间计数的数值了(图 16.1.1.1中的TIMG_VALUE)。
若我们想设置计数器的初始计数值或者重新装载值,可以通过向TIMG_Tx_LOAD_LO和TIMG_Tx_LOAD_HI寄存器写入起始值来实现。然后,通过向TIMG_TxLOAD_REG写入任意值将其重新加载到定时器中,这些寄存器描述如下图所示。


第十六章 TIMG实验2297.png
图16.1.1.5 配置重装载值(多个寄存器的合并图)

若我们要读取54位时间基准计数器的值,计时器值必须先被锁存到两个寄存器中,以便CPU读取(由于CPU是32位的,所以只能读取32位以内的数据)。通过向TIMG_TxUPDATE_REG写入任意值,当前54位计时器的值将开始被锁存到TIMG_TxLO_REG和TIMG_TxHI_REG寄存器中,前者包含低32位,后者包含高22位。当TIMG_TxUPDATE_REG被硬件清除时,表示锁存操作已完成,此时可以从TIMG_TxLO_REG和TIMG_TxHI_REG寄存器读取当前计时器值。TIMG_TxLO_REG和TIMG_TxHI_REG寄存器在CPU读取时将保持不变,直到TIMG_TxUPDATE_REG再次被写入。这些寄存器描述如下图所示。

第十六章 TIMG实验2653.png
图16.1.1.6 读取计数值(多个寄存器合并图)

若读者希望定时器以1µs计时,可以将预分频数值设置为80。其计算公式为:

第十六章 TIMG实验2718.png

根据上述的公式计算,80M / 80 = 1MHz的定时器时钟频率(图 16.1.1.1 中的TB_CLK),然后根据时间 T与频率F的关系,如下公式所示:

第十六章 TIMG实验2803.png

经过上述公式的计算,最终计数器计数一次的时钟为1µs。
3,比较器的警报机制
若计数器启动后,TIMG_VALUE的数值会输入到比较器(Comparator)中,比较器根据警报值进行比较。如果TIMG_VALUE数值与警报值相等或出现其他触发情况,则会触发定时组中断(TIMG_Tx_INT)。下表为警报触发情景。


1.png
表16.1.1.1 警报触发情景

图16.1.1.1中,我们通过TIMG_TxCONFIG_REG寄存器中的TIMG_Tx_ALARM_EN字段来使能比较器,而警报值可通过TIMG_TxALARMLO_REG寄存器和TIMG_TxALARMHI_REG寄存器进行配置。这些字段描述如下所示。

第十六章 TIMG实验3551.png
图16.1.1.7 配置警报数值(多个寄存器合并图)

注意:报警时,TIMG_Tx_ALARM_EN字段会自动清除。这意味着在下次显式重新设置TIMG_Tx_ALARM_EN之前,不会再触发任何报警。这种行为确保每个事件只会触发一次报警。
3,定时中断
当计数值与警报值相等时,将触发中断输出TIMG_Tx_INT至中断矩阵,最后通知CPU触发中断。

16.1.2 定时器重载
当定时器的当前值被覆盖为存储在TIMG_Tx_LOAD_LO和TIMG_Tx_LOAD_HI字段中的重载值时,定时器就会被重载。这两个字段分别对应定时器新值的低32位和高22位。然而,写入重载值到TIMG_Tx_LOAD_LO和TIMG_Tx_LOAD_HI不会导致定时器当前值的变化。相反,重载值在重载事件发生之前会被定时器忽略。
重载事件可以通过软件即时重载或报警自动重载触发。
1)软件即时重载:当CPU向TIMG_TxLOAD_REG写入任何值时,会触发即时重载,这会立即更新定时器的当前值。如果 TIMG_Tx_EN 被设置,定时器将继续从新值开始递增或递减。在这种情况下,如果TIMG_Tx_ALARM_EN被设置,定时器仍然会在表16.1.1.1中列出的场景中触发报警。如果TIMG_Tx_EN被清除,定时器将保持在新值处冻结,直到重新启用计数。
2)报警自动重载:当报警发生时,将导致定时器重载,从而允许定时器从重载值继续递增或递减。这在使用周期性报警时非常有用,可以重置定时器的值。要启用报警自动重载,应该设置TIMG_Tx_AUTORELOAD字段。如果没有启用,定时器的值将在报警后继续递增或递减,超过报警值。

16.2 硬件设计

16.2.1 程序功能
在1s周期内翻转LED0电平状态,并实时打印当前计数值。

16.2.2 硬件资源
1)LED灯
        LED        0        - IO51
2)TIMG

16.2.3 原理图
本章实验使用的TIMG为ESP32-P4的片上资源,因此并没有相应的连接原理图。

16.3 程序设计
注意:本书提供了两个TIMG实验,分别为06_1_timg和06_2_timg。其中,06_1_timg实验使用旧版本的API,而06_2_timg实验使用新版API。之所以提供两个版本,是因为旧版和新版API在定时器组的选择方式上存在差异。06_1_timg实验允许用户自由选择定时器组和定时器,可以灵活指定使用哪个定时器组的哪个定时器。而在06_2_timg实验中,使用的新API要求创建定时器时必须按顺序从定时器组0的定时器0开始,依次创建到定时器组1的定时器1。这意味着在新版本中,用户不能随意选择定时器组和定时器,必须按照固定的顺序进行创建和使用。
本章节将以06_2_timg实验中使用的API函数为基准进行讲解,06_1_timg实验仅作为参考。

16.3.1 TIMG的IDF驱动
TIMG外设驱动位于ESP-IDF的components\esp_timer目录。该目录中的include文件夹存放TIMG相关的头文件,声明了TIMG函数和结构体等;而src文件夹则存放实际的TIMG操作函数。要使用TIMG功能,必须先导入以下头文件。
  1. <font size="3">#include "driver/gptimer.h"</font>
  2. <font size="3">#include "../src/gptimer_priv.h"</font>
复制代码
接下来,作者将介绍一些常用的TIMG函数,这些函数的描述及其作用如下:
1,创建一个新的通用定时器gptimer_new_timer
该函数用于创建一个新的通用定时器,其函数原型如下:
  1. <font size="3">esp_err_t gptimer_new_timer(const gptimer_config_t *config, </font>
  2. <font size="3">gptimer_handle_t *ret_timer);</font>
复制代码
函数形参:

2.png
表16.3.1.1 gptimer_new_timer函数形参描述

返回值:
ESP_OK表示成功创建GPTimer。
ESP_ERR_INVALID_ARG表示创建GPTimer失败,因参数无效。
ESP_ERR_NO_MEM表示创建GPTimer失败,因内存不足。
ESP_ERR_NOT_FOUND表示创建GPTimer失败,因所有硬件定时器已被使用,没有可用。
ESP_FAIL表示创建GPTimer失败,因其他错误。
config为指向TIMG配置结构体的指针。接下来,笔者将详细介绍gptimer_config_t结构体中的各个成员变量,如下代码所示:
  1. typedef struct {
  2.     gptimer_clock_source_t clk_src;              /* GPTimer时钟源 */
  3. gptimer_count_direction_t direction;         /* 计数方向 */
  4. /* 计数器分辨率(工作频率),以 Hz 为单位,每次计数的 步长等于 (1/resolution_hz) 秒 */
  5. uint32_t resolution_hz;               
  6. /* GPTimer中断优先级,如果设置为0,驱动程序将尝试分配相对较低优先级的中断(1,2,3) */
  7.     int intr_priority;                  
  8. struct {
  9. uint32_t intr_shared: 1;/* 设为真,则定时器中断号可以与其他外设共享 */
  10. /* 如果设置,驱动程序将在进入/退出睡眠模式之前/之后备份/恢复 GPTimer 寄存器。
  11. 通过这种方式,系统可以关闭 GPTimer 的电源域。这可以节省电力,但会消耗更多的 RAM */
  12.         uint32_t backup_before_sleep: 1;
  13.     } flags;                                                                /* GPTimer 配置标志 */
  14. } gptimer_config_t;
复制代码
上述结构体用于配置TIMG的定时参数,以下对各个成员做简单介绍。
1)clk_src:
设置GPTimer时钟源。此字段可配置为GPTIMER_CLK_SRC_PLL_F80M、GPTIMER_CLK_SRC_RC_FAST、GPTIMER_CLK_SRC_XTAL和GPTIMER_CLK_SRC_DEFAULT。
2)direction:
设置定时计数方向。可选GPTIMER_COUNT_DOWN向下计数或GPTIMER_COUNT_UP向上计数。
3)resolution_hz:
设置计数器分辨率。
4)intr_priority:
设置定时器中断优先级。
5)flags.intr_shared
设置TIMG中断号共享。
6)flags.backup_before_sleep
设置进入睡眠。
2,通用定时器(GPTimer)设置回调函数gptimer_register_event_callbacks
该函数用于通用定时器(GPTimer)设置回调函数,其函数原型如下:
  1. esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer,
  2. const gptimer_event_callbacks_t *cbs,
  3. void *user_data);
复制代码
函数形参:

3.png
表16.3.1.2 gptimer_register_event_callbacks函数形参描述

返回值:
ESP_OK表示成功设置事件回调。
ESP_ERR_INVALID_ARG表示由于无效参数导致设置回调失败。
ESP_ERR_INVALID_STATE表示定时器不处于初始化状态,无法设置回调。
ESP_FAIL表示由于其他错误导致设置回调失败。
3,启用通用定时器gptimer_enable
该函数用于启用通用定时器,其函数原型如下:
  1. esp_err_t gptimer_enable(gptimer_handle_t timer);
复制代码
函数形参:

4.png
表16.3.1.3 gptimer_enable函数形参描述

返回值:
ESP_OK表示成功启用GPTimer。
ESP_ERR_INVALID_ARG表示由于无效参数导致启用失败。
ESP_ERR_INVALID_STATE表示定时器已经处于启用状态,无法再次启用。
ESP_FAIL表示由于其他错误导致启用失败。
4,通用定时器(GPTimer)设置报警事件的操作gptimer_set_alarm_action
该函数用于通用定时器(GPTimer)设置报警事件的操作,其函数原型如下:
  1. esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer,
  2. const gptimer_alarm_config_t *config);
复制代码
函数形参:

5.png
表16.3.1.4 gptimer_set_alarm_action函数形参描述

返回值:
ESP_OK表示成功为GPTimer设置报警操作。
ESP_ERR_INVALID_ARG表示由于无效参数导致设置失败。
ESP_FAIL表示由于其他错误导致设置失败。
config为指向报警配置结构体的指针。接下来,笔者将详细介绍gptimer_alarm_config_t结构体中的各个成员变量,如下代码所示:
  1. typedef struct {
  2.     uint64_t alarm_count; /* 报警目标计数值,当定时器计数达到此值时,将触发报警事件 */
  3.     uint64_t reload_count;/* 报警重载计数值,仅在auto_reload_on_alarm设为真时有效 */
  4.     struct {
  5.         uint32_t auto_reload_on_alarm: 1; /* 报警事件发生时,硬件是否立即重载计数值 */
  6.     } flags;                              /* 报警配置标志 */
  7. } gptimer_alarm_config_t;
复制代码
gptimer_alarm_config_t结构体用于传递通用定时器(GPTimer)的报警配置参数。以下是各个参数的说明。

6.png
表16.3.1.5 gptimer_alarm_config_t结构体的各个参数描述及可选项

5,启动通用定时器gptimer_start
该函数用于启动通用定时器,其函数原型如下:
  1. esp_err_t gptimer_start(gptimer_handle_t timer);
复制代码
函数形参:

7.png
表16.3.1.6 gptimer_start函数形参描述

返回值:
ESP_OK表示成功启动GPTimer。
ESP_ERR_INVALID_ARG表示启动GPTimer失败,原因是无效参数。
ESP_ERR_INVALID_STATE表示启动GPTimer失败,因为定时器未启用或已处于运行状态。
ESP_FAIL表示启动GPTimer失败,原因是其他错误。

16.3.2 程序流程图

第十六章 TIMG实验8584.png
图16.3.2.1 TIMG实验程序流程图

16.3.3 程序解析
在06_2_timg例程中,作者在06_2_timg\components\BSP路径下新建TIMG文件夹,并且需要更改CMakeLists.txt内容,以便在其他文件上调用。
1,TIMG驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。ESPTIMER驱动源码包括两个文件:timg.c和timg.h。
timg.h主要用于声明timg_init等函数,以便在其他文件中调用,具体内容不再赘述。
下面我们再解析timg.c的程序,看一下初始化函数timg_init,代码如下:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief              初始化定时器</font>
  3. <font size="3"> * [url=home.php?mod=space&uid=271674]@param[/url]             alarm_count:触发警报事件的目标计数值</font>
  4. <font size="3"> * @param             resolution: 定时器的分辨率</font>
  5. <font size="3"> * @retval           定时器的ID</font>
  6. <font size="3"> */</font>
  7. <font size="3">uint8_t timg_init(uint64_t alarm_count, uint32_t resolution)</font>
  8. <font size="3">{</font>
  9. <font size="3">    gptimer_handle_t gptimer = NULL;                         /* 定义一个通用定时器实例 */</font>
  10. <font size="3">    uint8_t group_index, timer_index, timer_id = 0;</font>

  11. <font size="3">    gptimer_config_t timer_config =                  /* 配置定时器参数 */</font>
  12. <font size="3">    {</font>
  13. <font size="3">        .clk_src = GPTIMER_CLK_SRC_DEFAULT,          /* 选择定时器的时钟源 */</font>
  14. <font size="3">        .direction = GPTIMER_COUNT_UP,                /* 设置定时器的计数方向 */</font>
  15. <font size="3">/* 设置内部计数器的分辨率,若为1000000即1MHz,1tick = 1us */</font>
  16. <font size="3">        .resolution_hz = resolution,         </font>
  17. <font size="3">    };</font>
  18. <font size="3">    ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));/* 实例化定时器 */</font>
  19. <font size="3">    </font>
  20. <font size="3">    /* 获取定时器ID信息 */</font>
  21. <font size="3">    group_index = gptimer->group->group_id;</font>
  22. <font size="3">    timer_index = gptimer->timer_id;</font>
  23. <font size="3">    timer_id |= (group_index << 1) | timer_index;</font>
  24. <font size="3">ESP_LOGI("timer", "group_index:%d  timer_index:%d  timer_id:%d",</font>
  25. <font size="3">         group_index, timer_index, timer_id); </font>

  26. <font size="3">    gptimer_event_callbacks_t callback_func =                 </font>
  27. <font size="3">    {</font>
  28. <font size="3">        .on_alarm = timeout_callback,              /* 设置警报事件的回调函数 */</font>
  29. <font size="3">};</font>
  30. <font size="3">/* 将函数挂载到中断服务例程 (ISR) */</font>
  31. <font size="3">ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer,</font>
  32. <font size="3">&callback_func, NULL));  </font>

  33. <font size="3">    gptimer_enable(gptimer);                            /* 使能定时器 */</font>

  34. <font size="3">    gptimer_alarm_config_t alarm_config = </font>
  35. <font size="3">    {</font>
  36. <font size="3">        .alarm_count = alarm_count,                     /* 报警目标计数值 */</font>
  37. <font size="3">        .reload_count = 0,                              /* 重载计数值为0 */</font>
  38. <font size="3">        .flags.auto_reload_on_alarm = true,             /* 开启重加载 */</font>
  39. <font size="3">    };   </font>
  40. <font size="3">    gptimer_set_alarm_action(gptimer, &alarm_config);   /* 设置触发报警条件 */</font>

  41. <font size="3">    gptimer_start(gptimer);                             /* 定时器开始工作 */</font>

  42. <font size="3">    return timer_id;</font>
  43. <font size="3">}</font>
复制代码
timg_init函数用于初始化一个通用定时器,配置其时钟源、计数方向和分辨率。它注册一个报警回调函数,使能定时器,并设置报警条件,包括目标计数值和自动重载功能。最后,函数启动定时器并返回定时器的ID,以便后续使用。如下是GPTimer回调函数timeout_callback的处理任务。
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief            定时器回调函数</font>
  3. <font size="3"> * @param             timer:通用定时器对象</font>
  4. <font size="3"> * @param             edata:通用定时器警报事件数据</font>
  5. <font size="3"> * @param            user_data:用户数据</font>
  6. <font size="3"> * @retval            布尔类型</font>
  7. <font size="3"> */</font>
  8. <font size="3">static bool IRAM_ATTR timeout_callback( gptimer_handle_t timer, </font>
  9. <font size="3">const gptimer_alarm_event_data_t *edata, </font>
  10. <font size="3">void *user_data)</font>
  11. <font size="3">{</font>
  12. <font size="3">    if (timer->group->group_id == 0)        /* 定时器组0 */</font>
  13. <font size="3">    {</font>
  14. <font size="3">        if ((timer->timer_id))              /* 定时器1 */</font>
  15. <font size="3">        {</font>
  16. <font size="3">            /* 执行定时器1定时操作 */</font>
  17. <font size="3">            ESP_DRAM_LOGI("TimerGroup0", "timer1 time out");</font>
  18. <font size="3">        }</font>
  19. <font size="3">        else                                /* 定时器0 */</font>
  20. <font size="3">        {</font>
  21. <font size="3">            /* 执行定时器0定时操作 */</font>
  22. <font size="3">            ESP_DRAM_LOGI("TimerGroup0", "timer0 time out");</font>
  23. <font size="3">        }</font>
  24. <font size="3">    }</font>
  25. <font size="3">    else                                    /* 定时器组1 */</font>
  26. <font size="3">    {</font>
  27. <font size="3">        if ((timer->timer_id))              /* 定时器1 */</font>
  28. <font size="3">        {</font>
  29. <font size="3">            /* 执行定时器1定时操作 */</font>
  30. <font size="3">            ESP_DRAM_LOGI("TimerGroup1", "timer1 time out");</font>
  31. <font size="3">        }</font>
  32. <font size="3">        else                                /* 定时器0 */</font>
  33. <font size="3">        {</font>
  34. <font size="3">            /* 执行定时器0定时操作 */</font>
  35. <font size="3">            ESP_DRAM_LOGI("TimerGroup1", "timer0 time out");</font>
  36. <font size="3">        }</font>
  37. <font size="3">    }</font>

  38. <font size="3">    return pdTRUE;</font>
  39. <font size="3">}</font>
复制代码
timeout_callback是一个定时器回调函数,当定时器触发报警事件时被调用。该函数根据定时器所属的组和ID,判断是哪个定时器超时,并打印相应的日志信息。返回值为pdTRUE,表示回调执行成功。
2,CMakeLists.txt文件
本例程的功能实现主要依靠GPTimer驱动。要在main函数中,成功调用GPTimer文件中的内容,就得需要修改BSP文件夹下的CMakeLists.txt文件(重点看红色内容),修改如下:
  1. <font size="3">set(src_dirs</font>
  2. <font size="3">            LED</font>
  3. <font size="3">            TIMG)</font>

  4. <font size="3">set(include_dirs</font>
  5. <font size="3">            LED</font>
  6. <font size="3">            TIMG)</font>

  7. <font size="3">set(requires</font>
  8. <font size="3">            driver</font>
  9. <font size="3">            esp_timer)</font>

  10. <font size="3">idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs}</font>
  11. <font size="3">                       REQUIRES ${requires})</font>

  12. <font size="3">component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)</font>
复制代码
3,main.c驱动代码
在main.c里面编写如下代码。
  1. <font size="3">void app_main(void)</font>
  2. <font size="3">{</font>
  3. <font size="3">    esp_err_t ret;</font>
  4. <font size="3">    ret = nvs_flash_init();                    /* 初始化NVS */</font>
  5. <font size="3">    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)</font>
  6. <font size="3">    {</font>
  7. <font size="3">        ESP_ERROR_CHECK(nvs_flash_erase());</font>
  8. <font size="3">        ESP_ERROR_CHECK(nvs_flash_init());</font>
  9. <font size="3">    }</font>
  10. <font size="3">    led_init();                         /* 初始化LED */</font>
  11. <font size="3">    /* 执行顺序会自动分配定时器 */</font>
  12. <font size="3">    timg_init(500000, 1000000);          /* 定时器0初始化 */</font>
  13. <font size="3">    timg_init(1000000, 1000000);         /* 定时器1初始化 */</font>
  14. <font size="3">    timg_init(2000000, 1000000);         /* 定时器2初始化 */</font>
  15. <font size="3">    timg_init(4000000, 1000000);          /* 定时器3初始化 */</font>
  16. <font size="3">    while(1)</font>
  17. <font size="3">    {</font>
  18. <font size="3">        LED0_TOGGLE();</font>
  19. <font size="3">        vTaskDelay(200);</font>
  20. <font size="3">    }</font>
  21. <font size="3">}</font>
复制代码
该函数首先按顺序初始化两个定时器组的四个定时器,每个定时器被设置为不同的定时时间。具体实现通过timeout_callback回调函数处理定时器超时事件,根据定时器的组和ID执行不同的操作。这样可以灵活管理多个定时器的行为,满足不同的定时需求。

16.4 下载验证
程序下载完成后,我们可打开监视器查看各个定时器的操作任务,如下图所示。

第十六章 TIMG实验13161.png
图16.4.1 四个通用定时器运行消息
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-12-19 22:35

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表