一、 简介
- 获取时间戳
- 周期性任务
本文主要内容参考 官网API文档
本文主要代码参考 来自这里
ESP32-C3 有2个定时器组,每个组有2个定时器,共有4个定时器。
每组定时器包括一个普通定时器和一个看门狗定时器。
在 timer_types.h 里可以看到结构体的定义:
typedef enum {
TIMER_GROUP_0 = 0, /*!
每个通用硬件定时器都是基于16位预分频器和64位自动重载功能的向上/向下计数的64位通用定时器。
二、使用步骤
- 资源分配
- 设置和获取计数器值
- 设置报警动作
- 注册事件回调函数
- 使能或禁用定时器
- 启动和停止定时器
其它的操作有:
三、操作函数
1. 基本操作
(1)定时器实例gptimer_handle_t
(2) 定时器配置结构体gptimer_config_t
使用结构体 gptimer_config_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 r e s o l u t i o n _ h z \\frac {1} {resolution_hz} resolution _hz1
- gptimer_config_t::intr_shared 设置是否将定时器中断源标记为共享源。
示例:
// 配置定时器,默认时钟源: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:则相反
};
(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_t gptimer = NULL;
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 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_disable
4. 启动和停止定时器
(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)
typedef struct {
// 定时器组号
int timer_group;
// 定时器序号
int timer_idx;
// 报警时间
int alarm_interval;
// 是否自动重装
bool auto_reload;
} timer_info_t;
// 定义一个示例结构体
typedef struct {
// 定时器的参数
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
*/
static void inline print_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
*/
static bool 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);
// 将定时器中断响应的定时器赋予结构体变量evt
timer_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 间隔
*/
static void timer_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);
}
void app_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);
}
}
运行结果:
====== Timer Group without auto reload ======
------ Group[1], timer[0] alarm event ------
[ evt.timer_counter_value ] Counter: 0x0000000002faf089 Time : 10.00000180 s
[timer.timer_counter_value] Counter: 0x0000000002fb43ab Time : 10.00425820 s
====== Timer Group without auto reload ======
------ Group[1], timer[0] alarm event ------
[ evt.timer_counter_value ] Counter: 0x0000000005f5e112 Time : 20.00000360 s
[timer.timer_counter_value] Counter: 0x0000000005f632f5 Time : 20.00419620 s
如果 timer_config_start函数的auto_reload设置为true,则输出示例:
可以看到达到报警值后,计数器值会还原。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
硬件
+关注
关注
11文章
2922浏览量
64764 -
分频器
+关注
关注
43文章
433浏览量
49312 -
定时器
+关注
关注
23文章
3147浏览量
112034 -
函数
+关注
关注
3文章
3868浏览量
61308 -
ESP32-C3
+关注
关注
0文章
9浏览量
278
发布评论请先 登录
相关推荐
ESP32-C3——专为物联网应用场景设计
解决方案,搭载低功耗WiFi+蓝牙二合一模组ESP32-C3,外连机智云AIoT云平台,实现APP控制端、精准控温、异常报警、设备联动、超温保护、离水断电等功能,内控传感器,精简硬件结构设计,降低
发表于 05-09 15:37
求助,esp32-c3不支持pcnt吗?
我在esp32-c3开发板上测试pcnt,编译报错找不到相关的函数,查看sdk源码发现要配置CONFIG_SOC_PCNT_SUPPORTED才会编译pcnt.c,查看examples里面的项目也说了只支持ESP32 和
发表于 02-15 06:47
ESP32-C3没有芯片ID是正常的吗?
我正在使用 ESP32-C3-DevKitM1。'esptool chip_id' 报告“警告:ESP32-C3 没有芯片 ID。改为读取 MAC。” 这是正常的吗?如果不是,是否可以将其强制设置为
发表于 02-28 09:13
请问ESP32-C3需要外接flash芯片吗?
我最近使用 ESP32-C3 MCU 而不是 SOC 制作了定制 PCB。由于尺寸限制,我没有包括 SOC 原理图上显示的外部闪存芯片。所以我的问题是 ESP32-C3 是否需要外部闪存芯片?或者
发表于 02-28 06:36
如何使用ESP32-C3 SOC进行硬件设计呢?
我是 ESP32 产品线的忠实粉丝。我有丰富的经验,从开发工具包开始,通过各种模块。我有一个不需要 SOC或 WiFi 功能的新项目,我正在考虑使用 ESP32-C3 SOC。除了 IC 数据表,我
发表于 03-01 08:19
ESP32-C3和时钟以及i2c_set_timeout的错误问题如何解决?
使用示例和文档。https://github.com/lucafaccin/esp-pn532我也遇到了 ESP32-C3 和时钟以及 i2c_set_timeout 的错误,我解决了但我不确
发表于 03-02 07:34
请问ESP32-C3是否支持使用ESP32 Host?
1.我看到ESP32 Hosted器件列表上没有ESP32-C3的型号,请问目前是否已经支持?2.若支持,ESP32-C3与ESP32是不是一样的使用方法?或者有哪些点需要注意
发表于 03-13 06:03
ESP32-C3的编程方式
1.说明
ESP32-C3采用的是RISCV架构的芯片,目前又专注RISCV研究,所以特此来研究一下这个芯片的使用情况。
该芯片的主要特性如下:
采用RSCV-V 32位的单核处理器,四级流水线
发表于 08-16 06:57
ESP32-C3芯片的性价比有多高
今天小明为大家捋一捋ESP32-C3性价比到底有多高呢?很多在说乐鑫急着发布ESP32-C3和ESP32-S3,是在布一个大局,到底在布啥局呢?
发表于 04-28 09:52
•4684次阅读
ESP32-C3模组芯片的功能特性
重磅消息来喽!本月乐鑫esp32驱动86面板,esp32-C3 +2.4寸彩屏,esp32- C3+1.3寸圆屏 QSPI即将出品!一颗mcu搞定WIFI蓝牙和驱动彩屏,而且ESP32-C3
发表于 06-03 11:22
•1766次阅读
ESP32 之 ESP-IDF 教学(三)——通用硬件定时器(Timer)
ESP32 之 ESP-IDF 学习笔记(三)【通用硬件定时器(Timer)】文章目录ESP32 之 E
发表于 11-26 11:36
•37次下载
评论