实战案例:打造会 “报时 + 提醒” 的智能音箱(含完整代码,100 元内搞定)

一、开篇:新手也能做的智能音箱 —— 核心功能 + 低成本方案

你是不是想过:“能不能自己做个智能音箱,不用连 WiFi,就能整点报时、设置喝水提醒?”

其实不用复杂模块!今天用 ESP32 + 时钟模块 + 离线 TTS 方案,实现两大核心功能:

✅ 整点报时:比如 “现在是下午 3 点整”;

✅ 按键设置提醒:按一下按键,设置 “10 分钟后提醒喝水”,到点自动播报;

全套零件成本≤100 元,不用焊接,面包板直插,代码复制就能跑,新手 3 小时内搞定!

二、工具清单(淘宝可搜,100 元内封顶)

零件名称

型号推荐

淘宝搜索关键词

价格范围

核心作用

说明书获取渠道

ESP32 开发板

ESP32-WROOM-32

ESP32 开发板 带排针

30-50 元

核心控制(读时间 + 触发播报)

乐鑫官网→Espressif ESP32 Datasheet

离线 TTS 模块

SYN6288(带功放)

SYN6288 TTS 模块

15-25 元

文本转语音(报时 / 提醒内容)

科大讯飞开放平台→搜索 “SYN6288 用户手册”

DS3231 实时时钟模块

DS3231(带电池)

DS3231 RTC 模块 备用电池

10-15 元

提供精准时间(掉电不丢时间)

CSDN 搜 “DS3231  datasheet”

轻触按键

6×6mm 四脚按键

轻触按键 6×6mm

5 元 / 10 个

设置提醒(触发时间录入)

淘宝卖家详情页(无需复杂说明书)

微型喇叭

4Ω 1W

4Ω 1W 小喇叭 带线

8-12 元

发声载体

淘宝卖家详情页

锂电池 + 充电模块

11.1V 18650(可选)

18650 锂电池 充电模块

20-30 元

便携供电(脱离插电使用)

淘宝卖家详情页

面包板 + 杜邦线

400 孔面包板 + 公对母

面包板 杜邦线 套装

10-15 元

连接零件(不用焊接)

无需说明书

选型理由:

  • 用 DS3231 而非软件计时:避免 ESP32 掉电后时间重置,报时更精准;
  • 选带电池的 RTC 模块:断电后仍能保存时间,下次上电直接用;
  • 锂电池供电:可做成便携音箱,放床头、书桌都方便(若不用便携,用 USB 供电也行)。

三、核心功能逻辑拆解(先懂原理,再动手)

1. 整点报时逻辑

graph TD

A[DS3231实时时钟] --> B[ESP32每10秒读取时间]

B --> C{是否到整点?(如14:00:00)}

C -- 是 --> D[调用SYN6288播报“现在是下午2点整”]

C -- 否 --> B

  • 关键:ESP32 通过 I2C 接口读 DS3231 的时间,判断 “分钟 = 0 且秒 = 0” 时触发报时;
  • 优化:加 “上午 / 下午” 判断(比如 13 点→下午 1 点),符合日常习惯。

2. 按键设置提醒逻辑

graph TD

A[按下轻触按键] --> B[ESP32检测到按键触发]

B --> C[读取当前时间+设置提醒间隔(如10分钟)]

C --> D[计算提醒时间(当前+10分钟)]

D --> E[存储提醒时间到EEPROM(掉电不丢)]

E --> F[ESP32循环对比当前时间vs提醒时间]

F -- 时间一致 --> G[调用SYN6288播报“提醒您喝水啦!”]

F -- 不一致 --> F

  • 关键:用 EEPROM 存储提醒时间,避免 ESP32 断电后提醒失效;
  • 优化:加按键防抖(避免按一次触发多次),提醒后自动清除已完成的提醒。

四、分步骤实操:接线→代码→测试

(一)第一步:硬件接线(表格 + 文字说明,零焊接)

核心原则:ESP32 通过 I2C 接 RTC 模块,串口接 TTS 模块,GPIO 接按键,喇叭接 TTS 模块,所有零件共地(GND 连在一起)。

模块 / 零件

引脚名称

连接到 ESP32 的引脚

接线说明

DS3231 RTC 模块

VCC

3.3V

给 RTC 模块供电(3.3V,别接 5V!)

DS3231

GND

GND

