一、功能需求

实现一个简单的功能:
让 ESP32 每天在固定的时间 自动打开电源(通电),到了设定时间后自动关闭电源(断电)。

比如:

  • 每天早上 7:00 自动打开电源
  • 每天晚上 17:00 自动关闭电源

这样就不用手动操作了。

开始前需要掌握的知识

面包版

我们在学习使用单片机的时候,电路是必须要用到的,而面包版和杜邦线就非常适合搭建电路

面板版的分为窄条宽条,面板包的外观如下图所式

image.png

窄条,外观的结构和功能如下

image.png

窄条上下两行之间电不连通。每 5 个插孔为一组,标注 + 的窄条一般接电源,- 接地。

宽条,外观的结构和功能如下

image.png

宽条上下两行之间电连通,左右不连通,每 5 个插孔为一组

杜邦线

杜邦线是一种用于电子制作中连接模块和板子的导线

杜邦线的线有线头为公线,无线头为母线

image.png

杜邦线的分类

名称用法
公对公(♂-♂)接两个母座(比如两个排针)
公对母(♂-♀)一头插排针,一头接传感器
母对母(♀-♀)接两个模块,或模块和传感器

image.png

LED

LED(Light Emitting Diode) 发光二极管 是一种能将电转换为光能的电子元器件,它具有单向导电性。

LED 是一个 二极管,具有方向性:

  • 阳极(长脚):接电源正极(VCC)
  • 阴极(短脚):接地(GND)
只有电流从正极流向负极时才会发光。

image.png

名称数值范围说明
最小点亮电流≈ 3mA一般来说 3mA 就能点亮 LED,但亮度较低
推荐电流5mA ~ 15mA常用范围,亮度适中且不会损伤 LED
最大安全电流20mA超过此值可能会缩短寿命甚至烧毁,通常不推荐长时间使用
导通压降≈ 1.7V发光时的两端电压(红色 LED 典型值)

点亮一个LED灯

名称
LED
1kΩ 电阻
面包板
杜邦线

image.png

功能如何实现?

ESP32 是一个联网的芯片,我们用它来:

  1. ESP32 连上 Wi-Fi,自动从网络上获取准确的时间;
  2. 你设置好“几点通电、几点断电”;
  3. 每分钟 ESP32 会查看一次当前时间;
  4. 到了设定时间,它就通过一个引脚输出 高电平(接通电源控制开关,比如继电器);
  5. 超过那个时间,它就输出 低电平,断开电源。

需要的设备

  • ✅ 一块 ESP32 开发板
  • ✅ 一个 继电器模块(用来控制电的开和关)
  • ✅ 一块 面包板(方便连接各个模块)
  • ✅ 若干 杜邦线(用来连接 ESP32 和继电器)
  • ✅ 三个 LED灯
  • ✅ 一条 USB 数据线(用于连接电脑上传程序)
  • ✅ 电源适配器(用于 ESP32 或继电器供电)
⚠️ 注意:控制220V电器,一定要查看继电器支持的电压,开发阶段可以使用低压设备进行测试

主要功能逻辑

主要引脚说明

ESP32 引脚编号功能说明
GPIO 12启动检测指示灯(程序启动时点亮)
GPIO 13Wi-Fi 连接成功指示灯
GPIO 14控制电源开关(控制继电器)
GND地线
3.3V 或 5V电源

image.png

完整代码

#include <WiFi.h>
#include "time.h"

#define LED_ESP32_BOOT 12 // esp32 启动检测 
#define LED_WIFI_SUCCESS 13 // wifi 连接成功 led 灯
#define LED_POWER_ON 14 // 定时开始时间

// wifi 设置
const char* ssid = "yunzhi";
const char* password = "yunzhi.club";

// 设置时区
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 8 * 3600;  // 东八区 (北京时间)
const int   daylightOffset_sec = 0;

// 开灯时间:07:00
const int ON_HOUR = 21;
const int ON_MIN = 57;

// 关灯时间:17:00
const int OFF_HOUR = 22;
const int OFF_MIN = 20;

void setup() {
  Serial.begin(9600);
  initPinMode();

  WiFi.disconnect(true);

  WiFi.begin(ssid, password);

  Serial.print("正在连接 Wi-Fi");

  // 检测是否连接 wifi 成功
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("连接成功");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  digitalWrite(LED_ESP32_BOOT, HIGH);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}

