ESP32 网络计时器,包含自动保存

简介

本代码是基于ESP32开发板实现的一个计时器功能,具备倒计时、计时器时长选择、显示当前时间、有源蜂鸣器报警等功能。代码中使用了WiFi网络连接、NTP时间同步、EEPROM存储等功能。通过按钮控制计时器的开始、停止和计时器时长的选择。

运行原理概述

在ESP32开发板上,使用了三个按钮,分别为开始计时按钮(BUTTON1)、停止计时按钮(BUTTON2)和计时器时长选择按钮。首先连接WiFi网络,同步NTP时间,并初始化OLED屏幕。

然后通过setdefaulttime()函数设置计时器默认时长,并初始化按钮引脚。

在主循环中通过checkTimerButtons()函数检测按钮状态,若按钮被按下,根据按钮类型执行相应的操作。如果开始计时按钮被按下,则开始计时,并在OLED屏幕上显示计时器倒计时时间。

如果停止计时按钮被按下,则停止计时,并根据按钮状态执行相应的操作。如果计时器时长选择按钮被按下,则切换计时器时长,并在OLED屏幕上显示新的计时器时长。

特色功能

1.具备倒计时功能,可以按照设定的计时器时长进行倒计时,到时后有报警提示。

2.计时器时长可以选择,用户可以根据需求选择不同的计时器时长。

3.通过WiFi网络连接和NTP时间同步功能,保证了计时器的时间准确性。

4.使用EEPROM存储功能,保存计时器时长选择的状态,即使重新上电,也能保留上一次的时长选择状态。

重要函数的解释

  1. void setdefaulttime()函数:设置计时器默认时长,并从EEPROM中读取上一次的时长选择状态。

  2. void checkTimerButtons()函数:检测按钮状态,并根据按钮类型执行相应的操作。

  3. void updateTimeDisplay()函数:更新OLED屏幕上的时间和计时器倒计时时间。

  4. bool saveIntToEEPROM(int value, int address)函数:将整数值存储到EEPROM中。

  5. int readIntFromEEPROM(int address)函数:从EEPROM中读取整数值。

ESP32开发板引脚硬件设备引脚连接方式
GPIO21OLED_SDAI2C数据线
GPIO22OLED_SCLI2C时钟线
GPIO35BUTTON1按钮输入
GPIO34BUTTON2按钮输入
GPIO32BUZZER_PIN有源蜂鸣器引脚
3.3VOLED_VCCOLED显示屏电源
GNDOLED_GNDOLED显示屏电源和地
3.3VBUTTON1按钮电源
3.3VBUTTON2按钮电源
GNDBUTTON1按钮电源和地
GNDBUTTON2按钮电源和地

#include <WiFi.h>
#include <NTPClient.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <EEPROM.h>
#define OLED_ADDR 0x3C // OLED屏幕地址
#define OLED_SDA 21    // ESP32开发板上的SDA引脚
#define OLED_SCL 22    // ESP32开发板上的SCL引脚
#define BUTTON1 35     // 开始计时按钮
#define BUTTON2 34     // 停止计时按钮
#define BUZZER_PIN 32  // 有源蜂鸣器连接的引脚
#define MAXMENU 5
#define ADDR_1 1
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp.ntsc.ac.cn"); // NTP客户端
Adafruit_SSD1306 display(128, 64, &Wire, -1);   // OLED屏幕
int menuvalue = 1;
// 计时器相关变量
unsigned long startTime = 0; // 计时器开始时间
unsigned long stopTime = 0; // 计时器停止时间
bool timerRunning = false; // 是否正在计时
unsigned long duration = 0; // 计时器持续时间
unsigned long remainingTime = 0; // 剩余时间

// 时间显示相关变量
String lastFormattedTime = ""; // 上次更新的时间
unsigned long lastUpdateTime = 0; // 上次更新时间的时间戳
// 默认倒计时时间
int defaulttime = 5*60*1000;
// 设置默认倒计时时间
void setdefaulttime();