共地(必须接,否则读不到时间)

DS3231

SDA

GPIO21

I2C 数据引脚(ESP32 默认 I2C 引脚)

DS3231

SCL

GPIO22

I2C 时钟引脚

SYN6288 TTS 模块

VCC

3.3V

给 TTS 模块供电(ESP32 输出 3.3V 足够)

SYN6288

GND

GND

共地(否则语音有杂音)

SYN6288

RX

GPIO17(TX)

ESP32 给 TTS 模块发指令(TX→RX)

SYN6288

TX

GPIO16(RX)

TTS 模块回传状态(新手可省略,不影响基础功能)

SYN6288

SPK+

喇叭正极

TTS 模块功放输出→喇叭发声

SYN6288

SPK-

喇叭负极

喇叭负极(接反没声音,换线即可)

轻触按键

一脚

GPIO0

按键输入(GPIO0 下拉,按下去触发)

轻触按键

另一脚

GND

按键接地(形成回路)

锂电池(可选)

正极(通过充电模块)

VBAT

给 ESP32 供电(便携使用,USB 供电可省略)

(二)第二步:软件准备(Arduino IDE + 库安装)

  1. 打开 Arduino IDE,安装以下库(直接搜名称安装):
    • RTClib:用于读取 DS3231 时间(作者:Adafruit);
    • Wire:ESP32 I2C 通信库(IDE 自带,无需额外安装);
    • HardwareSerial:ESP32 串口通信库(IDE 自带);
    • EEPROM:ESP32 存储提醒时间(IDE 自带)。
  1. 选择开发板:工具→开发板→ESP32 Dev Module,端口选 ESP32 连接电脑的 COM 口。

(三)第三步:完整代码(复制即用,含详细注释)

// 引入所需库

#include <Wire.h>

#include <RTClib.h>

#include <HardwareSerial.h>

#include <EEPROM.h>

// 1. 模块初始化配置

RTC_DS3231 rtc;  // 初始化RTC模块(DS3231)

HardwareSerial ttsSerial(2);  // 初始化串口2(接SYN6288,TX=17,RX=16)

// 2. 引脚定义

const int KEY_PIN = 0;  // 按键引脚(GPIO0)

const int EEPROM_ADDR = 0;  // EEPROM存储提醒时间的地址(0-511)

// 3. 变量定义

DateTime now;  // 存储当前时间

unsigned long reminderTime = 0;  // 存储提醒时间(单位:秒,从2000年1月1日开始算)

bool hasReminder = false;  // 是否有未完成的提醒

unsigned long lastKeyTime = 0;  // 按键防抖:记录上次按键时间

const int DEBOUNCE_TIME = 500;  // 防抖时间(500ms)

void setup() {

  Serial.begin(115200);  // 电脑串口调试(波特率115200)

  ttsSerial.begin(9600);  // TTS模块波特率(固定9600,和SYN6288默认一致)

  

  pinMode(KEY_PIN, INPUT_PULLUP);  // 按键引脚设为上拉输入(按下去为低电平)

  EEPROM.begin(512);  // 初始化EEPROM(大小512字节)

  // 初始化RTC模块

  if (!rtc.begin()) {

    Serial.println("RTC模块初始化失败!检查接线!");

    ttsSpeak("RTC模块初始化失败,请检查接线");

    while (1);  // 初始化失败则卡住,提示用户

  }

  // 如果RTC模块没设置时间,手动设置一次(第一次使用时打开注释,设置后注释掉)

  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));  // 用编译时间设置RTC

  // 从EEPROM读取之前存储的提醒时间

  EEPROM.get(EEPROM_ADDR, reminderTime);

  hasReminder = (reminderTime > 0);  // 有非0的提醒时间,说明有未完成提醒

  Serial.print("从EEPROM读取的提醒时间:");

  Serial.println(reminderTime);

  ttsSpeak("智能音箱初始化完成,支持整点报时和按键设置提醒");

  delay(2000);

}

void loop() {

  now = rtc.now();  // 读取当前时间

  checkKey();       // 检查按键是否被按下(设置提醒)

  checkHourlyReport();  // 检查是否到整点(触发报时)

  checkReminder();  // 检查是否到提醒时间(触发提醒)

  delay(1000);  // 每秒循环一次,避免频繁读取

}

// 【功能1:TTS播报函数】给SYN6288发指令,播报文本

