提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
记录一下,对知识的整理和复习,方便你我他。。。
只是记录的外设的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的周期性亮灭
- 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)
//省略上面有
- 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
- 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引脚的值,如外部中断配置的是下降延,就判断是否为低。我这里是配置的是上升沿,所以是高。
- 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));
}
- 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);
}
}
六、补充
-
gptimer_disable函数如果在定时器没使能的情况下使用,会有DbugLog报错。
-
gptimer_handle_t 申请的是个指针。
gptimer_handle_t time1;
time1 = gptimer_handle_t TimerInit(time1, int hz, int count);
如果我这个函数内部不返回time1,则执行完后time1还是NULL;
没有想到很好的办法,求大佬知道。