ESP-C3入门5. 使用通用计时器(esp3806)

2023-03-04 18:29:11

 

一、 简介ESP32-C3硬件定时器分辨率高,一般可用于:获取时间戳周期性任务本文主要内容参考 官网API文档本文主要代码参考 来自这里ESP32-C3 有2个定时器组,每个组有2个定时器,共有4个定时器。

每组定时器包括一个普通定时器和一个看门狗定时器在 timer_types.h 里可以看到结构体的定义:typedefenum { TIMER_GROUP_0 = 0, /*!

#if SOC_TIMER_GROUPS > 1 TIMER_GROUP_1 = 1, /*!

每个通用硬件定时器都是基于16位预分频器和64位自动重载功能的向上/向下计数的64位通用定时器二、使用步骤资源分配设置和获取计数器值设置报警动作注册事件回调函数使能或禁用定时器启动和停止定时器其它的操作有:。

电源管理IRAM安全线程安全Kconfig 设置选项三、操作函数1. 基本操作(1)定时器实例gptimer_handle_t(2) 定时器配置结构体gptimer_config_t使用结构体 gptimer_config_t

来创建定时器实例, gptimer_config_t 结构体的属性值:gptimer_config_t::clk_src 选择定时器的时钟源,枚举值: gptimer_clock_source_tgptimer_config_t::direction 设置定时器的计数方向,枚举值:

gptimer_count_direction_tgptimer_config_t::resolution_hz 设置内部计数器的分辨率,计数器滴答一次用时秒数为:1 r e s o l u t i o n _ h z \frac {1} {resolution\_hz}

resolution_hz1gptimer_config_t::intr_shared 设置是否将定时器中断源标记为共享源示例:// 配置定时器,默认时钟源:APBtimer_config_t config = { .divider = TIMER_DIVIDER, 。

//定时器预分频;esp32-c3的APB_CLK=80MHz,80MHz/TIMER_DIVIDER(16)=5MHz .counter_dir = TIMER_COUNT_UP,

//计数器向上计数,从0开始 .counter_en = TIMER_PAUSE, //计数器暂时中止 .alarm_en = TIMER_ALARM_EN,

//定时器警报使能 .auto_reload = auto_reload, //1:定时器硬件在警报事件后自动重装载;0:则相反 };(3) 定时器初始化timer_init()

示例: /* * 函数功能:初始化和配置定时器 * group_num:定时器分组值, 从0开始 * timer_num:定时器序号,从0开始 【一组定时器包含:普通定时器,看门狗定时器】

* *config: 定时器配置结构体 */ timer_init(group, timer, &config);(3) 设置定时器初值timer_set_counter_value()

示例:// 设置定时器值,如果设置了auto_reload,则报警后会也会重置为此值 timer_set_counter_value(group, timer, 0);(4)设置报警值timer_set_alarm_value()

示例:// 设置报警值、使能中断ISR timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);(5)使用定时器timer_enable_intr()

示例:// 使能定时器组(group)、定时器x(timer)中断 timer_enable_intr(group, timer);(6) 定时器添加ISR中断回调timer_isr_callback_add()

示例:// 定时器添加ISR中断回调函数timer_info_t *timer_info = calloc(1, sizeof(timer_info_t)); timer_info->timer_group = group; timer_info->timer_idx = timer; timer_info->auto_reload = auto_reload; timer_info->alarm_interval = timer_interval_sec; timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info,

0);//???(7)启动定时器timer_start()示例:timer_start(group, timer);(8) 获取定时器值timer_get_counter_value()示例:uint64_t

task_counter_value; // 获取定时器组,中定时器,的计数器的值; timer_get_counter_value(evt.info.timer_group, evt.info.timer_idx, &task_counter_value);

2. 其它操作(1) 创建新定时器gptimer_new_timer()示例: 创建分辨率为1 MHz 的通用定时器:gptimer_handle_tgptimer=NULL;gptimer_config_t

