ESP32-定时器(timer)

概述

ESP32 内置 4 个 64-bit 通用定时器。每个定时器包含一个 16-bit 预分频器和一个 64-bit 可自动重新加载向上/向下计数器。

• 16-bit 时钟预分频器,分频系数为 2-65536
• 64-bit 时基计数器
• 可配置的向上/向下时基计数器:增加或减少
• 暂停和恢复时基计数器
• 报警时自动重新加载
• 当报警值溢出/低于保护值时报警
• 软件控制的即时重新加载
• 电平触发中断和边沿触发中断

名词扫盲

16-bit 预分频器:分频就是把系统工作频率分频后当做定时器的工作频率,例如系统时钟为12MHz,12分频后定时器的dao工作时钟为1MHz。
分频示意图
按照ESP32的输入时钟频率为80MHZ,换句话说也就是1/80us=0.0125us就会计数加一,如何我们设置分频系数为80,则1us就会计数加一。分频系数范围是0-65536

64-bit 时基计数器:这个更简单,就是累加计数器,按照输出时钟,每过一个’波‘就加一。它的计数范围是0-0xFFFF FFFF FFFF FFFF,非常大大大大大的数。

Arduino层编程

在Arduino编程时因为无需考虑寄存器的设置,我们只需记住该外设的配置思路即可~
定时器的配置思路:

  1. 选择定时器(两组四个)
  2. 配置合适分频系数
  3. 绑定中断函数
  4. 配置报警计数器保护值
  5. 开启报警

其中我们还可以随时停止定时器、停止报警、重启、重设等等……

1、开启定时器

hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp);

timer(选择定时器):0-3 divider(分频系数):0-65536 countUp:是否为向上计数
代码中可以看出,程序执行了该语句后,定时器立即按照默认状态开始了工作。

hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
    if(num > 3){
        return NULL;
    }
    hw_timer_t * timer = &hw_timer[num];
    if(timer->group) {
        DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
        DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
        TIMERG1.int_ena.val &= ~BIT(timer->timer);
    } else {
        DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
        DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
        TIMERG0.int_ena.val &= ~BIT(timer->timer);
    }
    timer->dev->config.enable = 0;
    timerSetDivider(timer, divider);
    timerSetCountUp(timer, countUp);
    timerSetAutoReload(timer, false);
    timerAttachInterrupt(timer, NULL, false);
    timerWrite(timer, 0);
    timer->dev->config.enable = 1;
    addApbChangeCallback(timer, _on_apb_change);
    return timer;
}

2、停止定时器

直接调用,即用即停,效果显著。

void timerEnd(hw_timer_t *timer){
    timer->dev->config.enable = 0;
    timerAttachInterrupt(timer, NULL, false);
    removeApbChangeCallback(timer, _on_apb_change);
}

3、设置定时器(细化)

void timerSetConfig(hw_timer_t *timer, uint32_t config);
uint32_t timerGetConfig(hw_timer_t *timer);

提供了可以更细化的配置内容,这里不做详解。

4、开启中断

void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
void timerDetachInterrupt(hw_timer_t *timer);

绑定中断函数

5、配置报警计数器保护值

void timerAlarmWrite(hw_timer_t *timer, uint64_t interruptAt, bool autoreload);

timer:目标定时器 interruptAt:报警保护值 autoreload:是否开启自动重载

配置好上面后,使能报警:

bool timerAlarmEnabled(hw_timer_t *timer);

6、杂七杂八

懒得逐一介绍~

void timerStart(hw_timer_t *timer);
void timerStop(hw_timer_t *timer);
void timerRestart(hw_timer_t *timer);
void timerWrite(hw_timer_t *timer, uint64_t val);
void timerSetDivider(hw_timer_t *timer, uint16_t divider);
void timerSetCountUp(hw_timer_t *timer, bool countUp);
void timerSetAutoReload(hw_timer_t *timer, bool autoreload);

