【物联网毕设】智能家居天气时钟(STM32+云端数据+语音交互+APP控制)
1. 项目背景与核心功能
最近在帮学生做毕业设计时,发现智能家居天气时钟是个非常实用的课题。这个项目把STM32单片机、云端数据获取、语音交互和手机控制完美结合,特别适合作为物联网入门练手项目。我自己在调试过程中踩过不少坑,今天就把完整实现方案分享给大家。
这个天气时钟的核心功能很接地气:早上起床能语音报时,出门前看一眼屏幕就知道今天要不要带伞,上班时还能用手机远程查看家里的温湿度。硬件成本控制在200元以内,用到的都是常见模块:
- STM32F103C8T6:性价比超高的主控芯片,72MHz主频完全够用
- ESP8266-01s:十块钱就能搞定的WiFi模块
- 0.96寸OLED:显示天气信息足够清晰
- DHT11:经典温湿度传感器,精度对于家用完全足够
- SYN6288语音模块:比普通蜂鸣器高级多了,能合成真人语音
2. 硬件设计详解
2.1 核心电路设计
主控板我用的是最小系统板,自己画PCB的话注意这几个关键点:
- 给ESP8266单独供电,实测3.3V电流峰值能达到200mA
- STM32的NRST引脚要留出调试接口
- OLED最好用I2C接口,节省IO资源
电源部分有个坑要注意:DHT11对电压波动敏感,我在VCC并联了100μF电容才稳定。下面是实测可用的原理图片段:
// STM32与ESP8266连接示意图
PA9(TX) —— ESP8266 RX
PA10(RX) —— ESP8266 TX
PB6 —— OLED SCL
PB7 —— OLED SDA
PC13 —— 用户按键
PA0 —— DHT11数据线
2.2 模块选型建议
语音模块我对比过三种方案:
- SYN6288:成本约25元,支持GB2312编码,音质较好
- LD3320:能本地识别简单指令,但需要大量训练样本
- 科大讯飞模块:效果最好但价格超预算
最终选择SYN6288+按键触发的方式,既控制成本又保证实用性。时钟模块用DS1302就行,比DS3231便宜不少,走时精度每天误差在2秒左右,通过联网校准完全够用。
3. 软件架构设计
3.1 程序流程图
整个系统跑在裸机上,没有上RTOS。主循环这样设计:
while(1) {
读取DHT11数据();
if(网络连接正常){
获取网络时间();
每30分钟更新天气();
}
检测按键();
刷新OLED显示();
处理语音队列();
}
3.2 关键代码实现
天气API我用的是心知天气的免费版,HTTP请求要这样构造:
// 示例请求URL
char url[128];
sprintf(url, "https://api.seniverse.com/v3/weather/now.json?key=你的密钥&location=%s&language=zh-Hans",
city_name);
JSON解析推荐用cJSON库,STM32上跑起来毫无压力:
cJSON *root = cJSON_Parse(response);
cJSON *now = cJSON_GetObjectItem(root, "now");
temperature = cJSON_GetObjectItem(now, "temperature")->valuestring;
4. 云端数据对接
4.1 天气API配置
免费API有调用次数限制,我的解决方案是:
- 本地缓存最近查询结果
- 非必要不频繁更新
- 多个城市共用同一个API key
在STM32上实现HTTPS有点吃力,可以改用HTTP或者通过路由器做反向代理。实测发现,用ESP8266的AT指令直接请求HTTP,代码最简洁:
AT+CIPSTART="TCP","api.seniverse.com",80
AT+CIPSEND=98
GET /v3/weather/now.json?key=xxx&location=beijing HTTP/1.1\r\nHost: api.seniverse.com\r\n\r\n
4.2 数据同步策略
设计了一个智能更新策略:
- 首次上电强制更新
- 之后每30分钟更新一次
- 用户主动查询时立即更新
- 网络异常时使用最近有效数据
在Flash里开辟了一个存储区,保存最后一次成功获取的数据:
typedef struct {
char temp[8];
char weather[16];
uint32_t timestamp;
} WeatherCache;
5. 语音交互实现
5.1 语音合成控制
SYN6288通过串口控制,发送文本前要先组包:
void speak(const char *text) {
uint8_t head[] = {0xFD, 0x00, 0x00, 0x01, 0x00};
head[2] = strlen(text) + 2;
head[4] = 0x04; // GB2312编码
HAL_UART_Transmit(&huart2, head, 5, 100);
HAL_UART_Transmit(&huart2, (uint8_t*)text, strlen(text), 100);
}
5.2 交互逻辑设计
设计了几个常用语音指令:
- "现在时间":播报当前时间
- "天气情况":朗读温度和天气状况
- "打开灯光":预留的智能家居接口
为了避免误触发,采用长按按键激活语音功能。在代码里用状态机实现:
if(按键按下时间 > 2秒) {
播放提示音();
开始录音();
while(!超时){
检测语音指令();
}
}
6. APP远程控制
6.1 通信协议选择
对比了三种方案后选择MQTT:
- HTTP轮询:实现简单但耗电
- WebSocket:需要持续连接
- MQTT:最适合物联网场景
用ESP8266内置的MQTT功能,代码量大幅减少:
AT+MQTTUSERCFG=0,1,"clientID","","",0,0,""
AT+MQTTCONN=0,"broker.emqx.io",1883,0
6.2 控制指令设计
定义了简单的JSON协议:
{
"cmd": "set_alarm",
"time": "07:30",
"repeat": [1,1,1,1,1,0,0]
}
APP端用Android Studio开发,关键是用好MQTT的异步回调:
client.setCallback(new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) {
String payload = new String(message.getPayload());
// 更新UI
}
});
7. 常见问题解决
在开发过程中遇到过几个典型问题:
-
ESP8266频繁断连 解决方法:在AT指令后加500ms延时,电源并联470μF电容
-
DHT11读取失败 解决方法:将数据线改为开漏输出,上拉电阻改为4.7K
-
语音模块杂音大 解决方法:在电源端加π型滤波电路,地线单独走线
-
OLED显示闪烁 解决方法:改用硬件I2C,时钟频率降到100kHz
这个项目最让我满意的是它的扩展性——后续可以轻松加入更多功能,比如通过GPIO控制智能插座,或者增加PM2.5检测模块。所有源码和PCB文件我都整理好了,需要的话可以留言区告诉我。
更多推荐


所有评论(0)