- 本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途。如有不对之处,请留言,本人及时更改。
一 前言:
- 博文开始前,小徐共勉在简书上面阅读的一篇好文里面的句子,发现自己自律于写技术分享帖了。
我从来不相信什么懒洋洋的自由。我向往的自由是通过勤奋和努力实现的更广阔的人生,那样的自由才是珍贵的,有价值的;我相信一万小时定律,我从来不相信天上掉馅饼的灵感和坐等的成就。做一个自由又自律的人,靠势必实现的决心认真地活着。
——山本耀司
- 好了,转入主题了!定时器在单片机中最为常见的了,那么本篇就为大家介绍下
ESP32
的定时器,总的来说,分为2种运行模式: - 定时器以自动重载来运行: 字面上意思是会不断地根据一个时间数值来间隔地发生中断触发回调事件!
- 定时器以单次模式来运行: 定时器仅仅运行一次!
二 官方提供的API
接口说明:
- 官方的定时器文档各个版本对定时器的介绍有所不同,我这是根据目前
2015/5/22
最新版的定时器来介绍给大家怎么使用,在esp32
的定时功能,也可以用rtos
的定时!
官方对定时器的说明:https://esp-idf.readthedocs.io/en/latest/api-reference/system/esp_timer.html
- ①:创建一个定时的函数
esp_timer_create()
- 第一个参数是
定时器
结构体,第二个是定时器返回的句柄! - 返回值是也是一个结构体类型的
esp_err_t
。
- ②:开始执行定时器有2个方法,一个是执行单次的
esp_timer_start_once()
和周期性执行的esp_timer_start_periodic()
, 虽然传入的参数的类型都为一样,但是传入参数含义有所不一样哦! -
esp_timer_start_once()
的传参含义分别是:句柄 ,第二个是:这个时间后将触发的事件回调; -
esp_timer_start_periodic()
的传参含义分别是:句柄 ,第二个是:每次触发的事件回调的时间间隔;
- ③:对于您要暂停和删除定时器,官方提供了下面2个方法:
- 暂停定时器:
esp_timer_stop()
:停止一个定时器操作,不管是执行单次的还是重复性执行的!形参是定时器的句柄! - 删除定时器:
esp_timer_delete()
:删除一个定时器,记得必须要先暂停定时器哦!形参是定时器的句柄!
- ③:官方还提供了这么一个方法
esp_timer_get_time()
:获取定时器运行到现在的当前时间间隔,返回数值是微秒单位的:
三 代码实现:
- 上面说了这么多理论知识,现在开始敲写代码啦!是不是有点兴奋!
第一步:定义2个定时器的句柄和2和定时器结构体:
//定义2个定时器句柄
esp_timer_handle_t test_p_handle = 0;
esp_timer_handle_t test_o_handle = 0;
//定义一个单次运行的定时器结构体
esp_timer_create_args_t test_once_arg = { .callback = &test_timer_once_cb, //设置回调函数
.arg = NULL, //不携带参数
.name = "TestOnceTimer" //定时器名字
};
//定义一个周期重复运行的定时器结构体
esp_timer_create_args_t test_periodic_arg = { .callback =
&test_timer_periodic_cb, //设置回调函数
.arg = NULL, //不携带参数
.name = "TestPeriodicTimer" //定时器名字
};
第二步:定义2个定时器的回调函数,其中周期性回调的函数执行LED闪烁!
void test_timer_periodic_cb(void *arg) {
int64_t tick = esp_timer_get_time();
printf("方法回调名字: %s , 距离定时器开启时间间隔 = %lld \r\n", __func__, tick);
if (tick > 100000000) {
//停止定时器工作,并获取是否停止成功
esp_err_t err = esp_timer_stop(test_p_handle);
printf("要停止的定时器名字:%s , 是否停止成功:%s", test_periodic_arg.name,
err == ESP_OK ? "ok!\r\n" : "failed!\r\n");
err = esp_timer_delete(test_p_handle);
printf("要删除的定时器名字:%s , 是否停止成功:%s", test_periodic_arg.name,
err == ESP_OK ? "ok!\r\n" : "failed!\r\n");
}
//低电平
gpio_set_level(16, 0);
//延迟
vTaskDelay(1000 / portTICK_PERIOD_MS);
//高电平
gpio_set_level(16, 1);
//延迟
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
void test_timer_once_cb(void *arg) {
int64_t tick = esp_timer_get_time();
printf("方法回调名字: %s , 距离定时器开启时间间隔 = %lld \r\n", __func__, tick);
esp_err_t err = esp_timer_delete(test_o_handle);
printf("要删除的定时器名字:%s , 是否停止成功:%s", test_periodic_arg.name,
err == ESP_OK ? "ok!\r\n" : "failed!\r\n");
}
第三步:创建定时器,并且定义2个定时器的回调函数:
//GPIO16初始化
gpio_pad_select_gpio(16);
gpio_set_direction(16, GPIO_MODE_OUTPUT);
//开始创建一个重复周期的定时器并且执行
esp_err_t err = esp_timer_create(&test_periodic_arg, &test_p_handle);
err = esp_timer_start_periodic(test_p_handle, 1000 * 1000);
printf("重复周期运行的定时器创建状态码: %s", err == ESP_OK ? "ok!\r\n" : "failed!\r\n");
//开始创建一个单次周期的定时器并且执行
err = esp_timer_create(&test_once_arg, &test_o_handle);
err = esp_timer_start_once(test_o_handle, 10 * 1000 * 1000);
printf("单次运行的定时器创建状态码: %s", err == ESP_OK ? "ok!\r\n" : "failed!\r\n");