bool timerStarted(hw_timer_t *timer);
uint64_t timerRead(hw_timer_t *timer);
uint64_t timerReadMicros(hw_timer_t *timer);
double timerReadSeconds(hw_timer_t *timer);
uint16_t timerGetDivider(hw_timer_t *timer);
bool timerGetCountUp(hw_timer_t *timer);
bool timerGetAutoReload(hw_timer_t *timer);

uint64_t timerAlarmRead(hw_timer_t *timer);
uint64_t timerAlarmReadMicros(hw_timer_t *timer);
double timerAlarmReadSeconds(hw_timer_t *timer);

例子(模拟看门狗)

当GPIO接地超过3s,系统判断程序跑飞,强制重启。

**#include <Arduino.h>
const int button = 0;         //  按键用于触发延时
const int wdtTimeout = 3000;  //  看门狗时间(ms)
hw_timer_t *timer = NULL;

void IRAM_ATTR resetModule() { // 中断函数
  Serial.println("reboot\n");
  esp_restart();
}

void setup() {
  Serial.begin(9600);
  Serial.println();
  Serial.println("running setup");

  pinMode(button, INPUT_PULLUP);                    
  timer = timerBegin(0, 80, true);                  // 选择timer0,分频系数为80,向上计数
  timerAttachInterrupt(timer, &resetModule, true);  // 绑定中断函数
  timerAlarmWrite(timer, wdtTimeout * 1000, false); // 设置报警保护函数
  timerAlarmEnable(timer);                          // 使能报警器
}

void loop() {
  Serial.println("running main loop");

  timerWrite(timer, 0); // 重置定时器,喂狗 (feed watchdog)
  long loopTime = millis();
  // 当按键被按着超过了3秒,看门狗重启程序
  while (!digitalRead(button)) {
    Serial.println("button pressed");
    delay(500);
  }
  delay(1000); 
  loopTime = millis() - loopTime;
  
  Serial.print("loop time is = ");
  Serial.println(loopTime);
}
  • 15
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Arduino ESP32-C3板(ESP32-C3 DevKitM)有多个硬件定时器,可以用来生成精确定时的信号,例如PWM信号、定时采样等。在这里,我们将介绍如何在Arduino ESP32-C3板上使用硬件定时器来生成PWM信号。 步骤1:引入头文件 首先,需要在Arduino IDE中引入ESP32-C3的头文件,其中包含了定时器相关的函数和常量。 #include <esp32-hal-timer.h> 步骤2:配置定时器 在Arduino ESP32-C3板上,有四个硬件定时器可供使用,分别为TIMER0、TIMER1、TIMER2和TIMER3。在使用定时器之前,需要先进行配置。以下是一个示例代码段,用于配置TIMER0。 void initTimer0() { // 配置TIMER0为PWM模式 timerAttach(TIMER0, 0, true); timerSetMode(TIMER0, TIMER_PWM_MODE, 1); timerSetFrequency(TIMER0, 1000); timerSetDuty(TIMER0, 0, 50); // 开始TIMER0 timerAlarmEnable(TIMER0); } 在上述代码中,我们首先使用timerAttach()函数将TIMER0与GPIO0引脚绑定,然后使用timerSetMode()函数将其设置为PWM模式。接下来,使用timerSetFrequency()函数设置PWM频率为1000Hz,然后使用timerSetDuty()函数设置PWM占空比为50%。最后,使用timerAlarmEnable()函数启动TIMER0。 步骤3:控制PWM输出 完成定时器的配置后,可以使用timerWrite()函数来控制PWM输出。以下是一个示例代码段,用于控制TIMER0输出PWM信号。 void loop() { for (int i = 0; i <= 100; i++) { timerWrite(TIMER0, i); delay(10); } } 在上述代码中,我们使用一个for循环来逐步增加PWM占空比,从0到100。每次循环使用timerWrite()函数来设置PWM占空比,然后使用delay()函数延时10毫秒。 总结 在Arduino ESP32-C3板上使用硬件定时器可以生成精确的PWM信号,用于控制各种设备和传感器。在使用定时器时,需要注意配置定时器的模式、频率和占空比。同时,也需要注意控制PWM输出的时序,以保证信号的稳定性和准确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值