timer_config={.clk_src=GPTIMER_CLK_SRC_DEFAULT,.direction=GPTIMER_COUNT_UP,.resolution_hz=1*1000*1000

,//1MHz,1tick=1us};ESP_ERROR_CHECK(gptimer_new_timer(&timer_config,&gptimer));(2) 设置和获取计数值gptimer_get_raw_count()

gptimer_get_raw_count 用来获取计数值创建计数器后,内部计数器将默认重置为0计数值重置时,将会从新值计数计数值达最大值后将重置,最大值与SOC宏: SOC_TIMER_GROUP_COUNTER_BIT_WIDTH。

有关3. 使能和禁用定时器(1)使能gptimer_enable()此函数功能:将定时器驱动的状态从init切换为enable如果gptimer_register_event_callbacks() 已经延迟安装中断服务,此函数将使能中断服务

如果选择了特定的时钟源,此函数将获取适当的电源管理锁(2)禁用gptimer_disable4. 启动和停止定时器(1)启动gptimer_start()(2)停止gptimer_stop()四、示例程序。

#include"freertos/FreeRTOS.h"#include"freertos/queue.h"#include"driver/timer.h"#define TIMER_DIVIDER (16)

// Hardware timer clock divider// 计数值转为秒#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER)

typedefstruct {// 定时器组号int timer_group; // 定时器序号int timer_idx; // 报警时间int alarm_interval;

// 是否自动重装bool auto_reload; } timer_info_t; // 定义一个示例结构体typedefstruct {// 定时器的参数timer_info_t info;

// 计数器值uint64_t timer_counter_value; } timer_event_t; // 主程序接收报警数据的队列static xQueueHandle s_timer_queue;

/* * A simple helper function to print the raw timer counter value * and the counter value converted to seconds */

staticvoidinlineprint_timer_counter(uint64_t counter_value){ printf("Counter: 0x%08x%08x \t", (uint32_t

) (counter_value >> 32), (uint32_t) (counter_value)); printf("Time : %.8f s\r\n", (double) counter_value / TIMER_SCALE); }

/** * 报警回调函数 * @param args timer_info_t结构体 * @return */staticbool IRAM_ATTR timer_group_isr_callback

(void *args){ // 计算回调函数返回值 BaseType_t high_task_awoken = pdFALSE; timer_info_t *info = (timer_info_t

*) args; // 在ISR中获取计数器值uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(info->timer_group, info->timer_idx);

// 将定时器中断响应的定时器赋予结构体变量evttimer_event_t evt = { .info.timer_group = info->timer_group, .info.timer_idx = info->timer_idx, .info.auto_reload = info->auto_reload, .info.alarm_interval = info->alarm_interval, .timer_counter_value = timer_counter_value };

// 定时器组中的定时器,是否有自动重载if (!info->auto_reload) { timer_counter_value += info->alarm_interval * TIMER_SCALE;

// 重置定时器组中定时器的时间间隔(定时器自身的时间间隔) timer_group_set_alarm_value_in_isr(info->timer_group, info->timer_idx, timer_counter_value); }

// 以队列形式把数据发送到主函数,消息存储在结构体evt中// high_task_awoken 用于接收返回值 xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);

return high_task_awoken == pdTRUE; } /** * @brief 初始化定时器 * * @param group 定时器组序号,从0开始 * @param timer timer ID, 从0开始 * @param auto_reload 是否自动重载 * @param timer_interval_sec 间隔 */

staticvoidtimer_config_start(int group, int timer, bool auto_reload, int timer_interval_sec){ // 配置定时器,默认时钟源:APB

timer_config_t config = { .divider = TIMER_DIVIDER, //定时器预分频;esp32-c3的APB_CLK=80MHz,80MHz/TIMER_DIVIDER(16)=5MHz

.counter_dir = TIMER_COUNT_UP, //计数器向上计数,从0开始 .counter_en = TIMER_PAUSE,

//计数器暂时中止 .alarm_en = TIMER_ALARM_EN, //定时器警报使能 .auto_reload = auto_reload,

//1:定时器硬件在警报事件后自动重装载;0:则相反 }; /* * 函数功能:初始化和配置定时器 * group_num:定时器分组值, 从0开始 * timer_num:定时器序号,从0开始 【一组定时器包含:普通定时器,看门狗定时器】 * *config: 定时器配置结构体 */

timer_init(group, timer, &config); // 设置定时器值,如果设置了auto_reload,则报警后会也会重置为此值 timer_set_counter_value(group, timer,

0); // 设置报警值、使能中断ISR timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);

// 使能定时器组(group)、定时器x(timer)中断 timer_enable_intr(group, timer); // 定时器添加ISR中断回调函数timer_info_t

*timer_info = calloc(1, sizeof(timer_info_t)); timer_info->timer_group = group; timer_info->timer_idx = timer; timer_info->auto_reload = auto_reload; timer_info->alarm_interval = timer_interval_sec; timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info,

0);//???// 启动定时器 timer_start(group, timer); } voidapp_main(void){ // xQueueCreate是freeRTOS宏,用于创建队列实例

s_timer_queue = xQueueCreate(10, sizeof(timer_event_t)); // 配置定时器组1,中的定时器0,无自动重装,间隔是5s timer_config_start(TIMER_GROUP_1, TIMER_0,

false, 10); while (1) { timer_event_t evt; // 等待队列事件,时间是永远等待 xQueueReceive(s_timer_queue, &evt, portMAX_DELAY);

// 定时器组自动重装if (evt.info.auto_reload) { printf("====== Timer Group with auto reload ======\n"

); } else { printf("====== Timer Group without auto reload ======\n"); }

printf("------ Group[%d], timer[%d] alarm event ------\n", evt.info.timer_group, evt.info.timer_idx);

// 打印事件上报的计数器值printf("[ evt.timer_counter_value ] "); print_timer_counter(evt.timer_counter_value);

// 直接从定时器获取计数器值printf("[timer.timer_counter_value] "); uint64_t task_counter_value; // 获取定时器组,中定时器,的计数器的值;

timer_get_counter_value(evt.info.timer_group, evt.info.timer_idx, &task_counter_value); print_timer_counter(task_counter_value); } }

运行结果:======TimerGroupwithoutautoreload======------Group[1],timer[0]alarmevent------[evt.timer_counter_value

]Counter:0x0000000002faf089Time :10.00000180s[timer.timer_counter_value]Counter:0x0000000002fb43abTime :

10.00425820s======TimerGroupwithoutautoreload======------Group[1],timer[0]alarmevent------[evt.timer_counter_value

]Counter:0x0000000005f5e112Time :20.00000360s[timer.timer_counter_value]Counter:0x0000000005f632f5Time :

20.00419620s

如果 timer_config_start函数的auto_reload设置为true,则输出示例:

可以看到达到报警值后,计数器值会还原。


以上就是关于《ESP-C3入门5. 使用通用计时器(esp3806)》的全部内容,本文网址:https://www.7ca.cn/baike/1546.shtml,如对您有帮助可以分享给好友,谢谢。
标签:
声明

排行榜