定时器是指从指定的时刻开始,经过一个指定时间触发超时事件,按类型分为硬件定时器和软件定时器。
硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。
软件定时器是由底层系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受硬件定时器资源限制的定时器服务,它实现的功能与硬件定时器也是类似的。
ESP32 Arduino开发框架内的定时器类

其中SwTimer为软件定时器,封装了FreeRTOS中的timer相关函数;
HwTimer为硬件定时器,封装了Arduino-ESP32中内置的Ticker库;
下面用两个例子来说明定时器的使用
从 https://gitee.com/billyzh/esp32-cpp-lesson 下载本教程的源码到本地硬盘文件夹,如d:\esp32-cpp-lesson
在VSCode中,选择【文件】->【打开文件夹...】选择上一步保存的文件夹打开
打开项目后,选择config.h文件,修改第10行为
#define APP_LESSON61_A 1
打开unit6-lesson61a/app_config.h文件,设置启用软件定时器,
#define CONFIG_USE_SW_TIMER 1
打开unit6-lesson61a/board_config.h文件,设置LED使用的引脚,
#define BUILTIN_LED_PIN GPIO_NUM_4
配置启用GpioLed
#define CONFIG_USE_LED_GPIO 1
创建LED实例,代码如下(unit6-lesson61a/my_board.cpp):
MyBoard::MyBoard() : Board() {
Log::Info(TAG, "===== Create Board ...... =====");
Log::Info(TAG, "initial led.");
led_ = new GpioLed(BUILTIN_LED_PIN, false);
Log::Info( TAG, "===== Board config completed. =====");
}
程序很简单,就是创建一个GpioLed实例。
控制LED闪烁
控制代码如下(unit6-lesson61a/my_application.cpp):
void MyApplication::OnInit() {
// 创建定时器
timer1_ = TimerFactory::CreateTimer("timer1");
timer1_->Start(1000, [this]() {
Blink();
});
}
void MyApplication::Blink() {
Led *led = Board::GetInstance().GetLed();
if (state_==0) {
led->TurnOn();
state_ = 1;
} else {
led->TurnOff();
state_ = 0;
}
}
程序解读
1. 在OnInit方法中使用TimerFactory类创建定时器,然后启动定时器,时间间隔为1000ms,回调函数为Lambda表达式,最终调用Blink成员函数;
2. 在Blink方法中先获取Led实例,然后根据state_变量的值打开或关闭LED,以实现闪烁效果;
与前面小节在Loop方法中使用delay来实现LED闪烁相比,使用定时器类似于多任务并行执行,更加灵活,也可避免在Loop方法中处理太多功能。
编译项目并上传开发板检验
打开项目后,选择config.h文件,修改第10行为
#define APP_LESSON61_B 1
打开unit6-lesson61b/app_config.h文件,设置启用软件定时器,
#define CONFIG_USE_SW_TIMER 1
打开unit6-lesson61b/board_config.h文件,设置LED使用的引脚,
#define BUILTIN_LED_PIN GPIO_NUM_4
配置启用GpioLed
#define CONFIG_USE_LED_GPIO 1
创建LED实例,代码如下(unit6-lesson61b/my_board.cpp):
MyBoard::MyBoard() : Board() {
Log::Info(TAG, "===== Create Board ...... =====");
Log::Info(TAG, "initial led.");
led_ = new GpioLed(BUILTIN_LED_PIN, false);
Log::Info( TAG, "===== Board config completed. =====");
}
程序很简单,就是创建一个GpioLed实例。
定时器任务
控制代码如下(unit6-lesson61b/my_application.cpp):
void MyApplication::OnInit() {
// 创建定时器
timer1_ = TimerFactory::CreateTimer("timer1");
timer1_->Start(1000, [this]() {
Timer1Task();
});
timer2_ = TimerFactory::CreateTimer("timer2");
timer2_->Start(500, [this]() {
Timer2Task();
});
}
void MyApplication::Timer1Task() {
Log::Info(TAG, "Time1Task execute.");
Led *led = Board::GetInstance().GetLed();
if (state_==0) {
led->TurnOn();
state_ = 1;
} else {
led->TurnOff();
state_ = 0;
}
}
void MyApplication::Timer2Task() {
Log::Info(TAG, "Time2Task execute...");
// 执行时间大于定时器时间(500s)
delay(600);
}
程序解读
1. 在OnInit方法中使用TimerFactory类创建两个定时器,然后启动定时器;
2. 在Timer1Task方法中实现LED闪烁效果;
3. 在Timer2Task方法中延时600ms;
编译项目并上传开发板检验
使用定时器的初衷是可以实现一些复杂的定时任务,但是实际上使用xTimerStart得到的实例只能处理一些简单的任务,I/O,数据的运算。注意有一些操作会导致回调函数不执行,如刷新IIC接口的屏幕,在本框架中,可以使用Schedule方法将操作调度到事件循环中执行。
定时任务的规则其实是按照绝对时间来启用任务的,但是如果回调函数运行时长超时,也会一直运行到正常结束。这样子程序是稳定了,但是会不会按照意愿进行就不能保证了。
举个例子:定时任务500ms执行一次,但是任务执行1ms。这是非常复合预期的结果。事实上就是每500ms运行一次。如果任务执行时间为600ms。则在600ms时任务就会变为就绪状态。600ms任务执行完成,则会直接再次执行任务。

