Skip to content

2.3 ZigBee 3.0 组网实验 ​

学习提示

本节课讲解多个理论知识,理解起来并不容易,如果暂时不理解也没关系,随着后续的学习,相信大家会逐步加深理解!

上节课学习了 BDB Commissioning Modes 基本原理之后,本节课讲解怎么样实现设备之间的网络组建。

一. 裁剪应用层 UI ​

(1)协议栈裁剪是开发者需要掌握的一项技术,因为 Z-Stack 3.0 包含了丰富的功能,但是在实际的开发过程中,部分功能可能是冗余的,甚至会影响到开发过程。

(2)打开本章节配套的工程代码,展开 App 层代码,如图所示。

SampleSwitch 工程 App 层代码

(3)红框中的两个文件是针对 TI 的评估板而设计的 UI,在产品开发过程并不需要用到,而且还会影响其他的开发工作,因此需要把它们裁剪掉。右击文件,选择 Remove,如图所示。

右击文件选择 Remove

(4)裁剪后如图所示。

裁剪完成后的 App 层

(5)zcl_samplesw.c 文件中会调用到这些 UI,也需要把其全部删除。点击 Edit,然后选择 Find and Replace → Find in Files...,如图所示。

Edit 菜单中的 Find in Files

(6)在弹出的窗口中输入"UI_",然后点击 Find 按钮,如图所示。

Find in Files 对话框

(7)最后,在文件 zcl_samplesw.c 中根据搜索结果,一个一个地把带"UI_"的地方删除,如图所示。

删除 zcl_samplesw.c 中的 UI 相关内容

(8)正确删除完成后,工程代码是可以编译通过的。

二. 编写设备组网代码 ​

(1)如同前面章节所述,设备组网代码非常简单:

  • 第一步,调用 bdb_StartCommissioning() 让协调器创建网络。

  • 第二步,还是调用 bdb_StartCommissioning(),让其他设备加入到网络。

(2)角色判断

在编译工程的时候,可以选择让编译出来的程序工作在协调器(Coordinator)中、路由器(Router)中或者终端(EndDevice)中,即选择设备在 ZigBee 网络中的角色。在代码中,可以利用宏 ZDO_COORDINATOR 来判断当前的工作模式,判断方法是如果宏 ZDO_COORDINATOR 被定义了,那么说明程序工作在协调器环境中,否则就是工作在路由器或者终端环境中。

(3)编写代码

在 zcl_samplesw.c 的初始化函数 zclSampleSw_Init() 中添加如下代码:

c
#ifdef ZDO_COORDINATOR
    bdb_StartCommissioning( BDB_COMMISSIONING_MODE_NWK_FORMATION |
                            BDB_COMMISSIONING_MODE_FINDING_BINDING );

    NLME_PermitJoiningRequest(255);
#else
    bdb_StartCommissioning( BDB_COMMISSIONING_MODE_NWK_STEERING |
                            BDB_COMMISSIONING_MODE_FINDING_BINDING );
#endif

代码比较简单,如果是协调器那么就让协调器创建网络,如果是路由器或者终端那么就加入到网络。

其中的 NLME_PermitJoiningRequest(255) 是允许其他设备加入到由本协调器创建的网络中,这一点在介绍 Network Formation 时也有讲述过,也就是设备要经过信任中心的同意才能加入到网络中。参数 255 表示一直允许,如果改为 0 则表示一直不允许;如果改为 1~254 表示在 1~254 秒内允许。

三. 处理设备入网失败 ​

(1)然而,设备入网的过程可能会受到多种因素的影响,从而导致入网失败,例如在入网过程信号受到干扰等。开发者需要学会处理设备入网失败。一种简单而有效的办法就是在设备入网失败后,让设备自动重新尝试入网。

(2)在 zcl_samplesw.c 文件中可以找到一个 zclSampleSw_ProcessCommissioningStatus() 函数,这个函数的作用是处理 Commissioning 结果,例如协调器创建网络是否成功、设备是否成功加入到网络等。

(3)可以在这个函数中根据 Commissioning 的结果采取相应的处理,例如在设备入网失败后重新调用 bdb_StartCommissioning() 来再次入网。

(4)可以用事件的机制来实现这个过程,当设备入网失败后就启动一个事件,让程序在 1s 后重新尝试入网。Z-Stack 3.0 的事件使用方法在前面的章节已经讲解过了,这里就不再讲了,而是直接使用。

(5)在头文件 zcl_samplesw.h 定义一个用户事件,并且定义重新入网的时间间隔,代码如下:

