ESP32S3学习——通用定时器补充,附官方示例,带自己理解的注释

芯片:esp32s3

开发环境:espidfv4.4

一、问题

1)最开始有个疑问,关于多久进一次中断的问题,因为串口打印值和想个不一样,如图。后来想明白了

 

group【0】为自动重装载,3s计时间隔,为什么打印值不是3?

原因:到达计数值->自动重装载|进入中断->arr=0->中断中arr已经在计数->counter不为零

所以,是定时器达到计数值进入中断,对于group【0】是3s

2)消息队列,自己理解

  • //main中创建消息队列

  • s_timer_queue = xQueueCreate(10, sizeof(example_timer_event_t));
  • //whilie中接收队列信息,信息来自中断回调

  • xQueueReceive(s_timer_queue, &evt, portMAX_DELAY);
  • 中断中

  • //创建结构体:储存定时器信息等

  • example_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
    
    };

  • //从中断中返回信息到while

  • xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);
  • BaseType_t high_task_awoken = pdFALSE;该位保证队列接受到数据

二、例程效果

group【0】:自动重装载,3s计时,计时间隔有该参数确定

timer_interval_sec * TIMER_SCALE:计时间隔定时器时钟(系统时钟,apb80M/预分频5=16M)3故为3s

group【1】;没有自动重装载,在中断中更新arr,即报警值,没5秒触发,串口打印的为累加时间

三、官方示例加注释

/* General Purpose Timer example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.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)  // convert counter value to seconds

typedef struct {
    int timer_group;
    int timer_idx;
    int alarm_interval;
    bool auto_reload;
} example_timer_info_t;

/**
 * @brief A sample structure to pass events from the timer ISR to task
 *
 */
typedef struct {
    example_timer_info_t info;
    uint64_t timer_counter_value;
} example_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)
{
    //54位计数值
    printf("Counter: 0x%08x%08x\r\n", (uint32_t) (counter_value >> 32),
           (uint32_t) (counter_value));
           //将计数值转化为时间
    printf("Time   : %.8f s\r\n", (double) counter_value / TIMER_SCALE);
}
//定时器中断回调,参数为自定义的结构体
static bool IRAM_ATTR timer_group_isr_callback(void *args)
{
    BaseType_t high_task_awoken = pdFALSE;
    //接收参数
    example_timer_info_t *info = (example_timer_info_t *) args;
    //获取当前定时器的计数值
    uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(info->timer_group, info->timer_idx);

    /* Prepare basic event data that will be then sent back to task */
    //创建结构体:储存定时器信息等
    example_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) {
        //此函数针对group【1】,计数位累加计数,5s打印->10s->15s
        //在报警后(计数达到arr,进行重装载)

        timer_counter_value += info->alarm_interval * TIMER_SCALE;
        timer_group_set_alarm_value_in_isr(info->timer_group, info->timer_idx, timer_counter_value);
    }

    /* Now just send the event data back to the main program task */
    //从中断中返回信息到while
    xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);

    return high_task_awoken == pdTRUE; // return whether we need to yield at the end of ISR
}

/**
 * @brief Initialize selected timer of timer group
 *
 * @param group Timer Group number, index from 0
 * @param timer timer ID, index from 0
 * @param auto_reload whether auto-reload on alarm event
 * @param timer_interval_sec interval of alarm
 */
static void example_tg_timer_init(int group, int timer, bool auto_reload, int timer_interval_sec)
{
    /* Select and initialize basic parameters of the timer */
    timer_config_t config = {
        .divider = TIMER_DIVIDER,
        .counter_dir = TIMER_COUNT_UP,
        .counter_en = TIMER_PAUSE,
        .alarm_en = TIMER_ALARM_EN,
        .auto_reload = auto_reload,
    }; // default clock source is APB
    timer_init(group, timer, &config);

    /* Timer's counter will initially start from value below.
       Also, if auto_reload is set, this value will be automatically reload on alarm */
    timer_set_counter_value(group, timer, 0);

    /* Configure the alarm value and the interrupt on alarm. */
    timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
    timer_enable_intr(group, timer);
    //初始化队列信息
    example_timer_info_t *timer_info = calloc(1, sizeof(example_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_group_isr_callback:注册的回调函数
    //timer_info:传入回调的参数
    timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info, 0);
//开启定时器
    timer_start(group, timer);
}

void app_main(void)
{
    //创建消息队列
    s_timer_queue = xQueueCreate(10, sizeof(example_timer_event_t));
    //初始化定时器
    example_tg_timer_init(TIMER_GROUP_0, TIMER_0, true, 3);
    example_tg_timer_init(TIMER_GROUP_1, TIMER_0, false, 5);

    while (1) {
        //自定义的结构体,包含定时器等信息
        example_timer_event_t evt;
        //接收队列信息
        xQueueReceive(s_timer_queue, &evt, portMAX_DELAY);

        /* Print information that the timer reported an event */
        //当前定时器组带有自动重装载
        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);

        /* Print the timer values passed by event */
        printf("------- EVENT TIME --------\n");
        //进入中断时的计数器计数值
        print_timer_counter(evt.timer_counter_value);

        /* Print the timer values as visible by this task */
        printf("-------- TASK TIME --------\n");
        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);
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值