void ttsSpeak(String text) {

  if (text.length() == 0) return;  // 空文本不播报

  

  // SYN6288通信协议:帧头(AA) + 指令(01=播报) + 文本长度 + 文本 + 帧尾(BB)

  ttsSerial.write(0xAA);

  ttsSerial.write(0x01);

  ttsSerial.write(text.length());

  ttsSerial.print(text);

  ttsSerial.write(0xBB);

  

  Serial.print("已播报:");

  Serial.println(text);

  delay(1000);  // 等待播报开始,避免指令堆积

}

// 【功能2:整点报时检查】判断是否到整点,生成报时文本

void checkHourlyReport() {

  int minute = now.minute();

  int second = now.second();

  

  // 每分钟的0秒检查是否到整点(避免每秒检查,节省资源)

  if (second == 0 && minute == 0) {

    String timeText = getTimeText();  // 获取“上午X点整”格式的文本

    ttsSpeak("现在是" + timeText);

    delay(5000);  // 避免同一整点重复播报(延迟5秒)

  }

}

// 【辅助函数:时间转中文文本】比如14:00→“下午2点整”

String getTimeText() {

  int hour = now.hour();

  String period = "上午";

  

  // 判断上午/下午(24小时转12小时制)

  if (hour >= 12) {

    period = "下午";

    if (hour > 12) hour -= 12;  // 13点→1点,12点保持12点

  } else if (hour == 0) {

    hour = 12;  // 0点→凌晨12点

    period = "凌晨";

  }

  

  return period + String(hour) + "点整";

}

// 【功能3:按键设置提醒】检测按键按下,设置10分钟后提醒

void checkKey() {

  int keyState = digitalRead(KEY_PIN);

  unsigned long currentTime = millis();

  

  // 按键防抖:按下且距离上次按键超过500ms

  if (keyState == LOW && (currentTime - lastKeyTime) > DEBOUNCE_TIME) {

    lastKeyTime = currentTime;  // 更新上次按键时间

    

    // 计算提醒时间:当前时间 + 10分钟(10*60秒)

    reminderTime = now.unixtime() + 10 * 60;

    hasReminder = true;

    

    // 存储提醒时间到EEPROM(掉电不丢)

    EEPROM.put(EEPROM_ADDR, reminderTime);

    EEPROM.commit();  // 提交写入(ESP32必须加这行)

    

    // 播报提醒设置成功

    String remindText = "提醒设置成功,将在10分钟后提醒您喝水";

    ttsSpeak(remindText);

    Serial.print("设置提醒时间(Unix时间):");

    Serial.println(reminderTime);

  }

}

// 【功能4:提醒检查】对比当前时间和提醒时间,到点播报

void checkReminder() {

  if (!hasReminder) return;  // 没有提醒则跳过

  

  unsigned long currentUnixTime = now.unixtime();

  

  // 当前时间 ≥ 提醒时间(到点或超时)

  if (currentUnixTime >= reminderTime) {

    ttsSpeak("提醒您喝水啦!请起身活动一下");

    

    // 清除已完成的提醒(重置变量+EEPROM)

    reminderTime = 0;

    hasReminder = false;

    EEPROM.put(EEPROM_ADDR, reminderTime);

    EEPROM.commit();

    

    Serial.println("提醒已触发,已清除提醒");

  }

}

(四)第四步:测试步骤(分功能验证,确保成功)