c
/* 协调器 */
#ifdef ZDO_COORDINATOR
/* 路由器或者终端 */
#else
    // 重新加入事件
    #define SAMPLEAPP_REJOIN_EVT 0x0100
    // 时间间隔:1000ms(1秒)
    #define SAMPLEAPP_REJOIN_PERIOD 1000
#endif

由于设备入网是针对路由器或者终端类型的 ZigBee 设备的,因此同样地使用了宏来判断程序角色。

(6)在函数 zclSampleSw_ProcessCommissioningStatus 中找到入网失败处理位置,如图所示。

zclSampleSw_ProcessCommissioningStatus 函数

(7)在入网失败的位置添加如下代码:

c
/* 协调器 */
#ifdef ZDO_COORDINATOR
/* 路由器或者终端 */
#else
    /* 启动重新加入事件 */
    osal_start_timerEx(zclSampleSw_TaskID,
                       SAMPLEAPP_REJOIN_EVT,
                       SAMPLEAPP_REJOIN_PERIOD);
#endif

代码中,首先判断设备角色,然后启动刚才定义的事件。

开发者也可以在入网成功的位置添加一些代码,例如在显示器上显示入网成功的信息等。

(8)在应用层事件处理函数 zclSampleSw_event_loop() 中处理该事件,也就是重新启动入网,代码如下。

c
#ifdef ZDO_COORDINATOR
#else
  if ( events & SAMPLEAPP_REJOIN_EVT ) //如果事件类型为重新加入网络事件
  {
      /* 重新加入网络 */
      bdb_StartCommissioning(BDB_COMMISSIONING_MODE_NWK_STEERING |
                             BDB_COMMISSIONING_MODE_FINDING_BINDING );

      return ( events ^ SAMPLEAPP_REJOIN_EVT );
  }
#endif

四. 编译下载 ​

(1)角色选择

前文中多次提及到设备的网络角色,其实在编译代码的时候可以选择不同的网络角色,从而编写不同角色的程序。

在工程中单击选项卡,可以看到如图所示的选择框,可以选择待开发设备的对应的工作模式。

工程角色选择下拉框

其中 CoordinatorEB、RouterEB、EndDeviceEB 的含义分别是:

(1)CoordinatorEB:协调器角色设备。

(2)RouterEB:路由器角色设备。

(3)EndDeviceEB:终端角色设备。

除了此之外,还有 EndDeviceEB-OTAClient 和 RouterEB-OTAClient,其实这两个指的是带 OTA 功能的终端设备和带 OTA 功能的路由设备。

(2)使用角色

(2-1)首先选择 CoordinatorEB,如图所示。编译完成后下载到其中一块开发板中,建议使用 ZigBee 3.0 Mini 板。此开发板在 ZigBee 网络中会充当协调器角色设备。

选择 CoordinatorEB

(2-2)选择 RouterEB,如图所示。同样编译完成后下载到另一个板子中,建议使用 ZigBee 3.0 标准板。此开发板 ZigBee 网络中即会充当路由器角色设备。

选择 RouterEB

注意

切换工程后,同样需要在工程的预编译那里开启 LED、串口、显示屏等功能,并且把屏幕的路径加入到工程中。

五. 仿真调试 ​

(1)给协调器上电后,协调器会自动创建网络。创建网络成功后,在屏幕上可以看到网络 ID(PanID),如图所示。

协调器屏幕显示网络 ID

(2)接着给路由器或终端上电后,它会自动加入到由协调器创建的网络中,加入后可以在屏幕上看到被分配到的网络地址和父节点的网络地址,路由器或终端设备加入后如图所示。

  • 路由器

路由器屏幕显示网络地址

  • 终端

终端屏幕显示网络地址

六. 常见问题处理 ​

路由器(节点)无法加入协调器 ? ​

搭建项目时,务必按照以下顺序执行:

(1)先烧录「协调器」固件并上电;

(2)后烧录路由器(节点)固件,并上电;

(3)路由器(节点)会自动搜索协调器,并加入其中。

(4)如路由器(节点)仍没有自动加入,按一下协调器中的 Reset 按键重启协调器,路由器(节点)也可自动加入。

路由器(节点)如何加入新的协调器中 ? ​

一个简单的方法是:

(1)重新烧录「路由器(节点)」固件;

(2)烧录完成后,会自动搜索协调器并加入到其中。

实验要点

本节课完成了 ZigBee 3.0 组网实验的全流程:裁剪冗余 UI → 编写组网代码(协调器创建网络 / 设备加入网络)→ 处理入网失败自动重连 → 选择设备角色编译下载 → 仿真调试观察结果。核心 API 仍是 bdb_StartCommissioning() + NLME_PermitJoiningRequest(),配合事件机制实现入网失败自动重试。

