ESP32之ESP-IDF学习笔记3——通用定时器(led闪烁/按键取抖)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

记录一下,对知识的整理和复习,方便你我他。。。
只是记录的外设的API函数的使用,外设知识不介绍。
IDF版本V5.1.2

一、需要的头文件

#include "driver/gptimer.h"

二、API

/*
函数: gptimer_new_timer
功能: 创建一个新的通用定时器,并返回句柄
输入: config:定时器的配置项;ret_timer:返回的句柄
返回值: 
*/
esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer);

/*
函数: gptimer_register_event_callbacks
功能: 注册回调函数
输入: timer:gptimer句柄;cbs:回调函数组;user_data:用户数据
返回值: 
*/
esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data);

/*
函数: gptimer_enable
功能: 使能gptimer
输入: timer:gptimer句柄;
返回值: 
*/
esp_err_t gptimer_enable(gptimer_handle_t timer);

/*
函数: gptimer_disable
功能: 失能gptimer
输入: timer:gptimer句柄;
返回值: 
*/
esp_err_t gptimer_disable(gptimer_handle_t timer);

/*
函数: gptimer_set_alarm_action
功能: 设置GPTimer的告警事件动作。
输入: timer:gptimer句柄;config:配置项
返回值: 
*/
esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config);

/*
函数: gptimer_start
功能: 启动gptimer
输入: timer:gptimer句柄;
返回值: 
*/
esp_err_t gptimer_start(gptimer_handle_t timer);

/*
函数: gptimer_stop
功能: 停止gptimer
输入: timer:gptimer句柄;
返回值: 
*/
esp_err_t gptimer_stop(gptimer_handle_t timer);

三、GPTIMER初始化

这样配置之后会周期性的进入中断

/*
函数: TimerInit
功能: 初始化一个定时器
参数:
    hz:定时器的频率
    count:计数值
*/
gptimer_handle_t TimerInit(gptimer_handle_t gptimer, int hz, int count)
{
    //配置定时器
    gptimer_config_t timer_config = {
        .clk_src = GPTIMER_CLK_SRC_DEFAULT,//时钟源
        .direction = GPTIMER_COUNT_UP,//计数方向
        .resolution_hz = hz, // 1MHz, 1 tick=1us
        .intr_priority = 0,//中断等级,如果为0会分配一个较低的中断等级(1~3)
    };
    ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));//创建一个新的通用定时器,并返回句柄

    //创建回调函数组,并写入回调函数
    gptimer_event_callbacks_t cbs = {
        .on_alarm = gptimer_isr_handler,
    };
    //注册回调函数,第一次调用这个函数需要在使能 gptimer 之前。
    //并且更换回调函数的时候需要,先失能 gptimer,如果是第一次则不需要否则会报错
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));

    //使能 gptimer
    ESP_ERROR_CHECK(gptimer_enable(gptimer));

    //配置定时的计数值
    gptimer_alarm_config_t alarm_config = {
        .alarm_count = count,
        .reload_count = 0,
        .flags.auto_reload_on_alarm = true,
    };
    //设置GPTimer的告警事件动作。
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
    //启动GPTimer
    ESP_ERROR_CHECK(gptimer_start(gptimer));

    return gptimer;
}

四、定时器实现led的周期性亮灭

  1. timer.c文件内容
#include "timer.h"
#include "driver/gptimer.h"
#include "esp_attr.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "led.h"

int status = 0;

gptimer_handle_t time1;

static bool IRAM_ATTR gptimer_isr_handler(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
    BaseType_t high_task_awoken = pdFALSE;
    // stop timer immediately
    //gptimer_stop(timer);
    
    if(status == 1) status = 0;
    else status = 1;
    gpio_set_level(LED0_GPIO, status);

    return (high_task_awoken == pdTRUE);
}

gptimer_handle_t TimerInit(gptimer_handle_t gptimer, int hz, int count)
//省略上面有
  1. timer.h文件内容
#ifndef __TIMER_H
#define __TIMER_H
#include "driver/gptimer.h"

extern gptimer_handle_t time1;
gptimer_handle_t TimerInit(gptimer_handle_t gptimer, int hz, int count);
#endif
  1. main.c文件
#include <stdio.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "timer.h"

char *TAG = "main";

void app_main(void)
{
    esp_log_level_set(TAG, ESP_LOG_DEBUG); //设置日志等级
    Led_init();
    KeyExtiInit();
    time1 = TimerInit(time1, 1000000, 1000000);

    while(1)
    {
        vTaskDelay(500);   
    }
}

五、用定时器来消抖

思路:
跟在上面的TimerInit后,使用函数 TimerChangeKeyDelay() ,可以把定时器设置成不自动装载。并且在中断服务函数中即时关断。
key使用外部中断,触发外部中断后开启定时器,此时经过TimerChangeKeyDelay函数定时器的报警事件为20ms。当定时器中断触发后,判段key引脚的值,如外部中断配置的是下降延,就判断是否为低。我这里是配置的是上升沿,所以是高。

  1. timer.c文件追加的内容
static bool IRAM_ATTR gptimer_isr_handler_key(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
    BaseType_t high_task_awoken = pdFALSE;
    // stop timer immediately
    gptimer_stop(timer);
    
    if(gpio_get_level(KEY) == 1)
    {
        if(status == 1) status = 0;
        else status = 1;
        gpio_set_level(LED0_GPIO, status);
    }
    return (high_task_awoken == pdTRUE);
}

void TimerChangeKeyDelay(gptimer_handle_t gptimer)
{
	//我载使用的时候已经启动了所以这里要先关闭,否则会出错
    gptimer_stop(gptimer);
    //创建回调函数组,并写入回调函数
    gptimer_event_callbacks_t cbs = {
        .on_alarm = gptimer_isr_handler_key,
    };
    //注册回调函数,第一次调用这个函数需要在使能 gptimer 之前。
    //并且更换回调函数的时候需要,先失能 gptimer
    ESP_ERROR_CHECK(gptimer_disable(gptimer));
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));

    //使能 gptimer
    ESP_ERROR_CHECK(gptimer_enable(gptimer));

    //配置定时的计数值
    gptimer_alarm_config_t alarm_config = {
        .alarm_count = 20000,
        .reload_count = 0,
        .flags.auto_reload_on_alarm = false,
    };
    //设置GPTimer的告警事件动作。
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
}
  1. main.c文件
#include <stdio.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "led.h"
#include "keyexti.h"
#include "timer.h"

char *TAG = "main";

void app_main(void)
{
    uint64_t count = 0;
    uint32_t f = 0;
    esp_log_level_set(TAG, ESP_LOG_DEBUG); //设置日志等级
    Led_init();
    KeyExtiInit();
    time1 = TimerInit(time1, 1000000, 1000000);

    while(1)
    {
        if(!f)
        {
            if(count > 10)
            {
                TimerChangeKeyDelay(time1);
                f = 1;
            }
            else count++;
        }
        vTaskDelay(500);   
    }
}

六、补充

  1. gptimer_disable函数如果在定时器没使能的情况下使用,会有DbugLog报错。
    在这里插入图片描述

  2. gptimer_handle_t 申请的是个指针。
    gptimer_handle_t time1;
    time1 = gptimer_handle_t TimerInit(time1, int hz, int count);
    如果我这个函数内部不返回time1,则执行完后time1还是NULL;
    没有想到很好的办法,求大佬知道。

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值