3. ZigBee 设备类型与角色:协调器、路由器、终端设备
这一章咱们聊聊 ZigBee 网络里的三种设备角色。说白了,一个 ZigBee 网络就像一个小型团队,有人当组长,有人当传话筒,还有人当省电的普通成员。这三种角色分工明确,缺一不可。
我在做项目时经常遇到有人问:「为什么我的终端设备连不上网?」「为什么路由器加进去后网络就乱了?」——这些问题,多半是对设备角色理解不够深。咱们今天就把这三个角色彻底讲透。
3.1 协调器(Coordinator)——网络的发起者
协调器是每个 ZigBee 网络的第一个节点。它负责建立网络、分配地址、管理入网。一个网络只能有一个协调器,而且它一旦启动,就不能再改变角色。
3.1.1 协调器的核心功能
- 网络建立:扫描信道,选择一个干扰最小的信道,启动网络
- 地址分配:为加入的路由器和终端设备分配 16 位短地址
- 入网管理:允许或拒绝设备加入网络
- 信标发送:在信标使能模式下定期发送信标帧
关键点:协调器本质上也是一个全功能设备(FFD),它拥有完整的协议栈功能。但它不是路由器,不能转发数据包——这一点很多人搞混。
3.1.2 协调器的初始化流程
我习惯把协调器的启动过程分成三步。嗯,每一步都有坑,咱们一个一个说。
- 硬件初始化:MCU 时钟、GPIO、SPI/UART 外设、中断系统
- 协议栈初始化:调用
ZigBeeInit(),加载 NV 参数,初始化 MAC 层 - 网络启动:调用
ZDO_StartDevice(),选择信道,建立网络
// 协调器初始化代码示例(基于 Z-Stack)
void zbStartRequest( void )
{
// 1. 初始化硬件
HalDriverInit();
// 2. 初始化协议栈
ZMacInit();
nvInit();
// 3. 启动设备为协调器
ZDOInitDevice( 0 ); // 0 表示协调器
// 4. 等待网络建立完成
// 回调函数 zbStartConfirm() 会通知结果
}
void zbStartConfirm( uint8 status )
{
if( status == ZB_SUCCESS )
{
// 网络建立成功
// 此时可以获取网络短地址 0x0000
// 协调器的短地址固定为 0x0000
}
else
{
// 网络建立失败,检查信道干扰
}
}
我曾经踩过的坑:有一次协调器启动后,终端设备死活加不进来。查了半天,发现是 NV 参数里残留了上次测试的网络信息。解决办法很简单——每次量产前做一次 NV 擦除。记住:协调器的 NV 必须干净。
3.2 路由器(Router)——网络的中继者
路由器的作用说白了就是「传话」。它接收数据包,然后转发给下一个节点。没有路由器,ZigBee 网络就只能覆盖几十米范围。
3.2.1 路由器的功能
- 数据中继:接收并转发数据包,扩展网络覆盖范围
- 路由发现:通过 AODV 算法寻找最优路径
- 子节点管理:允许终端设备通过它加入网络
- 路由表维护:动态更新路由表,处理链路失效
个人经验:我建议在部署路由器时,尽量让它们形成「网状」结构,而不是「链状」。链状结构一旦中间一个路由器掉电,后面的节点全断。网状结构有冗余路径,可靠性高得多。
3.2.2 路由发现过程
你想想看,当一个终端设备要发数据给另一个设备,路由器怎么知道往哪走?它靠的是路由发现。
- 源节点广播路由请求(RREQ)
- 中间路由器收到 RREQ,记录上一跳地址,继续广播
- 目标节点收到 RREQ,回复路由应答(RREP)
- RREP 沿原路径返回,沿途路由器更新路由表
这个过程我见过很多次。有一次在工厂里,设备之间距离太远,路由发现总是超时。后来加了两个路由器做中继,问题就解决了。
3.3 终端设备(End Device)——网络的省电者
终端设备是 ZigBee 网络里最「懒」的角色。它不转发数据,大部分时间都在睡觉。这正是它的价值所在——低功耗。
3.3.1 终端设备的低功耗特性
| 特性 | 说明 | 典型值 |
|---|---|---|
| 休眠模式 | 设备大部分时间处于睡眠状态 | 休眠电流 < 1 μA |
| 轮询机制 | 定期醒来向父节点查询是否有数据 | 轮询间隔 100ms ~ 10s |
| 数据发送 | 发送完数据立即进入休眠 | 发送电流 ~ 30 mA |
| 父节点缓存 | 数据由父节点暂存,等待终端设备轮询 | 缓存超时 7.68s |
关键点:终端设备必须关联一个父节点(协调器或路由器)。父节点负责缓存发给它的数据。如果终端设备休眠时间太长,父节点会丢弃缓存数据。
3.3.2 终端设备的轮询机制
终端设备怎么知道有数据要收?它不会一直监听,那样太费电。它用轮询——定期醒来问父节点:「有我的数据吗?」
// 终端设备轮询示例
void pollForData( void )
{
// 设置轮询间隔为 1 秒
uint16 pollInterval = 1000; // 单位:毫秒
while(1)
{
// 进入休眠
halSleep( pollInterval );
// 醒来,发送数据请求
zbSendDataRequest( parentAddr, NULL, 0, 0, AF_ACK_REQUEST );
// 如果有数据,回调函数会处理
// 处理完继续休眠
}
}
// 数据接收回调
void zbReceiveDataIndication( uint16 source, uint16 command,
uint16 len, uint8 *pData )
{
// 处理接收到的数据
// 处理完后自动进入下一轮休眠
}
注意:轮询间隔不能太长。我曾经有个项目,终端设备设了 10 秒轮询一次,结果父节点缓存超时只有 7.68 秒,数据全丢了。后来改成 3 秒轮询,问题解决。记住:轮询间隔必须小于父节点缓存超时时间。
3.4 三种角色的分工对比
咱们用一张表把三种角色放在一起对比,一目了然。
| 特性 | 协调器 | 路由器 | 终端设备 |
|---|---|---|---|
| 设备类型 | FFD | FFD | RFD |
| 网络数量 | 1 个 | 多个 | 多个 |
| 数据转发 | 否 | 是 | 否 |
| 低功耗 | 否 | 否 | 是 |
| 子节点管理 | 是 | 是 | 否 |
| 典型应用 | 网关、集中器 | 中继器、智能插座 | 传感器、遥控器 |
3.5 设备角色在组网中的分工
一个典型的 ZigBee 网络是这样工作的:
- 协调器:启动网络,分配地址,管理入网
- 路由器:扩展覆盖范围,转发数据,提供冗余路径
- 终端设备:采集数据,发送给父节点,大部分时间休眠
说白了,协调器是「大脑」,路由器是「神经」,终端设备是「感官」。三者配合,才能形成一个稳定、可靠、低功耗的无线网络。
我的建议:在设计网络拓扑时,尽量让终端设备直接连接路由器,而不是协调器。协调器要处理网络管理任务,负载已经很重了。把终端设备分散到各个路由器上,网络会更稳定。
这张图展示了一个典型的 ZigBee 星型+网状混合拓扑。协调器在中心,两个路由器扩展覆盖范围,四个终端设备分别挂在不同路由器下。路由器之间还有网状连接,提供冗余路径。