基于 ZigBee 与 4G 的无线温湿度监测及远程控制系统

4156 字
21 分钟
基于 ZigBee 与 4G 的无线温湿度监测及远程控制系统

基于 ZigBee 与 4G 的无线温湿度监测及远程控制系统#

项目简介#

这是一个面向物联网环境监测场景设计的嵌入式项目。系统使用 CC2530 和 DHT11 组成无线采集终端,通过 ZigBee 将温湿度数据发送给协调器;协调器中的 CC2530 负责接收无线数据,STM32F103 负责数据解析、状态显示与告警控制,最后通过 ML307R 4G 模块将数据上传到 OneNET 云平台。

除了基本的数据采集和云端展示,系统还实现了温湿度超限告警、LED 与蜂鸣器控制、云端属性下发以及网络异常后的自动重连,形成了一条完整的“端—网关—云”物联网链路。

项目最终实现的主要功能包括:

  • DHT11 温湿度周期采集;
  • 终端 OLED 本地数据显示;
  • CC2530 ZigBee 自动组网与无线传输;
  • STM32 串口接收、帧校验和异常重同步;
  • 网关 OLED 显示节点地址、温湿度、网络状态和上传次数;
  • 温湿度超限时通过 RGB LED 和蜂鸣器报警;
  • ML307R 通过 4G 网络接入 OneNET;
  • 云端查看温湿度及执行 LED、蜂鸣器远程控制;
  • 4G 掉线或连续发布失败后的自动重连。

项目效果#

系统正常运行后,数据链路如下:

DHT11
↓
终端 CC2530
↓ ZigBee
协调器 CC2530
↓ UART
STM32F103
↓ USART3 / AT 指令
ML307R 4G 模块
↓ 蜂窝网络
OneNET 云平台

终端 OLED 用于显示当前 ZigBee 入网状态、节点短地址、温度和湿度;网关 OLED 用于显示接收到的节点数据、4G 网络状态、云端发布状态以及串口诊断计数。

将本文迁移到博客时,需要同时上传上图,或者将图片地址替换为博客图床地址。

系统架构#

系统可以分为采集终端、ZigBee 协调器、4G 网关和云平台四个部分。

层级核心器件主要职责
采集终端CC2530、DHT11、OLED采集温湿度、显示数据、加入 ZigBee 网络并周期发送数据
ZigBee 协调器CC2530建立 ZigBee 网络、接收终端数据、提取节点短地址并通过串口转发
4G 网关STM32F103RCT6、ML307R、OLED、RGB LED、蜂鸣器解析数据、显示状态、执行告警、连接 4G 并与 OneNET 通信
云平台OneNET保存和展示设备属性,并向网关下发控制命令

这样的分层方式将局域无线采集与广域网络通信分离:CC2530 专注于 ZigBee 组网,STM32 专注于网关业务,ML307R 专注于蜂窝联网。各模块之间通过明确的数据协议连接,便于单独调试和后续扩展。

硬件组成#

采集终端#

终端以 CC2530 为主控,主要外设连接如下:

功能引脚
DHT11 DATAP2.0,外接 10 kΩ 上拉电阻
OLED SCLP1.2
OLED SDAP1.3
蜂鸣器P1.7
LED1P1.4
LED2P0.1
LED3P1.0
LED4P1.1

终端完成 ZigBee 入网后,大约每 2.000~2.255 秒采集并发送一次数据。增加少量随机抖动,可以降低多个终端同时发送造成碰撞的概率。

协调器与 4G 网关#

协调器板上同时包含 CC2530 和 STM32F103RCT6。两颗 MCU 分工明确:CC2530 处理 ZigBee 协议栈,STM32 负责网关业务。

功能STM32 引脚连接对象
ZigBee 数据输入PC11 / UART4_RXCC2530 P0.4 / USART1_TX
调试串口PA9、PA10 / USART1CH340N / USB1
ML307R 通信PB10、PB11 / USART3ML307R
OLED SCLPA12板载 OLED
OLED SDAPA11板载 OLED
RGB LEDPC13、PC14、PC15板载 LED
蜂鸣器PA15板载有源蜂鸣器驱动电路

三路串口均采用 115200、8N1:USART1 输出调试日志,UART4 接收 CC2530 数据,USART3 与 ML307R 通信,从硬件和软件层面避免了串口资源冲突。

软件与工具链#

模块开发环境或框架
CC2530 ZigBee 程序TI Z-Stack、IAR Embedded Workbench for 8051
STM32 网关程序Keil MDK、STM32F10x 标准外设库
蜂窝通信ML307R RTU 固件及 AT 指令
云平台OneNET 物联网平台

