定时器中断

罗大富 BigRich大约 6 分钟ESP32Arduino

上一节我们介绍了 ESP32 的外部中断的使用,本节课介绍 ESP32 的定时器功能。

实验原理

定时器,顾名思义就是用来计时的,我们常常会设置计时或闹钟,然后时间到了就告诉我们要做什么。ESP32 也是这样,通过定时器可以完成各种预设好的任务。ESP32 定时器到达指定时间后也会产生中断,然后在回调函数内执行所需功能,这个和外部中断类似。

在 Arduino 中操控 ESP32 时,有 硬件定时器软件定时器 两种类型的定时器可供选择。它们具有不同的工作原理和用途。

硬件定时器 是 ESP32 芯片上的内置计时器,它们是专门设计用于定时和计时任务的硬件模块。硬件定时器可以通过设置特定的寄存器来配置和控制,通常具有更高的精确度和稳定性。它们不受软件的影响,可以在后台独立运行,不会受到其他代码的干扰。硬件定时器适用于需要高精度和实时性的定时任务,例如 PWM 输出、捕获输入脉冲等。

软件定时器 是通过编写代码在 Arduino 中模拟实现的定时器。它们不依赖于硬件模块,而是使用计数器变量来实现定时功能。软件定时器是基于延时循环的原理,在特定的时间间隔内执行特定的任务。但是,使用软件定时器时需要注意,它们可能会受到其他代码的影响而产生误差,特别是当涉及到需要精确时间控制的应用时,如通信协议处理、高速数据采集等。

硬件定时器和软件定时器各有优劣,具体选择取决于你的应用需求。如果需要高精度、实时性和稳定性,建议使用硬件定时器。如果时间精度要求不高,或者只需要基本的定时功能,可以使用软件定时器来简化代码编写。

需要注意的是,ESP32 具有 4 个硬件定时器,具体使用哪个定时器取决于你的需求和硬件资源的可用性。请参考 ESP32 的官方文档和相关库的文档以获取更详细的信息和使用示例。

硬件电路设计

物料清单(BOM 表):

材料名称数量
直插式 LED2
1kΩ 电阻2
杜邦线(跳线)若干
面包板1

LED 的正极接开发板的 D2、D4 引脚,并串联一个电阻,负极接 GND,如下图:

注意

一定要接电阻,不然会由于电流过大,烧坏 LED。

软件程序设计

1. 硬件定时器

在 ESP32 Arduino 开发环境中,可以使用以下几个库函数来配置和操作硬件定时器(Timer):

  1. void timerBegin(timer_num_t timer_num, uint32_t divider, bool count_up):初始化硬件定时器,参数说明:
  • timer_num:定时器编号,可选值为 0-3 等。
  • divider:定时器的分频系数,用于设置定时器的时钟频率。较大的分频系数将降低定时器的时钟频率。可以根据需要选择合适的值,一般设置为 80 即可;
  • count_up:指定定时器是否为向上计数模式。设置为 true 表示向上计数,设置为 false 表示向下计数。
  1. timerAttachInterrupt(hw_timer_t *timer, void (*isr)(void *), void *arg, int intr_type):用于将中断处理函数与特定的定时器关联起来,参数含义如下:
  • timer;定时器指针;
  • isr: 中断处理函数。
  • arg: 传递给中断处理函数的参数。
  • intr_type: 中断类型,可选值为 ture(边沿触发)或 false(电平触发)。
  1. timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload):用于设置定时器的计数值,即定时器触发的时间间隔,参数含义如下:
  • timer:定时器指针;
  • alarm_value: 定时器的计数值,即触发时间间隔;
  • autoreload: 是否自动重载计数值,可选值为 true(自动重载)或 false(单次触发)。
  1. timerAlarmEnable(hw_timer_t *timer):用于启动定时器,使其开始计数;
  2. timerAlarmDisable(hw_timer_t *timer):用于禁用定时器,停止计数;
  3. timerGetAutoReload(hw_timer_t *timer):获取定时器是否自动重新加载;
  4. timerAlarmRead(hw_timer_t *timer):获取定时器计数器报警值;
  5. timerStart(hw_timer_t *timer):计数器开始计数;
  6. timerStop(hw_timer_t *timer):计数器停止计数;
  7. timerRestart(hw_timer_t *timer):计数器重新开始计数,从 0 开始;
  8. timerStarted(hw_timer_t *timer):计数器是否开始计数。

