mirror of
https://github.com/DuRuofu/ESP32-Guide.git
synced 2026-10-02 22:22:53 +08:00
197 lines
7.5 KiB
C
197 lines
7.5 KiB
C
#include <stdio.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
#include "driver/gptimer.h"
|
|
#include "esp_log.h"
|
|
|
|
static const char *TAG = "gptimer";
|
|
|
|
typedef struct {
|
|
uint64_t event_count;
|
|
} example_queue_element_t;
|
|
|
|
// 定时器警报事件的回调函数(案例1)
|
|
// 三个参数:定时器句柄 timer、事件数据指针 edata 和用户数据指针 user_data。
|
|
static bool IRAM_ATTR example_timer_on_alarm_cb_v1(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
|
{
|
|
BaseType_t high_task_awoken = pdFALSE;
|
|
QueueHandle_t queue = (QueueHandle_t)user_data;
|
|
// 立即停止计时器
|
|
gptimer_stop(timer);
|
|
// 从事件数据中获取计数值,并将其存储在 example_queue_element_t 结构体变量 ele 的 event_count 字段中。
|
|
example_queue_element_t ele = {
|
|
.event_count = edata->count_value
|
|
};
|
|
//使用 xQueueSendFromISR() 函数将 ele 变量发送到队列中
|
|
xQueueSendFromISR(queue, &ele, &high_task_awoken);
|
|
// return whether we need to yield at the end of ISR
|
|
return (high_task_awoken == pdTRUE);
|
|
}
|
|
|
|
// 定时器警报事件的回调函数(案例2)
|
|
static bool IRAM_ATTR example_timer_on_alarm_cb_v2(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
|
{
|
|
BaseType_t high_task_awoken = pdFALSE;
|
|
QueueHandle_t queue = (QueueHandle_t)user_data;
|
|
// Retrieve count value and send to queue
|
|
example_queue_element_t ele = {
|
|
.event_count = edata->count_value
|
|
};
|
|
xQueueSendFromISR(queue, &ele, &high_task_awoken);
|
|
// return whether we need to yield at the end of ISR
|
|
return (high_task_awoken == pdTRUE);
|
|
}
|
|
|
|
// 定时器警报事件的回调函数(案例3:动态更新报警值)
|
|
static bool IRAM_ATTR example_timer_on_alarm_cb_v3(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
|
{
|
|
BaseType_t high_task_awoken = pdFALSE;
|
|
QueueHandle_t queue = (QueueHandle_t)user_data;
|
|
// Retrieve count value and send to queue
|
|
example_queue_element_t ele = {
|
|
.event_count = edata->count_value
|
|
};
|
|
xQueueSendFromISR(queue, &ele, &high_task_awoken);
|
|
// reconfigure alarm value
|
|
gptimer_alarm_config_t alarm_config = {
|
|
.alarm_count = edata->alarm_value + 1000000, // alarm in next 1s
|
|
};
|
|
gptimer_set_alarm_action(timer, &alarm_config);
|
|
// return whether we need to yield at the end of ISR
|
|
return (high_task_awoken == pdTRUE);
|
|
}
|
|
|
|
void app_main(void)
|
|
{
|
|
// 定义一个 example_queue_element_t 类型的变量 ele
|
|
example_queue_element_t ele;
|
|
//创建了一个长度为 10,每个元素大小为 example_queue_element_t 类型的队列,并将其赋值给 queue 变量。
|
|
QueueHandle_t queue = xQueueCreate(10, sizeof(example_queue_element_t));
|
|
if (!queue) {
|
|
ESP_LOGE(TAG, "创建队列失败");
|
|
return;
|
|
}
|
|
|
|
// 初始化定时器
|
|
ESP_LOGW(TAG, "创建分辨率为 1 MHz 的通用定时器句柄");
|
|
gptimer_handle_t gptimer = NULL;
|
|
gptimer_config_t timer_config = {
|
|
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
|
.direction = GPTIMER_COUNT_UP,
|
|
.resolution_hz = 1000000, // 1MHz, 1 tick=1us
|
|
};
|
|
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
|
|
|
|
// 注册定时器事件回调函数(警报事件的回调函数)
|
|
gptimer_event_callbacks_t cbs = {
|
|
.on_alarm = example_timer_on_alarm_cb_v1,
|
|
};
|
|
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
|
|
|
// 使能定时器
|
|
ESP_LOGI(TAG, "Enable timer");
|
|
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
|
|
|
// 设置定时器的周期为 1s(触发警报事件的目标计数值)
|
|
ESP_LOGI(TAG, "Start timer, stop it at alarm event");
|
|
gptimer_alarm_config_t alarm_config1 = {
|
|
.alarm_count = 1000000, // period = 1s
|
|
};
|
|
// 设置定时器的报警事件
|
|
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config1));
|
|
// 启动定时器
|
|
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
|
|
|
// 等待定时器报警事件(从队列中接收数据,接收到的数据将会存储在 &ele 中)
|
|
if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) {
|
|
ESP_LOGI(TAG, "Timer stopped, count=%llu", ele.event_count);
|
|
} else {
|
|
ESP_LOGW(TAG, "Missed one count event");
|
|
}
|
|
|
|
// 设置定时器的计数值(异步更新)
|
|
ESP_LOGI(TAG, "Set count value");
|
|
ESP_ERROR_CHECK(gptimer_set_raw_count(gptimer, 100));
|
|
ESP_LOGI(TAG, "Get count value");
|
|
|
|
// 获取定时器的计数值
|
|
uint64_t count;
|
|
ESP_ERROR_CHECK(gptimer_get_raw_count(gptimer, &count));
|
|
ESP_LOGI(TAG, "Timer count value=%llu", count);
|
|
|
|
//--------------------------------------------------------------------//
|
|
ESP_LOGW(TAG, "案例1结束,案例2开始");
|
|
//--------------------------------------------------------------------//
|
|
|
|
// 在更新报警回调之前,我们应该确保计时器没有处于启用状态
|
|
ESP_LOGI(TAG, "Disable timer");
|
|
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
|
// 设置一个新的回调函数
|
|
cbs.on_alarm = example_timer_on_alarm_cb_v2;
|
|
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
|
ESP_LOGI(TAG, "Enable timer");
|
|
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
|
|
|
// 重新设置报警条件
|
|
ESP_LOGI(TAG, "Start timer, auto-reload at alarm event");
|
|
gptimer_alarm_config_t alarm_config2 = {
|
|
.reload_count = 0,
|
|
.alarm_count = 1000000, // period = 1s
|
|
.flags.auto_reload_on_alarm = true, //报警事件发生后立即通过硬件重新加载计数值
|
|
};
|
|
// 设置定时器的报警事件
|
|
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config2));
|
|
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
|
|
|
// 循环次数为4次。在每次循环中,通过 xQueueReceive() 函数从队列中接收数据,并等待最多2秒。如果成功接收到数据,则打印定时器重新加载的消息
|
|
int record = 4;
|
|
while (record) {
|
|
if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) {
|
|
ESP_LOGI(TAG, "Timer reloaded, count=%llu", ele.event_count);
|
|
record--;
|
|
} else {
|
|
ESP_LOGW(TAG, "Missed one count event");
|
|
}
|
|
}
|
|
ESP_LOGI(TAG, "Stop timer");
|
|
ESP_ERROR_CHECK(gptimer_stop(gptimer));
|
|
|
|
ESP_LOGI(TAG, "Disable timer");
|
|
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
|
|
|
//--------------------------------------------------------------------//
|
|
ESP_LOGW(TAG, "案例2结束,案例3开始");
|
|
//--------------------------------------------------------------------//
|
|
// 案例3动态更新报警值
|
|
cbs.on_alarm = example_timer_on_alarm_cb_v3;
|
|
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
|
ESP_LOGI(TAG, "Enable timer");
|
|
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
|
|
|
ESP_LOGI(TAG, "Start timer, update alarm value dynamically");
|
|
gptimer_alarm_config_t alarm_config3 = {
|
|
.alarm_count = 1000000, // period = 1s
|
|
};
|
|
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config3));
|
|
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
|
record = 4;
|
|
while (record) {
|
|
if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) {
|
|
ESP_LOGI(TAG, "Timer alarmed, count=%llu", ele.event_count);
|
|
record--;
|
|
} else {
|
|
ESP_LOGW(TAG, "Missed one count event");
|
|
}
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Stop timer");
|
|
ESP_ERROR_CHECK(gptimer_stop(gptimer));
|
|
ESP_LOGI(TAG, "Disable timer");
|
|
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
|
ESP_LOGI(TAG, "Delete timer");
|
|
ESP_ERROR_CHECK(gptimer_del_timer(gptimer));
|
|
|
|
vQueueDelete(queue);
|
|
}
|