CC2530 工程基于 Z-Stack 的 SampleApp 示例进行二次开发,在 OSAL 事件机制中加入 DHT11 采集、OLED 显示和传感器数据发送任务。STM32 工程采用前后台结构:中断负责快速接收数据,主循环负责协议解析、设备控制和云端通信。

数据通信设计#

终端到协调器:ZigBee 数据帧#

终端成功读取 DHT11 后发送 5 字节数据:

['T', 'H', temperature, humidity, checksum]

校验值为前 4 个字节相加后取低 8 位:

checksum = 'T' + 'H' + temperature + humidity;

协调器收到数据后会检查帧头、长度、校验值和温湿度范围。数据有效时,它从 Z-Stack 的接收包结构中读取真实的 ZigBee 网络短地址:

pkt->srcAddr.addr.shortAddr

因此,网关不仅能知道温湿度,还能区分数据来自哪个终端节点。协调器接收成功后会向终端广播 D1 确认帧,终端通过 LED 显示本次数据已被接收。

协调器到 STM32:ASCII 串口帧#

为了方便串口调试和跨平台解析,CC2530 将无线数据转换为固定格式的 ASCII 帧:

$TH,IIII,TTT,HHH*CC\r\n

各字段含义如下:

字段含义
IIII4 位十六进制 ZigBee 网络短地址
TTT3 位十进制温度
HHH3 位十进制湿度
CC从字符 T 到湿度末位之间所有 ASCII 字节的异或校验

示例:

$TH,E839,025,060*CC\r\n

STM32 的 UART4 中断只负责把字节写入 128 字节环形缓冲区,避免在中断中执行耗时操作。主循环再以 $ 为同步字符,以换行符为帧结束标志,完成格式检查、异或校验、数值转换和量程判断。

这种设计即使遇到丢字节、粘包或无效数据,也能在下一次出现 $ 时重新同步。网关还记录累计接收字节数和无效帧数,并显示为:

UART B:<接收字节数> E:<无效帧数>

这组计数在排查引脚、波特率和数据格式问题时非常实用。

STM32 到 OneNET:4G 属性上报#

STM32 通过 USART3 向 ML307R 发送 AT 指令,主要初始化过程包括:

  1. 连续发送 AT,确认模块已经完成启动且串口通信稳定;
  2. 选择 OneNET RTU 任务;
  3. 写入产品、设备和鉴权参数;
  4. 配置会话清理、保活时间和多消息模式;
  5. 订阅属性上报回复与属性设置通道;
  6. 重启模块并等待蜂窝网络注册完成;
  7. 发布一次设备属性,并以平台返回的 code:200 作为真正成功的依据。

每次上报的数据不仅包含温度和湿度,还包含本地输出设备的当前状态:

{
"id": "1",
"version": "1.0",
"params": {
"temp": { "value": 25 },
"humi": { "value": 60 },
"LED1": { "value": false },
"LED2": { "value": false },
"buzzer": { "value": false }
}
}

程序只有在收到 OneNET 的成功回复后才增加 OLED 上的上传计数,避免将“AT 指令已经发出”误判为“数据已经被云平台接受”。

告警与远程控制#

网关默认采用以下告警规则:

  • 温度大于 28 ℃时点亮红灯;
  • 湿度大于 80% 时点亮蓝灯;
  • 红灯或蓝灯任意一个处于告警状态时,蜂鸣器鸣响。

阈值集中定义在 协调器4G上云/app_config.h 中,便于根据应用场景调整。

OneNET 还可以向设备下发 LED1、LED2 和 buzzer 布尔属性。STM32 使用一个按长度接收的状态机解析 ML307R 主动上报的属性设置消息,执行本地控制后,再向平台返回对应的 set_reply。

本地告警请求和云端蜂鸣器请求采用“逻辑或”合并:只要告警条件或云端控制有任意一方要求蜂鸣器开启,蜂鸣器就保持鸣响。这样可以避免远程操作意外屏蔽现场告警。

程序运行流程#

终端流程#

  1. 初始化 CC2530、OLED 和 DHT11;
  2. 启动 Z-Stack 并搜索 ZigBee 网络;
  3. 入网成功后启动周期任务;
  4. 读取 DHT11 的 40 位数据并校验;
  5. 在 OLED 显示节点地址、温度和湿度;
  6. 通过 ZigBee 发送传感器帧;
  7. 等待协调器确认,并进入下一次采集周期。

DHT11 读取失败时,OLED 会显示 DHT11 ERROR,程序不会发送无效数据。