内容来源:紫甲 IoT《ZigBee 3.0 开发指南》第四部分·2.3 ZigBee 3.0 组网实验,原站链接



本章自测 ​

一、单项选择题(每题 4 分,共 40 分) ​

  1. 实验第一步"裁剪应用层 UI"中,需要从 App 层移除的文件是?(A. TI 评估板专用 UI 文件 B. 协议栈核心文件 C. BDB 库文件 D. OSAL 文件) 答案:A

  2. 在 zcl_samplesw.c 中,需要用 Find in Files 搜索并逐一删除的内容前缀是?(A. "NWK_" B. "UI_" C. "BDB_" D. "ZDO_") 答案:B

  3. 代码中用来判断当前程序是否工作在协调器环境中的宏是?(A. HAL_LED B. ZDO_COORDINATOR C. SAMPLEAPP_REJOIN_EVT D. POLL_RATE) 答案:B

  4. 协调器调用 NLME_PermitJoiningRequest(255),参数 255 表示?(A. 一直不允许加入 B. 一直允许加入 C. 只允许 255 秒 D. 允许 255 个设备) 答案:B

  5. 若 NLME_PermitJoiningRequest() 的参数取 1~254,则表示?(A. 永久禁止加入 B. 永久允许加入 C. 在对应秒数内允许加入 D. 只允许路由器加入) 答案:C

  6. 在 zcl_samplesw.c 中,专门用于处理 Commissioning 结果的函数是?(A. zclSampleSw_Init() B. zclSampleSw_ProcessCommissioningStatus() C. zclSampleSw_event_loop() D. osal_start_timerEx()) 答案:B

  7. 实验中定义的重新入网事件 SAMPLEAPP_REJOIN_PERIOD 的时间间隔是?(A. 100ms B. 1000ms C. 5000ms D. 60000ms) 答案:B

  8. 启动一个定时事件所使用的 Z-Stack API 是?(A. bdb_StartCommissioning() B. NLME_PermitJoiningRequest() C. osal_start_timerEx() D. HalLedOn()) 答案:C

  9. 编译配置下拉框中,CoordinatorEB 代表的是?(A. 终端角色 B. 路由器角色 C. 协调器角色 D. 带 OTA 的终端) 答案:C

  10. 按本页"常见问题",搭建项目时正确的烧录上电顺序是?(A. 先路由后协调器 B. 先协调器后路由/节点 C. 同时上电即可 D. 只烧路由即可) 答案:B

二、问答题(每题 20 分,共 60 分) ​

  1. 请概述本实验完成 ZigBee 3.0 组网的整体流程。参考答案要点:
  • 裁剪应用层 UI:Remove 评估板专用 UI 文件,并在 zcl_samplesw.c 中删除所有"UI_"相关代码,保证编译通过;
  • 编写组网代码:用 ZDO_COORDINATOR 判断角色,协调器调用 bdb_StartCommissioning(NWK_FORMATION | F&B) 并 NLME_PermitJoiningRequest(255),路由/终端调用 bdb_StartCommissioning(NWK_STEERING | F&B);
  • 处理入网失败:在 ProcessCommissioningStatus 中失败时启动重新加入事件,1s 后重试;
  • 选择 CoordinatorEB/RouterEB/EndDeviceEB 角色分别编译下载;
  • 仿真调试:协调器上电创建网络并显示 PanID,路由/终端上电后自动加入并显示网络地址与父节点地址。
  1. NLME_PermitJoiningRequest() 的参数取 255、0、1~254 时分别表示什么含义?参考答案要点:
  • 参数 255:表示一直允许其他设备加入本协调器创建的网络;
  • 参数 0:表示一直不允许加入;
  • 参数 1~254:表示在对应秒数(1~254 秒)内允许设备加入;
  • 这正对应 Network Formation 中"设备需经信任中心(协调器)同意才能入网"的机制。
  1. 当路由器/终端设备入网失败时,本实验是如何利用事件机制实现自动重连的?参考答案要点:
  • 在头文件中为路由/终端定义重新加入事件 SAMPLEAPP_REJOIN_EVT(0x0100)和时间间隔 SAMPLEAPP_REJOIN_PERIOD(1000ms);
  • 在 zclSampleSw_ProcessCommissioningStatus() 的入网失败分支中,调用 osal_start_timerEx() 启动该事件;
  • 在事件处理函数 zclSampleSw_event_loop() 中判断该事件,再次调用 bdb_StartCommissioning(NWK_STEERING | F&B) 重新入网;
  • 这样设备在信号受干扰等导致入网失败后,可每隔 1 秒自动重试,直到成功。

aioteer · 物联网专业课程群

💬AI 伴学配置