前言

最近公司接了一个智慧楼宇的项目,需要在机房、卫生间、厨房等多个位置部署漏水检测装置。考虑到布线成本和后期维护问题,决定采用无线方案。经过几轮技术选型,最终选择了Zigbee协议——功耗低、组网稳定、适合多节点部署。

整个系统跑下来效果不错,这里把踩过的坑和关键实现分享出来。

系统架构

整个系统采用星型拓扑结构:

  • 1个协调器(Coordinator):负责组网、数据汇聚、上报云端
  • N个终端节点(End Device):部署在各个点位,检测漏水并上报
                    云平台/本地服务器
                           |
                    [Zigbee协调器]
                    /     |      \
                   /      |       \
            [节点1]   [节点2]   [节点3]...
            (厨房)    (卫生间)   (机房)

硬件选型

协调器端

  • 主控: STM32F103C8T6
  • Zigbee模块: CC2530(德州仪器)
  • 通信接口: UART转USB,用于连接上位机
  • 电源: 220V转5V适配器

检测节点

  • 主控: STM32L051(低功耗系列)
  • Zigbee模块: CC2530
  • 漏水传感器: 自制电极式传感器
  • 电源: 2节18650锂电池 + TP4056充电模块
  • 报警: 蜂鸣器 + LED指示灯

核心原理

1. 漏水检测原理

采用电极式检测,两个金属电极间距5mm。正常情况下电极间电阻无穷大,当有水渗入时,水的导电性使电阻急剧下降。通过ADC采集分压电路的电压变化判断是否漏水。

硬件电路:

VCC(3.3V) ---[10K电阻]--- 检测点(ADC输入) ---[电极探头]--- GND

当有水时,电极短路,ADC读到的电压接近0V;无水时为3.3V左右。

2. Zigbee组网流程

协调器启动后建立PAN网络,终端节点扫描信道加入网络。这里用的是Z-Stack协议栈,版本是2.5.1a。

协调器端代码实现

主要文件结构

Coordinator/
├── main.c                 // 主程序
├── zigbee_coord.c         // Zigbee协调器逻辑
├── uart_protocol.c        // 与上位机通信协议
└── data_process.c         // 数据处理

main.c - 协调器主程序

#include "stm32f10x.h"
#include "zigbee_coord.h"
#include "uart_protocol.h"
#include "systick.h"
// 设备状态结构体
typedef struct {

uint16_t short_addr;      // 设备短地址
uint8_t  ieee_addr[8];    // IEEE地址
uint8_t  leak_status;     // 漏水状态: 0-正常 1-漏水
uint16_t battery_volt;    // 电池电压(mV)
uint32_t last_update;     // 最后更新时间
uint8_t  online;          // 在线状态
} device_info_t;
#define MAX_DEVICES 32
device_info_t device_list[MAX_DEVICES];
uint8_t device_count = 0;
// 系统初始化
void System_Init(void)
{

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_Init();
USART1_Init(115200);  // 与上位机通信
USART2_Init(115200);  // 与Zigbee模块通信
printf("Zigbee漏水检测协调器启动...\r\n");
}
// 设备管理 - 添加或更新设备
void Device_Update(uint16_t short_addr, uint8_t *ieee_addr,
uint8_t leak, uint16_t battery)
{

int i;
// 查找是否已存在
for(i = 0; i < device_count; i++) {

if(device_list[i].short_addr == short_addr) {

device_list[i].leak_status = leak;
device_list[i].battery_volt = battery;
device_list[i].last_update = get_tick_ms();
device_list[i].online = 1;
return;
}
}
// 新设备
if(device_count < MAX_DEVICES) {

device_list[device_count].short_addr = short_addr;
memcpy(device_list[device_count].ieee_addr, ieee_addr, 8);
device_list[device_count].leak_status = leak;
device_list[device_count].battery_volt = battery;
device_list[device_count].last_update = get_tick_ms();
device_list[device_count].online = 1;
device_count++;
printf("新设备加入: 0x%04X\r\n", short_addr);
}
}
// 检查设备在线状态(超过60秒未上报视为离线)
void Device_CheckOnline(void)
{

uint32_t now = get_tick_ms();
for(int i = 0; i < device_count; i++) {

if(device_list[i].online) {

if(now - device_list[i].last_update > 60000) {

device_list[i].online = 0;
printf("设备离线: 0x%04X\r\n", device_list[i].short_addr);
// 上报离线事件
Upload_Device_Offline(device_list[i].short_addr);
}
}
}
}
int main(void)
{

System_Init();
Zigbee_Coord_Init();  // 初始化Zigbee协调器
printf("开始建立网络...\r\n");
Zigbee_StartNetwork();
uint32_t last_check = 0;
while(1)
{

// 处理Zigbee接收数据
Zigbee_Process();
// 处理上位机命令
UART_Process();
// 定时检查设备在线状态
if(get_tick_ms() - last_check > 5000) {

Device_CheckOnline();
last_check = get_tick_ms();
}