bool saveIntToEEPROM(int value, int address) {
  EEPROM.begin(16);
  EEPROM.put(address, value);
  bool success = EEPROM.commit();
  EEPROM.end();
     display.setCursor(0, 50);
    display.setTextSize(1);
  if(success)
  {
    display.println("Save Success");
  }
  else 
  {
    display.println("Failed");
  }
  
  Serial.print("save menuvalue:");
  Serial.println(value);
  return success;
}

int readIntFromEEPROM(int address) {
  if (EEPROM.begin(16)) {
    int value;
    if (EEPROM.get(address, value)) {
      EEPROM.end();
      return value;
    } else {
      Serial.println("Failed to read from EEPROM");
    }
  } else {
    Serial.println("EEPROM initialization failed");
  }
  EEPROM.end();
  return 0;
}

unsigned long timerDuration = 5 * 60 * 1000;  // 初始计时器长度为5分钟
 
 //frequency参数是需要发出的声音频率,单位为Hz;duration参数是发出声音的持续时间,单位为毫秒。
void buzz(int frequency, long duration)
{
  int period = 1000000 / frequency; // 计算周期
  int pulse = period / 2; // 计算脉冲时间

  for (long i = 0; i < duration * 1000L; i += period)
  {
    digitalWrite(BUZZER_PIN, HIGH); // 发送高电平
    delayMicroseconds(pulse); // 持续脉冲时间的一半
    digitalWrite(BUZZER_PIN, LOW); // 发送低电平
    delayMicroseconds(pulse); // 持续脉冲时间的一半
  }
}
void checkTimerButtons()
{
  if (digitalRead(BUTTON1) == LOW && !timerRunning)
  {
    // 开始计时器
    buzz(2000, 100);
    startTime = millis();
    timerRunning = true;
  }
  if (digitalRead(BUTTON2) == LOW)
  {
    buzz(2000, 100);
    
    if (timerRunning)
    {
      // 停止计时器
      stopTime = millis();
      timerRunning = false;
      remainingTime = timerDuration - (stopTime - startTime);
      while(digitalRead(BUTTON2) == LOW);
      delay(100);
    }
    else
    {
      // 切换计时器时间长度
      if (menuvalue == 1)
      {
        timerDuration = 10 * 60 * 1000;
        menuvalue =2;
      }
      else if (menuvalue == 2)
      {
        timerDuration = 30 * 60 * 1000;
        menuvalue=3;
      }
      else if (menuvalue==3)
      {
        timerDuration = 60 * 60 * 1000;
        menuvalue=4;
      }
      else if (menuvalue ==4)
      {
        timerDuration = 5 * 60 * 1000;
        menuvalue = 1;
      }
      remainingTime = timerDuration;
      defaulttime = timerDuration;
      saveIntToEEPROM(menuvalue,ADDR_1);
      while(digitalRead(BUTTON2) == LOW);
    }
  }
}

void setdefaulttime()
{
  menuvalue = readIntFromEEPROM(ADDR_1);
  Serial.print("read menuvalue:");
  Serial.println(menuvalue);
  if (menuvalue>0&&menuvalue<=MAXMENU)
  {
    switch(menuvalue)
    {
      case 1:
      defaulttime = 5 * 60 * 1000;
      break;
      case 2:
      defaulttime = 10 * 60 * 1000;
      break;
      case 3:
      defaulttime = 30 * 60 * 1000;
      break;
      case 4:
      defaulttime = 60 * 60 * 1000;
      break;
      default:
      defaulttime = 5 * 60 * 1000;
      break;
    }
  }
  else
  {
    menuvalue = 1;
    saveIntToEEPROM(menuvalue,ADDR_1);
  defaulttime = 5 * 60 * 1000;
  }
  remainingTime = defaulttime;
  
}
void updateTimeDisplay()
{
  timeClient.update();
  String formattedTime = timeClient.getFormattedTime();
  display.clearDisplay();
  display.setCursor(0, 0);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.println(formattedTime);

  if (timerRunning)
  {
    duration = millis() - startTime;
    remainingTime = timerDuration - duration;

    display.setCursor(0, 36);
    display.setTextSize(4);
    int minutes = remainingTime / 1000 / 60;
    int seconds = (remainingTime / 1000) % 60;
    if (minutes < 10)
    {
      display.print("0");
    }
    display.print(minutes);
    display.print(":");
    if (seconds < 10)
    {
      display.print("0");
    }
    display.println(seconds);
  }
  else
  {
    display.setCursor(0, 36);
    display.setTextSize(4);
    int _minutes = remainingTime / 1000 / 60;
    int _seconds = (remainingTime / 1000) % 60;
    if (_minutes < 10)
    {
      display.print("0");
    }
    display.print(_minutes);
    display.print(":");
    if (_seconds < 10)
    {
      display.print("0");
    }
    display.println(_seconds);
  }

  display.display();
}



