目录
[3、DHT11 温湿度 / 光敏电阻](#3、DHT11 温湿度 / 光敏电阻)
[2、串口帧格式(以 SU-03T 为例)](#2、串口帧格式(以 SU-03T 为例))
[十一、软件设计(.h / .c 多文件工程)](#十一、软件设计(.h / .c 多文件工程))
[2、config.h ------ 全局配置](#2、config.h —— 全局配置)
[3、voice.h / voice.c ------ 语音识别模块](#3、voice.h / voice.c —— 语音识别模块)
[4、relay.h / relay.c ------ 继电器控制模块](#4、relay.h / relay.c —— 继电器控制模块)
[5、sensor.h / sensor.c ------ 环境传感器模块](#5、sensor.h / sensor.c —— 环境传感器模块)
[6、display.h / display.c ------ OLED 显示模块](#6、display.h / display.c —— OLED 显示模块)
[7、main.c ------ 主程序](#7、main.c —— 主程序)
[十五、开题报告 & 答辩要点](#十五、开题报告 & 答辩要点)
难度定位 :★★★☆☆(中等新颖型)|适合:有基础、想做「交互新颖 + 离线不依赖云端」选题、想突出差异化的同学|预估周期:3~4 周
一、这个毕设是干什么的?
一句话:做一套不用联网、喊一句就能控制家里电器的本地智能语音控制系统。
再展开说:你在家里说「开灯」,顶灯就亮;说「关风扇」,风扇就停;说「打开插座」,插在上面的设备就通电。这套系统用 ESP32 主控 + 离线语音识别模块,识别你的语音指令后直接驱动多路继电器开关电器,整个过程不需要 WiFi、不需要云平台、不需要手机 ,完全本地完成。同时它还会监测环境(温湿度、光照),比如温度高了自动开风扇、天暗了自动开灯,实现设备间的本地联动。
二、它解决什么问题?
不想用手机、不想联网操作 → 动嘴就能控制,符合日常直觉,老人小孩也会用;
依赖云端不稳 → 家里断网也能用,语音识别在本地完成,稳定性强、响应快;
晚上懒得摸黑找开关 → 一句话开灯;
环境自动调节 → 天热自动开风扇、天暗自动开灯,不用手动,体现智能联动。
**本质是:**把「手动开关 / 手机遥控」升级成「语音交互 + 本地联动」,突出「更自然的人机交互」和「不依赖外网的本地智能」,这正是智能家居从「远程控制」走向「主动服务」的方向。
三、核心功能?
| 功能 | 说明 |
|---|---|
| 离线语音控制 | 说「开灯/关灯/开风扇/关风扇/开插座/关插座」等,识别后控制对应电器 |
| 多路继电器 | 2~4 路独立控制灯具、风扇、插座,互不影响 |
| 本地设备联动 | 温度高自动开风扇、光照暗自动开灯(无需联网) |
| 环境监测 | 温湿度、光照实时采集并本地显示 |
| 本地显示 | OLED 屏显示设备状态与环境数据 |
| 无需联网 | 语音识别、设备控制全部本地完成,断网可用 |
四、用到哪些技术?
| 类别 | 具体 | 作用 |
|---|---|---|
| 主控 | ESP32 | 处理语音指令、驱动继电器、采集环境 |
| 语音识别 | 离线语音识别模块(SU-03T / LD3320) | 本地识别语音词条,输出指令帧 |
| 执行 | 多路继电器模块 | 控制灯具、风扇、插座通断电 |
| 传感器 | DHT11 温湿度、光敏电阻 | 环境监测、触发本地联动 |
| 显示 | SSD1306 OLED 屏 | 本地显示状态与环境数据 |
| 通信 | 串口(UART) | ESP32 与语音模块通信 |
| 开发 | Arduino IDE + C 语言 | 编写烧录程序 |
五、系统是怎么工作的?
语音输入(“开灯”)
↓
离线语音识别模块(本地识别词条)
↓ 串口指令帧
ESP32 主控(解析指令 → 驱动对应继电器)
↓
灯具 / 风扇 / 插座通电
↑
环境传感器(温度高 → 自动开风扇;光暗 → 自动开灯)
一句话串起来:说话 → 语音模块本地识别 → 串口发指令帧 → ESP32 解析 → 控制继电器开关电器;同时环境传感器数据驱动本地联动。
这套「本地语音识别 + 串口指令 + 继电器执行 + 传感器联动」的架构,是所有语音/离线控制类毕设的通用骨架,也可改造成语音控制窗帘、门锁等。
六、大概怎么做?
买齐硬件(ESP32 + 语音识别模块 + 2~4 路继电器 + DHT11 + 光敏 + OLED);
用语音模块配套工具配置词条(如「开灯」「关灯」「开风扇」「关风扇」);
接线:语音模块 TX/RX 接 ESP32 串口,继电器 IN 接控制脚,传感器接 GPIO;
用 Arduino IDE 写代码:接收串口指令 → 解析 → 驱动继电器;读取环境数据 → 本地联动;
上电说「开灯」,观察灯亮;捂热传感器验证温度联动开风扇;
断网(不连 WiFi)测试,确认完全本地可用,链路跑通即完成。
核心难点在于「语音模块词条配置 + 串口指令帧解析」,其余是简单控制逻辑。下面逐步展开。
七、硬件清单与接线
1、硬件清单
| 器件 | 型号/规格 | 数量 |
|---|---|---|
| 主控板 | ESP32 DevKitC | 1 |
| 语音识别模块 | SU-03T(离线,可自定义词条) | 1 |
| 继电器模块 | 5V 4 路(或 2 路) | 1 |
| 温湿度传感器 | DHT11 | 1 |
| 光照传感器 | 光敏电阻模块 | 1 |
| OLED 显示屏 | SSD1306 128×64 (I2C) | 1 |
| 负载 | 台灯 / 风扇 / 排插 | 1~4 |
| 电源 | 5V 适配器 / 充电宝 | 1 |
| 面包板 + 杜邦线 | --- | 若干 |
2、接线表
| ESP32 引脚 | 连接器件 | 说明 |
|---|---|---|
| GPIO16 (RX2) | SU-03T TX | 语音模块发送 → ESP32 接收 |
| GPIO17 (TX2) | SU-03T RX | ESP32 发送 → 语音模块接收(可不接) |
| GPIO26 | 继电器 IN1 | 第 1 路(灯) |
| GPIO27 | 继电器 IN2 | 第 2 路(风扇) |
| GPIO14 | 继电器 IN3 | 第 3 路(插座) |
| GPIO12 | 继电器 IN4 | 第 4 路(备用) |
| GPIO4 | DHT11 数据脚 DATA | 单总线读取温湿度 |
| GPIO34 | 光敏模块 AO | ADC 读取光照(0~4095) |
| GPIO21 | OLED SDA | I2C 数据线 |
| GPIO22 | OLED SCL | I2C 时钟线 |
| 5V | 继电器 VCC | 模块供电 |
| GND | 所有器件地线 | 必须共地 |
关键提醒 :语音模块与 ESP32 通信要共地;继电器 VCC 接 5V,控制电器时注意安全(火线走 COM/NO)。SU-03T 默认 3.3V 电平,接 ESP32 的 3.3V。
八、核心器件原理简述
1、离线语音识别模块(SU-03T)
本地语音识别芯片,不需联网,把语音词条提前「训练/配置」进模块,识别到就通过串口输出一帧指令;
用厂商配套工具(如「智能公元」在线配置)添加词条(如「开灯」),生成固件烧录进模块,无需写复杂算法;
识别结果以串口数据帧输出(典型帧如
FD 01 00 01 00 FF),ESP32 接收并解析帧里的词条序号即可;优点:完全离线、响应快、词条可自定义,是毕设里最省心又能突出交互的语音方案。
2、继电器(Relay)
用一个小电流控制线圈吸合/释放触点,从而通断大电流的电器;
常见低电平触发模块(IN 接地吸合),板上带指示灯;
三根关键接线:COM (公共)、NO (常开)、NC(常闭),电器火线接 COM、另一端接 NO,吸合时通电;
程序
digitalWrite高/低电平即可开关。
3、DHT11 温湿度 / 光敏电阻
DHT11 :单总线数字传感器,一根线读取 40bit 数据(含校验),无需 ADC;上电需稳定,两次读取间隔 ≥1 秒,读取失败返回
NaN需判空;光敏电阻模块:光照越强阻值越小,经模块输出模拟电压,ADC 读数越小说明越亮;用于「光暗自动开灯」联动,阈值需实测标定。
九、语音词条配置与串口协议
1、用智能公元工具配置词条(离线方案)
打开 智能公元(SU-03T 官方配置平台,免费注册);
新建项目,选「离线方案」+ 语音识别,添加词条:
唤醒词:
小智小智指令词:
开灯、关灯、开风扇、关风扇、打开插座、关闭插座每个指令词对应一个「命令词编号」(如 01、02、03...),生成固件并烧录到 SU-03T;
模块识别到词条后,通过串口输出数据帧(如
FD 01 00 01 00 FF),倒数第 4 字节即词条序号,代码据此区分指令。
2、串口帧格式(以 SU-03T 为例)
| 帧内容 | 含义 |
|---|---|
FD |
帧头 |
01 |
帧长(可变) |
00 |
版本 |
01 |
命令词编号(本帧为「开灯」) |
00 |
数据 |
FF |
帧尾 |
代码里只需校验帧头
FD、帧尾FF,取出命令词编号,映射到对应继电器动作即可。
十、开发环境搭建
安装 Arduino IDE(建议 2.x);
添加 ESP32 板卡:文件 → 首选项 → 附加开发板管理器网址填入
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json再在「工具 → 开发板 → 开发板管理器」搜索esp32安装;安装库(工具 → 管理库):
DHT sensor library、Adafruit SSD1306、Adafruit GFX;选择开发板
ESP32 Dev Module,烧录失败时按住板载 BOOT 键重试。
十一、软件设计(.h / .c 多文件工程)
代码按功能拆分:头文件(.h)只放宏定义、结构体、函数声明,源文件(.c)放具体实现,职责清晰、符合正式工程规范。
1、工程文件结构
esp32_voice_home/
├── config.h // 全局配置:引脚、继电器、阈值、词条映射(按需修改)
├── voice.h // 语音识别模块声明
├── voice.c // 串口接收 + 词条解析实现
├── relay.h // 继电器模块声明
├── relay.c // 多路继电器控制实现
├── sensor.h // 传感器模块声明
├── sensor.c // DHT11 温湿度 + 光敏采集实现
├── display.h // OLED 显示模块声明
├── display.c // OLED 显示实现
└── main.c // 主程序:setup() / loop()
2、config.h ------ 全局配置
#ifndef CONFIG_H
#define CONFIG_H
/* 继电器数量与控制引脚(低电平触发) */
#define RELAY_NUM 4
const int relayPin[RELAY_NUM] = {26, 27, 14, 12};
/* 环境传感器引脚 */
#define PIN_DHT 4
#define PIN_LIGHT 34 /* 光敏 ADC */
/* OLED (I2C) */
#define PIN_OLED_SDA 21
#define PIN_OLED_SCL 22
/* 语音模块串口 */
#define VOICE_UART 2 /* 使用 UART2: RX2=16, TX2=17 */
/* 本地联动阈值(建议实测标定) */
#define TEMP_AUTO_FAN 32.0f /* 温度高于此值自动开风扇 */
#define LIGHT_AUTO_ON 2000 /* 光照 ADC 高于此值(暗)自动开灯 */
/* 词条编号 → 动作映射(与智能公元配置一致) */
#define CMD_LAMP_ON 1 /* 开灯 */
#define CMD_LAMP_OFF 2 /* 关灯 */
#define CMD_FAN_ON 3 /* 开风扇 */
#define CMD_FAN_OFF 4 /* 关风扇 */
#define CMD_SOCKET_ON 5 /* 打开插座 */
#define CMD_SOCKET_OFF 6 /* 关闭插座 */
#endif
3、voice.h / voice.c ------ 语音识别模块
voice.h(声明):
#ifndef VOICE_H
#define VOICE_H
#include <stdbool.h>
void voice_init(void); /* 初始化语音串口 */
int voice_get_cmd(void); /* 返回收到的词条编号,无指令返回 -1 */
#endif
voice.c(实现):
#include "voice.h"
#include "config.h"
#include <HardwareSerial.h>
static HardwareSerial voiceSer(2); /* UART2 */
void voice_init(void) {
voiceSer.begin(9600, SERIAL_8N1, 16, 17); /* RX=16, TX=17, 波特率9600 */
}
/* 解析 SU-03T 数据帧,取出命令词编号 */
static int parseFrame(byte* buf, int len) {
if (len < 6) return -1; /* 帧至少 6 字节 */
if (buf[0] != 0xFD) return -1; /* 校验帧头 */
if (buf[len - 1] != 0xFF) return -1; /* 校验帧尾 */
return buf[3]; /* 命令词编号 */
}
int voice_get_cmd(void) {
static byte frame[16];
static int idx = 0;
while (voiceSer.available()) {
byte b = voiceSer.read();
frame[idx++] = b;
if (b == 0xFF) { /* 收到帧尾,解析一帧 */
int cmd = parseFrame(frame, idx);
idx = 0;
if (cmd > 0) return cmd; /* 返回词条编号 */
}
if (idx >= (int)sizeof(frame)) idx = 0; /* 防溢出 */
}
return -1;
}
4、relay.h / relay.c ------ 继电器控制模块
relay.h(声明):
#ifndef RELAY_H
#define RELAY_H
#include <stdbool.h>
void relay_init(void); /* 初始化所有继电器为关 */
void relay_on(int ch); /* 打开第 ch 路 */
void relay_off(int ch); /* 关闭第 ch 路 */
void relay_toggle(int ch); /* 翻转第 ch 路 */
bool relay_get_state(int ch); /* 读取第 ch 路状态 */
#endif
relay.c(实现):
#include "relay.h"
#include "config.h"
static bool state[RELAY_NUM];
void relay_init(void) {
for (int i = 0; i < RELAY_NUM; i++) {
pinMode(relayPin[i], OUTPUT);
relay_off(i); /* 上电默认全关,更安全 */
}
}
void relay_on(int ch) {
if (ch < 0 || ch >= RELAY_NUM) return;
digitalWrite(relayPin[ch], LOW); /* 低电平触发 */
state[ch] = true;
}
void relay_off(int ch) {
if (ch < 0 || ch >= RELAY_NUM) return;
digitalWrite(relayPin[ch], HIGH);
state[ch] = false;
}
void relay_toggle(int ch) {
if (state[ch]) relay_off(ch);
else relay_on(ch);
}
bool relay_get_state(int ch) {
if (ch < 0 || ch >= RELAY_NUM) return false;
return state[ch];
}
5、sensor.h / sensor.c ------ 环境传感器模块
sensor.h(声明):
#ifndef SENSOR_H
#define SENSOR_H
#include <stdbool.h>
typedef struct {
float temp; /* 温度 ℃ */
float humi; /* 湿度 % */
int light; /* 光照 ADC */
bool valid; /* 数据是否有效 */
} env_data_t;
void sensor_init(void); /* 初始化传感器 */
env_data_t sensor_read(void); /* 读取一次环境数据 */
#endif
sensor.c(实现):
#include "sensor.h"
#include "config.h"
#include <DHT.h>
static DHT dht(PIN_DHT, DHT11);
void sensor_init(void) {
dht.begin();
}
env_data_t sensor_read(void) {
env_data_t d;
d.temp = dht.readTemperature();
d.humi = dht.readHumidity();
d.light = analogRead(PIN_LIGHT);
d.valid = !isnan(d.temp) && !isnan(d.humi);
return d;
}
6、display.h / display.c ------ OLED 显示模块
display.h(声明):
#ifndef DISPLAY_H
#define DISPLAY_H
#include "sensor.h"
void display_init(void); /* 初始化 OLED */
void display_show(const env_data_t *d, const bool *relay); /* 刷新显示 */
#endif
display.c(实现):
#include "display.h"
#include "config.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
static Adafruit_SSD1306 oled(128, 64, &Wire, -1);
void display_init(void) {
Wire.begin(PIN_OLED_SDA, PIN_OLED_SCL);
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(SSD1306_WHITE);
}
void display_show(const env_data_t *d, const bool *relay) {
oled.clearDisplay();
oled.setCursor(0, 0);
oled.println("== Voice Home ==");
oled.print("Temp:"); oled.print(d->temp); oled.println("C");
oled.print("Humi:"); oled.print(d->humi); oled.println("%");
oled.print("Lamp:"); oled.println(relay[0] ? "ON " : "OFF");
oled.print("Fan :"); oled.println(relay[1] ? "ON " : "OFF");
oled.print("Sock:"); oled.println(relay[2] ? "ON " : "OFF");
oled.display();
}
7、main.c ------ 主程序
#include "config.h"
#include "voice.h"
#include "relay.h"
#include "sensor.h"
#include "display.h"
/* 把词条编号翻译成继电器动作 */
static void execVoiceCmd(int cmd) {
switch (cmd) {
case CMD_LAMP_ON: relay_on(0); break;
case CMD_LAMP_OFF: relay_off(0); break;
case CMD_FAN_ON: relay_on(1); break;
case CMD_FAN_OFF: relay_off(1); break;
case CMD_SOCKET_ON: relay_on(2); break;
case CMD_SOCKET_OFF: relay_off(2); break;
default: break;
}
}
/* 环境本地联动:温度高开风扇、光暗开灯(带状态变化防抖) */
static void envLinkage(const env_data_t *d) {
static bool fanAuto = false, lampAuto = false;
bool needFan = (d->temp > TEMP_AUTO_FAN);
bool needLamp = (d->light > LIGHT_AUTO_ON);
if (needFan != fanAuto) { fanAuto = needFan; needFan ? relay_on(1) : relay_off(1); }
if (needLamp != lampAuto){ lampAuto = needLamp; needLamp ? relay_on(0) : relay_off(0); }
}
void setup() {
relay_init(); /* 初始化继电器 */
sensor_init(); /* 初始化传感器 */
display_init(); /* 初始化 OLED */
voice_init(); /* 初始化语音串口 */
}
void loop() {
/* ① 处理语音指令 */
int cmd = voice_get_cmd();
if (cmd > 0) execVoiceCmd(cmd);
/* ② 读取环境并本地联动 */
env_data_t d = sensor_read();
if (d.valid) envLinkage(&d);
/* ③ 刷新显示 */
bool relayState[RELAY_NUM];
for (int i = 0; i < RELAY_NUM; i++) relayState[i] = relay_get_state(i);
display_show(&d, relayState);
delay(500);
}
以上为核心模块代码。需要时可继续扩展:新增
ir.c红外遥控、ble.c蓝牙本地控制、把联动做成可配置规则等,主程序只调用接口,逻辑一目了然。
十二、代码要点讲解
.h/.c分离 :.h只放宏、结构体、函数声明供#include,.c放具体实现隐藏细节,模块独立、便于扩展,是论文「模块化设计」的要点;
config.h集中配置:引脚、继电器、阈值、词条编号都收在一个文件,改参数不用翻代码;
voice.c串口帧解析 :用0xFD/0xFF校验帧头帧尾,取buf[3]命令词编号,稳定且不误判;词条编号与智能公元配置一一对应;
execVoiceCmd()命令分发:把词条编号翻译成继电器动作,语音模块换词条只需改映射,主逻辑不动;
envLinkage()本地联动 :温度 > 阈值自动开风扇、光照变暗自动开灯;用static标志只在状态翻转时动作,避免每循环反复触发,也避免和语音控制冲突;上电默认全关 :
relay_init把所有继电器置关,安全;
isnan()判空:DHT11 偶发读取失败返回非数值,必须判空,否则联动误判;完全不依赖 WiFi:本设计无需连网,语音识别与联动全本地完成,体现「离线可用」的核心卖点。
十三、功能测试与验收
| 功能 | 实现方式 | 测试方法 |
|---|---|---|
| 语音开灯 | 说「开灯」→ voice_get_cmd 返回 1 → relay_on(0) |
喊「开灯」,观察灯亮、OLED 显示 Lamp:ON |
| 语音关风扇 | 说「关风扇」→ 返回 4 → relay_off(1) |
喊「关风扇」,观察风扇停 |
| 语音开插座 | 说「打开插座」→ 返回 5 → relay_on(2) |
喊「打开插座」,插座负载通电 |
| 温度联动 | d.temp > TEMP_AUTO_FAN → 自动开风扇 |
用手捂热 DHT11,温度升高风扇自动启动 |
| 光照联动 | d.light > LIGHT_AUTO_ON → 自动开灯 |
遮住光敏模块,光线变暗灯自动亮 |
| 离线可用 | 全程不连 WiFi | 拔掉 WiFi/断网,语音控制与环境联动仍正常 |
分步验收清单:
上电 OLED 显示温度、湿度、设备状态 → 显示层 OK;
说「小智小智」唤醒,喊「开灯」,灯亮 → 语音识别 + 指令下行 OK;
喊「关灯」,灯灭 → 反向控制 OK;
捂热 DHT11,温度超阈值风扇自动转 → 温度联动 OK;
遮光敏,灯自动亮 → 光照联动 OK;
拔网测试,功能不变 → 离线可用 OK。
十四、能给你什么启发?
1. 选题优势:交互方式新颖(语音)、完全离线不依赖云端、系统稳定,答辩展示直观,且不像纯远程控制类那样「千篇一律」,差异化明显,论文素材充足。
2. 想冲更高分数,随便往这几个方向扩:
加红外遥控:用语音 + 红外控制空调、电视等带遥控的家电;
加蓝牙/局域网双模式:离线语音 + 手机局域网控制并存,覆盖更多入口;
联动规则可配置:把「温度多高开风扇、光照多暗开灯」做成可配置规则表,突出智能化;
加更多传感器:人体红外实现「人来灯亮、人走灯灭」;
多房间组网:多个语音控制盒分布家中,形成全屋语音智能家居。
十五、开题报告 & 答辩要点
1、开题报告可直接改用的表述
1. 选题依据(背景):随着智能家居的发展,用户对控制方式的便捷性、自然性要求越来越高。传统手机 APP 控制依赖网络、操作步骤多,对老人小孩不友好;云端方案在断网时无法使用。语音是人类最自然的交互方式,离线语音识别可在本地完成指令识别,无需依赖外部网络,能够提升智能家居控制的便捷性与稳定性,具有重要的实用价值。
2. 研究意义:本课题将离线语音识别技术与家居设备控制结合,一方面实现「动口不动手」的自然交互,提升智能家居的易用性与无网可用性;另一方面完整覆盖语音识别、串口通信、多路控制、传感器联动等物联网关键技术,对巩固专业知识、锻炼软硬件综合开发能力有重要意义。
3. 系统功能概述:系统基于 ESP32 主控,通过离线语音识别模块(SU-03T)识别语音指令,经串口将指令帧发送给主控解析,驱动多路继电器控制灯具、风扇、插座等电器;同时采集温湿度与光照数据,实现温度过高自动开风扇、光照变暗自动开灯等本地联动,全程无需联网。
4. 创新点(按实际情况选取):
采用离线语音识别,不依赖云端与网络,系统稳定性强;
采用 .h/.c 模块化软件架构,代码结构清晰、易于扩展;
实现「语音控制 + 环境联动」本地闭环,交互自然、智能化程度高。
5. 技术难点:
离线语音模块的词条配置与串口指令帧解析;
多路继电器独立控制与语音指令的可靠映射;
环境联动逻辑的状态管理与防抖处理。
2、答辩常见问题
| 可能被问 | 回答要点 |
|---|---|
| 为什么选离线语音识别? | 不依赖网络、响应快、稳定,交互自然,老人小孩都会用,突出差异化 |
| 语音识别怎么实现的? | SU-03T 离线芯片,提前用智能公元配置词条烧录,识别到后串口输出指令帧 |
| 指令帧怎么解析? | 校验帧头 FD、帧尾 FF,取命令词编号字节,映射到对应继电器动作 |
| 本地联动怎么实现? | 读 DHT11/光敏 → 温度高自动开风扇、光暗自动开灯,带状态翻转防抖 |
| 断网能用吗? | 能,语音识别、控制、联动全部本地完成,不依赖 WiFi 与云平台 |
| 系统有哪些改进空间? | 加红外控空调、蓝牙双模式、联动规则可配置、多房间组网等 |