void loop() {
  struct tm timeinfo;

  if (getLocalTime(&timeinfo)) {
    int hour = timeinfo.tm_hour;
    int min = timeinfo.tm_min;
    
    Serial.printf("当前时间: %02d:%02d\n", hour, min);

    if (isInTimeRange(hour, min)) {
       Serial.println("开始时间");
       digitalWrite(LED_14, HIGH);
    } else {
       Serial.println("关闭时间");
       digitalWrite(LED_14, LOW);
    }
  }
  delay(60 * 1000); 
}

bool isInTimeRange(int hour, int min) {
  int current = hour * 60 + min;
  int onTime = ON_HOUR * 60 + ON_MIN;
  int offTime = OFF_HOUR * 60 + OFF_MIN;

  Serial.printf("当前 totalMin: %d, 开始 onTime: %d, 关闭 offTime: %d\n", current, onTime, offTime);
  return current >= onTime && current < offTime;
}

void initPinMode() {
  pinMode(LED_12,OUTPUT);
  pinMode(LED_13,OUTPUT);
  pinMode(LED_14,OUTPUT);
  digitalWrite(LED_ESP32_BOOT, HIGH);
}

常量定义与配置信息

#define LED_ESP32_BOOT 12 // esp32 启动检测 
#define LED_WIFI_SUCCESS 13 // wifi 连接成功 led 灯
#define LED_POWER_ON 14 // 是否通电

定义三个 GPIO 引脚,用于不同状态下的 LED 指示。

const char* ssid = "yunzhi";
const char* password = "yunzhi.club";

设置 Wi-Fi SSID 和密码。

const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;  // 东八区
const int daylightOffset_sec = 0;

配置 NTP 服务器与时区,适用于中国(UTC+8)。

const int ON_HOUR = 7;
const int ON_MIN = 0;
const int OFF_HOUR = 17;
const int OFF_MIN = 0;

设置控制通电的时间段为 7:00 到 17:00。

初始化函数

Serial.begin(9600);
pinMode(LED_ESP32_BOOT,OUTPUT);
pinMode(LED_WIFI_SUCCESS,OUTPUT);
pinMode(LED_POWER_ON,OUTPUT);
digitalWrite(LED_ESP32_BOOT, HIGH); // 点亮 LED_ESP32_BOOT 代表程已启动

启动串口,波特率为 9600,用于调试输出;设置三个 LED 引脚为输出模式;点亮 LED_ESP32_BOOT 代码程序已经启动

image.png

  WiFi.disconnect(true);           // 确保断开之前的连接
  WiFi.begin(ssid, password);      // 启动 Wi-Fi 连接

  Serial.print("正在连接 Wi-Fi");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

image.png

等待连接成功;
每 500ms 打印一个点来表示正在尝试连接。

Serial.println("连接成功");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

digitalWrite(LED_WIFI_SUCCESS, HIGH);  // Wi-Fi 连接成功,点亮 LED_13

连接成功后打印 IP;
点亮 LED_WIFI_SUCCESS 作为指示

image.png

主循环

void loop() {
  struct tm timeinfo;

  if (getLocalTime(&timeinfo)) {
    int hour = timeinfo.tm_hour;
    int min = timeinfo.tm_min;
    
    Serial.printf("当前时间: %02d:%02d\n", hour, min);

    if (isInTimeRange(hour, min)) {
       digitalWrite(LED_POWER_ON, HIGH);
    } else {
       digitalWrite(LED_POWER_ON, LOW);
    }
  }
  delay(60 * 1000); 
}

判断时间范围函数 isInTimeRange

bool isInTimeRange(int hour, int min) {
  int current = hour * 60 + min;
  int onTime = ON_HOUR * 60 + ON_MIN;
  int offTime = OFF_HOUR * 60 + OFF_MIN;

  Serial.printf("当前 totalMin: %d, 开始 onTime: %d, 关闭 offTime: %d\n", current, onTime, offTime);
  return current >= onTime && current < offTime;
}
  • 将时间全部转化为分钟数来进行比较;
  • 如果当前分钟数在开始和结束时间之间,返回true;

补充说明

“wokwi-relay-module” 是 Wokwi 平台(一个专注于 Arduino、ESP32 等开发板模拟器)的一个虚拟继电器模块,用来模拟实际中的继电器(relay)工作方式,常用于控制大功率设备如灯、电机等。

image.png

当 IN 为高电平时,继电器吸合,NO 与 COM 导通。
当 IN 为低电平时,继电器释放,NC 与 COM 导通。

image.png

参考地址

https://docs.geeksman.com/esp32/Arduino/01.esp32-arduino-intr...

https://wokwi.com/


kexb
593 声望31 粉丝