void setup()
{
  // 连接WiFi网络
   pinMode(BUZZER_PIN, OUTPUT);
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); 
  Serial.begin(115200);
  Wire.begin(OLED_SDA, OLED_SCL);
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();
  display.setCursor(0, 0);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println("Connecting to ");
  display.println("360WiFi-016C34");
  display.println("Password: ");
  display.println("wangjinxuan");
  display.display();
  WiFi.begin("360WiFi-016C34", "wangjinxuan");
  int i = 0;
  while (WiFi.status() != WL_CONNECTED && i < 10)
  {
    delay(500);
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Connecting");
    for (int j = 0; j < i; j++)
    {
      display.print(".");
    }
    display.display();
    i++;
  }
  if (WiFi.status() != WL_CONNECTED)
  {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Failed to connect.");
    display.display();
    while (true)
    {
      // 连接失败,停止程序
    }
  }

  // 初始化OLED屏幕
  Wire.begin(OLED_SDA, OLED_SCL);
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();

  //初始化数值
  setdefaulttime();

  // 初始化按钮引脚
  pinMode(BUTTON1, INPUT_PULLUP);
  pinMode(BUTTON2, INPUT_PULLUP);

  // 同步时间
  timeClient.begin();
  timeClient.setTimeOffset(28800); // 设置时区(这里为东八区)
}


void loop()
{
  checkTimerButtons();
  updateTimeDisplay();
  if (timerRunning)
  {
    duration = millis() - startTime;
    remainingTime = timerDuration - duration;
    if (remainingTime <= 0 || remainingTime>timerDuration)
    {
      // 计时器已完成
      timerRunning = false;
      buzz(2000,1000);
      delay(800);
      buzz(2000,1000);
      delay(800);
      buzz(2000,1000);
      delay(800);
      remainingTime = timerDuration;
      // TODO: 执行计时器完成操作
    }
  }
}

ESP32 是一款基于 ESP8266 或 ESP32-S系列的嵌入式微控制器,广泛用于物联网(IoT)项目中。它内置了丰富的功能,包括计时器,可用于精确控制电机的运动。电机控制通常依赖于脉冲宽度调制(PWM)信号,因为电机的工作是根据接收到的电压占空比来调整转速。 下面是使用ESP32的Timer控制电机的基本步骤: 1. **初始化Timer**: - 首先,你需要选择一个合适的Timer(如Timer0、Timer1等),配置它的工作模式(比如模式3,即PWM模式)和分频器值。 2. **设置PWM通道**: - 在Timer配置完成后,为电机控制的GPIO口设置成PWM输出模式,并设置其作为Timer的输出通道。 3. **编写定时器回调函数**: - 创建一个回调函数,当Timer到达预设的时间间隔时会自动调用。这个函数负责改变PWM的占空比,从而控制电机的速度或方向。 ```c void timerCallback(void *arg) { int dutyCycle = calculateMotorSpeed(); // 根据当前状态计算 dutyCycle ESP32Timer->SetPulseWidth(dutyCycle); } void setup() { // Timer初始化 TimerHandle_t timer = xTimerCreate("MotorTimer", ...); // 设置回调函数 xTimerAttach(timerCallback, ...); // 启动Timer xTimerStart(timer, 0); } ``` 4. **电机速度计算**: - `calculateMotorSpeed()`函数可以根据你的需求来调整,比如接收外部输入、计数器递增等来计算适当的dutyCycle值。 5. **停止或重启Timer**: - 当需要停止或改变电机运动时,可以通过关闭或重新启动Timer来控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值