以上是一些常用的硬件定时器相关的库函数,你可以根据自己的需求和定时器的特性,调用适当的函数来配置和操作硬件定时器。请参考 ESP32 的官方文档和相关库的文档,以获取更详细的信息。

使用硬件定时器的基本步骤如下:

  1. 初始化定时器:使用 timerBegin() 函数初始化所需的硬件定时器;
  2. 注册中断处理函数:使用 timerAttachInterrupt() 函数将中断处理函数与定时器关联起来;
  3. 设置定时器模式:使用 timerAlarmWrite(),设置触发一次,还是周期性触发;
  4. 启动定时器:使用 timerAlarmEnable() 函数启动定时器,使其开始计数。

因此,我们的代码可以这么写:

#define LED   2
#define LED_ONCE  4

hw_timer_t *timer = NULL;
hw_timer_t *timer_once=NULL;


// 定时器中断处理函数
void timer_interrupt(){
  digitalWrite(LED, !digitalRead(LED));
}

void timer_once_interrupt() {
  digitalWrite(LED_ONCE, !digitalRead(LED_ONCE));
}
 
void setup() {
  pinMode(LED, OUTPUT);
  pinMode(LED_ONCE, OUTPUT);

  // 初始化定时器
  timer = timerBegin(0,80,true);
  timer_once = timerBegin(1, 80, true);

  // 配置定时器
  timerAttachInterrupt(timer,timer_interrupt,true);
  timerAttachInterrupt(timer_once, timer_once_interrupt, true);

  // 定时模式,单位us,只触发一次
  timerAlarmWrite(timer,1000000,true); 
  timerAlarmWrite(timer_once, 3000000, false);
  // 启动定时器
  timerAlarmEnable(timer); 
  timerAlarmEnable(timer_once);
 
}
 
void loop() {
}

2. 软件定时器

使用软件计时器的时候,我们需要用到 ESP32 内置的库 TickerTicker 是 ESP32 Arduino 内置的一个定时器库,这个库用于规定时间后调用函数。

接着我们来看看 Ticker 库的一些方法

  • detach():停止 Ticker;
  • active():Ticker 是否激活状态,True 表示启用;
  • once(n, callback,arg):n 秒后只执行一次 callback 函数,arg 表示回调函数的参数(不写表示没有);
  • once_ms(n, callback,arg):n 毫秒后只执行一次 callback 函数,arg 表示回调函数的参数(不写表示没有);
  • attach(n, callback, arg):每隔 n 秒周期性执行;
  • attach_ms(n, callback, arg):每隔 n 毫秒周期性执行;

注意

不建议使用 Ticker 回调函数来阻塞 IO 操作(网络、串口、文件);可以在 Ticker 回调函数中设置一个标记,在 loop 函数中检测这个标记;


#include <Ticker.h>
 
#define LED 4
#define LED_ONCE 2


// 定义定时器对象
Ticker timer;
Ticker timer_once;


// 定义定时器中断回调函数
void toggle(int pin) {
  digitalWrite(pin, !digitalRead(pin));
}
 

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(LED_ONCE, OUTPUT);

  // 配置周期性定时器
  timer.attach(0.5, toggle, LED);
  // 配置一次性定时器
  timer_once.once(3, toggle, LED_ONCE);
}
 
void loop() {
  
}

上次编辑于:
贡献者: Luo