在多任务应用中,单纯的使用定时器,很有可能造成一些不可估量的后果。如果存在两个任务都定时为50ms,但是运行时间都是30ms。则会出现两个任务每30ms交替运行一次。一次循环就是60ms。和预期的50ms出现了不符。如果再极端一点,任务执行时间为100ms,则一次循环就是200ms,若任务优先级不一样,则时间一直会被高优先级的任务独占,低优先级的无法运行。
本开发框架中需要定时执行的任务都是使用的Timer类,如Sensor类(传感器)就是使用Timer来定时获取传感器数据并传递到Application中进行后续处理。
例1中的LED闪烁,可直接调用Led类的Blink方法来实现,Blink方法内部使用Timer类来实现闪烁效果。
作业
1.修改示例程序使用硬件定时器(HwTimer)
2.在使用HwTimer时,观察任务执行时间超过定时间隔时的触发情况
GPIO 是指单片机(微控制器)主板上的一组引脚,这些引脚可以发送或接收电信号,但它们不是为任何特定目的而设计的,这就是为什么它们被称为“通用”IO。
本文本介绍配置飞书机器人为MimiClaw的一个输入/输出端,和添加一个控制WS2812与LED的控制技能。
一块 30 块钱的开发板 + 一个大模型 API,就能做出可以听懂人话的智能硬件。 本文记录完整安装过程和踩坑经验,确保你跟着做就能跑通。
本文将从手绘架构图入手,逐层拆解 MimiClaw 的分层设计、核心模块、数据流转与底层实现,带你解剖这只“智能虾”的技术骨架,看懂在 C 语言加持下,AI 智能体如何以可穿戴设备的形态,在你身边稳稳运行、离线服务、主动响应。
本文介绍如何在不脱离 ArduinoIDE 可视化开发的前提下,通过一个名为 platform.local.txt 的小文件,实现对 ESP32 编译流程的精准控制。
本文将系统分析程序体积增长的五大根源,并提供经过验证的优化方案,帮助减小固件大小。
本文所DIY的语音助手设备端使用的是MicroPython、服务端是Python,对于很多开发者来说MicroPython入门没难度。
本小节使用音频开发框架实现一个音频录制到文件的示例。
I2S协议通过BCLK、LRCLK和DATA三线精准传输音频数据,但时序边沿、帧格式、时钟源等细节常引发噪声或断连。本文详解ESP32的I2S实现,从协议原理到ESP-IDF v5.x代码配置,助你避开常见陷阱,确保音频稳定传输。
本小节介绍音频的基础知识、音频开发框架和AudioCodec的简介,用一个音频播放示例来说明音频管道的使用。
MimiClaw是基于ESP32-S3芯片的超轻量级AI助手,通过Telegram或WebSocket提供Claude/GPT智能服务。