网关流程#

  1. 初始化调试串口、UART4、OLED、LED、蜂鸣器和 ML307R;
  2. 配置 ML307R 并连接 OneNET;
  3. 持续从 UART4 环形缓冲区取出 CC2530 数据;
  4. 对串口帧执行重新同步、格式检查和校验;
  5. 更新 OLED、LED 和蜂鸣器状态;
  6. 将最新属性上传到 OneNET;
  7. 处理云端属性下发;
  8. 连续发布失败达到上限后,将网络标记为离线并定期重连。

即使 4G 网络暂时不可用,ZigBee 数据接收、OLED 显示和现场告警仍然可以继续运行,避免云端故障影响本地监测功能。

项目目录说明#

zuwang/
├─ Projects/ # Z-Stack 与 CC2530 主工程
│ └─ zstack/Samples/SampleApp/
├─ Components/ # Z-Stack HAL 与公共组件
├─ 终端采集温湿度/ # 早期终端独立工程及参考代码
├─ 协调器4G上云/ # STM32 + ML307R 网关工程
│ ├─ main.c # 网关主流程
│ ├─ zigbee.c/.h # UART4 接收及协议解析
│ ├─ ml307.c/.h # ML307R AT 指令通信
│ ├─ onenet.c/.h # OneNET 接入、上报与属性下发
│ ├─ led.c/.h # RGB LED 控制
│ ├─ buzzer.c/.h # 蜂鸣器控制
│ └─ app_config.h # 应用参数与云平台配置
├─ 参考文件/ # 流程图、硬件资料和调试记录
└─ 烧录文件/ # 最终可烧录 HEX 文件

CC2530 的核心业务代码位于:

Projects/zstack/Samples/SampleApp/Source/
├─ SampleApp.c
├─ SampleAppDht11.c/.h
├─ SampleAppTerminal.c/.h
└─ SampleAppUart.c/.h

编译与烧录#

CC2530#

使用 IAR Embedded Workbench for 8051 打开:

Projects/zstack/Samples/SampleApp/CC2530DB/SampleApp.ewp

工程包含终端与协调器 Target,需要分别选择对应目标进行编译和下载。

STM32#

使用 Keil MDK 打开:

协调器4G上云/Project.uvprojx

根据自己的 OneNET 产品配置修改 app_config.h,编译后下载到 STM32F103RCT6。

仓库的 烧录文件 目录已经提供三个最终固件:

EndDevice_CC2530.hex
Coordinator_CC2530.hex
Gateway_STM32.hex

推荐烧录顺序:

  1. 将 Gateway_STM32.hex 烧录到协调器板上的 STM32;
  2. 将 Coordinator_CC2530.hex 烧录到协调器 CC2530;
  3. 将 EndDevice_CC2530.hex 烧录到终端 CC2530;
  4. 先启动协调器,再启动终端。

调试与验证#

建议按照链路从近到远逐级验证:

  1. 观察终端 OLED 是否经历 SEARCHING、JOINING 并最终显示 ZB:ONLINE;
  2. 检查终端是否显示合理的温湿度;
  3. 查看网关 OLED 的 UART B/E 计数;
  4. 确认网关能够显示真实节点地址和传感器数据;
  5. 通过 USB1 打开 115200、8N1 串口日志;
  6. 检查 [CC2530 RX] 和 [ZIGBEE] 日志;
  7. 检查 [ML307 TX]、[ML307 RX] 和 OneNET 的 code:200 回复;
  8. 最后在 OneNET 查看设备在线状态、属性更新时间及远程控制结果。

串口诊断信息可以快速定位故障:

现象可能原因
B=0UART4 未收到数据,应检查固件、PC11/RXD4 信号和 CC2530 运行状态
B>0、E=0、节点仍为 ----串口有数据,但尚未收到完整有效的 $TH 帧
B>0、E>0帧格式、波特率、接线或校验值不匹配
ZigBee 日志正常但云端不更新检查 SIM 卡、天线、ML307R 注册状态及 OneNET 鉴权参数

开发过程中遇到的问题#

1. STM32 串口引脚判断错误#

最初将 CC2530 数据接收配置为 PA3/USART2_RX,但开发板原理图中的板内网络 RXD4 实际连接到 PC11/UART4_RX,导致网关一直显示 UART B:0。

修正 UART4 引脚与中断入口后,STM32 才能正确接收协调器数据。这次问题说明,在使用集成开发板时,不能只根据 MCU 的常用串口引脚猜测连接关系,必须以原理图上的网络名和实际走线为准。

2. 中断中执行过多业务导致时序风险#