1. 第一次使用:设置 RTC 时间
  • 首次烧录代码后,打开代码中的rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));这行注释(删除 //);
  • 重新烧录代码,此时 RTC 会用电脑的 “编译时间” 设置当前时间;
  • 时间设置完成后,再把这行代码注释掉(避免下次烧录覆盖正确时间)。
2. 测试整点报时
  • 烧录代码后,用 USB 给 ESP32 供电,打开串口监视器(波特率 115200);
  • 串口会显示当前时间,等待到整点(比如 15:00:00),喇叭会播报 “现在是下午 3 点整”;
  • 若没播报,检查:① DS3231 接线是否正确(SDA=21,SCL=22);② 串口监视器是否显示正确时间。
3. 测试按键设置提醒
  • 按下轻触按键,喇叭会播报 “提醒设置成功,将在 10 分钟后提醒您喝水”;
  • 串口监视器会显示 “设置提醒时间(Unix 时间):XXXXXX”;
  • 等待 10 分钟,到点后喇叭会播报 “提醒您喝水啦!请起身活动一下”,串口显示 “提醒已触发,已清除提醒”;
  • 若没提醒,检查:① 按键接线是否正确(GPIO0→按键→GND);② EEPROM 是否初始化(代码中EEPROM.begin(512)是否有)。
4. 测试便携供电(可选)
  • 把锂电池通过充电模块连接到 ESP32 的 VBAT 引脚;
  • 拔掉 USB 线,ESP32 会用锂电池供电,报时和提醒功能正常(锂电池满电可续航 2-3 天)。

五、避坑指南:新手必看的 5 个高频问题

1. 坑 1:RTC 读不到时间,串口显示 “初始化失败”

  • 原因:① I2C 引脚接错(不是 21/22);② DS3231 模块没插好;③ 模块坏了;
  • 解决:① 确认 DS3231 的 SDA 接 GPIO21,SCL 接 GPIO22;② 重新插拔模块;③ 用万用表测模块 VCC 是否有 3.3V 电压。

2. 坑 2:按键按了没反应,不设置提醒

  • 原因:① 按键引脚接错(不是 GPIO0);② 没开上拉输入(代码中pinMode(KEY_PIN, INPUT_PULLUP)是否正确);③ 按键坏了;
  • 解决:① 检查按键接线;② 串口打印digitalRead(KEY_PIN)的值(按下去应为 0,松开为 1);③ 换一个按键试试。

3. 坑 3:提醒设置后,断电再上电就没了

  • 原因:① 没调用EEPROM.commit()(ESP32 必须提交写入,否则不保存);② EEPROM 地址冲突;
  • 解决:① 确保代码中EEPROM.put后有EEPROM.commit();② 更换 EEPROM 地址(比如从 0 改成 10)。

4. 坑 4:报时 / 提醒声音小或有杂音

  • 原因:① 喇叭功率太小(选 4Ω 1W 以上);② 模块和 ESP32 没共地(GND 没连在一起);③ 杜邦线太长;
  • 解决:① 换功率大的喇叭;② 检查所有模块的 GND 是否都接 ESP32 的 GND;③ 用 10cm 以内的短线连接。

5. 坑 5:ESP32 上电后很快死机

  • 原因:① 供电不足(USB 线是充电线,不是数据线,电流不够);② 锂电池电压太低(低于 3.3V);
  • 解决:① 用支持数据传输的 USB 线(电流≥1A);② 给锂电池充电(用充电模块充到 4.2V)。

六、功能扩展建议(下一篇预告,吸引关注)

搞定基础版后,还能升级这些实用功能(下一篇详细讲,关注不迷路!):

  1. 自定义提醒间隔:加 3 个按键,分别设置 5 分钟、10 分钟、30 分钟提醒;
  2. WiFi 同步时间:不用手动设置 RTC,ESP32 连 WiFi 自动同步网络时间;
  3. 手机 APP 设置提醒:通过蓝牙 / WiFi,在手机上设置提醒内容(比如 “提醒开会”);
  4. 多语言报时:支持中英文切换(比如 “Now is 3 PM”)。

七、互动环节

  1. 你成功做出智能音箱了吗?评论区晒出你的成品照片,我会抽 3 个同学送 “智能音箱扩展代码包”(含 WiFi 同步时间、自定义提醒功能);
  2. 遇到具体问题?比如 “RTC 时间总不准”“提醒不播报”,评论区说清楚你的问题 + 接线 / 代码截图,我会逐条回复;
  3. 你想优先看哪个扩展功能?WiFi 同步时间扣 “51”,手机 APP 设置提醒扣 “52”,我按投票优先更!

附:紧急排坑工具包

  1. RTC 测试代码:单独读取 DS3231 时间,排除模块问题(https://blog.csdn.net/weixin_44363607/article/details/121462364);
  2. EEPROM 测试代码:验证 EEPROM 是否能正常读写(https://randomnerdtutorials.com/esp32-eeprom-arduino/);
  3. 串口调试技巧:打印now.unixtime()reminderTime,对比是否正确(判断提醒时间计算是否有误)。
Logo

网易智企-云信开发者社区是面向全网开发者的技术交流与服务平台,依托近 29 年 IM、音视频技术积累,提供 IM、RTC、实时对话智能体、云原生、短信等全场景开发资源。

更多推荐