早期实现如果在串口中断内直接解析协议或处理业务,很容易延长中断占用时间。最终方案让中断仅负责写环形缓冲区,将协议解析放到主循环中,既减少丢字节风险,也便于实现错误恢复。

3. DHT11 时序与 ZigBee 任务冲突#

DHT11 对微秒级时序较敏感,但长时间关闭中断会影响 Z-Stack 的系统节拍和无线任务。最终只在约 4 ms 的关键 40 位读取窗口中进行必要的临界区保护,而 18~20 ms 的启动阶段保持中断开启,在传感器时序与协议栈实时性之间取得平衡。

4. 发送成功不等于云端接收成功#

串口发送完 AT 指令只能说明命令已经交给 4G 模块,不能证明 OneNET 已经接受数据。因此程序将平台返回的 code:200 作为成功依据,并且只在收到成功回复后增加上传计数。

5. 本地告警与云端控制的状态冲突#

如果云端控制直接覆盖本地状态,可能出现云端关闭蜂鸣器后现场高温告警失效的问题。本项目将本地告警与云端请求分别保存,最后合并输出,使远程控制不会破坏基本的安全告警逻辑。

6. 旧版工程与新工具链的兼容问题#

项目还处理了 IAR 10 启动文件虚拟寄存器、Z-Stack Target 内存空间不足、HAL LCD 与终端 P1.7 蜂鸣器引脚冲突,以及自定义 UART 与 Z-Stack HAL UART 对象冲突等问题。这些问题大多不是业务代码错误,而是旧协议栈、编译器版本和硬件复用共同产生的工程兼容问题。

项目亮点#

我认为这个项目最有价值的部分,并不是单独驱动了某一个传感器或模块,而是完成了不同芯片、协议和网络之间的系统集成:

  • 将 DHT11 的单总线时序与 Z-Stack 的事件调度结合;
  • 使用 ZigBee 网络短地址区分终端,为多节点扩展保留基础;
  • 设计带校验、可读且能重新同步的 MCU 间串口协议;
  • 使用环形缓冲区实现中断接收和主循环解析解耦;
  • 将本地采集、现场告警、4G 上云和远程控制组合为闭环;
  • 网络异常时保留本地功能,并实现发布失败后的重连机制;
  • 通过 OLED、串口日志和计数器建立了较完整的可观测性。

可继续改进的方向#

当前系统已经完成核心功能,后续还可以从以下方向继续完善:

  1. 将 DHT11 更换为 SHT30、AHT20 等精度更高的传感器;
  2. 支持多个终端节点,并在云端按节点地址分别展示数据;
  3. 增加终端离线判断、心跳包和数据序号,识别丢包与重复包;
  4. 将阈值、采样周期等参数改为云端可配置;
  5. 增加 Flash 参数持久化,设备重启后保留云端设置;
  6. 对 ZigBee 应用数据增加更强的 CRC 或消息认证;
  7. 将同步等待式 AT 通信改为完全非阻塞状态机;
  8. 增加看门狗、断网缓存和网络恢复后的历史数据补传;
  9. 对云平台密钥进行安全存储,避免将真实凭据写入公开源码。

总结#

本项目搭建了一套完整的 ZigBee—4G 无线温湿度监测系统。终端负责采集,ZigBee 负责局域无线传输,STM32 负责网关控制,ML307R 负责广域联网,OneNET 负责云端展示和远程控制。

在实现过程中,我不仅完成了 DHT11、OLED、串口和 4G 模块等外设驱动,更重要的是实践了事件驱动、通信协议设计、中断与缓冲区、网络状态管理、故障诊断以及多模块联调。相比单一的传感器实验,这个项目更接近一个小型但完整的物联网产品原型。

发布前注意事项#

如果要将源码同步到公开仓库,请务必先处理以下内容:

  • 删除或替换 app_config.h 中真实的 OneNET 产品 ID、设备 ID、Access Key 和 Token;
  • 不要在博客截图、串口日志或示例命令中暴露设备鉴权信息;
  • 建议提供一个 app_config.example.h 示例文件,并通过 .gitignore 忽略真实配置;
  • 检查历史提交中是否曾经保存密钥;若已经公开,应立即在平台侧轮换密钥;
  • 博客中的项目效果图可以使用设备实拍、终端 OLED、网关 OLED、串口日志和 OneNET 属性页面组成。
基于 ZigBee 与 4G 的无线温湿度监测及远程控制系统
https://benjian.xyz/posts/zigbee-4g-environment-monitor/
作者
JIAN
发布于
2026-09-04
许可协议
CC BY-NC-SA 4.0