探索物联网实验的奥秘

目录

  • 1 实验名称——LED 控制实验
  • 1.1 实验目的
  • 1.2 实验环境
  • 1.3 实验原理
  • 1.4 实验内容
  • 1.5 实验步骤
  • 1.6 实验结果
  • 2 实验名称——温湿度传感器实验
  • 2.1 实验目的
  • 2.2 实验环境
  • 2.3 实验原理
  • 2.4 实验内容
  • 2.5 实验步骤
  • 2.6 实验结果
  • 3 实验名称——人体红外传感器实验
  • 3.1 实验目的
  • 3.2 实验环境
  • 3.3 实验原理
  • 3.4 实验内容
  • 3.5 实验步骤
  • 3.6 实验结果
  • 4 实验名称——点对点通信实验
  • 4.1 实验目的
  • 4.2 实验环境
  • 4.3 实验原理
  • 4.4 实验内容
  • 4.5 实验步骤
  • 4.6 实验结果
  • 5 实验名称——广播通信实验
  • 5.1 实验目的
  • 5.2 实验环境
  • 5.3 实验原理
  • 5.4 实验内容
  • 5.5 实验步骤
  • 5.6 实验结果
  • 6 实验名称——网络拓扑-星状网
  • 6.1 实验目的
  • 6.2 预备知识
  • 6.3实验环境
  • 6.4实验原理
  • 6.5 实验内容
  • 6.6 实验步骤
  • 6.7 实验结果
  • 7 实验名称——网络拓扑-树状网
  • 7.1 实验目的
  • 7.2 预备知识
  • 7.3 实验环境
  • 7.4 实验原理
  • 7.5 实验内容
  • 7.6 实验步骤
  • 7.7 实验结果
  • 7.7 实验结果
  • 本文内容仅供参考,如有不足之处,欢迎大家指正

    1 实验名称——LED 控制实验

    LED 控制实验

    1.1 实验目的

  • 通过 I/O 控制小灯闪烁的过程
  • 在 ZXBee CC2530 节点板上运行自己的程序
  • 1.2 实验环境

  • 硬件: ZXBee CC2530 节点板一块, SmartRF 仿真器,PC 机,调试转接板
  • 软件: Windows XP/Windows 7/8/10 ,IAR 集成开发环境
  • 1.3 实验原理

    通过 CC2530 的 I/O 引脚,输出高低电平来控制 D6 及 D7 的亮与灭。

    CC2530 的 I/O 控制口一共有 21 个,分成 3 组,分别是 P0、P1 和 P2;由电路原理图可以看 出 D7 所对应的 I/O 口为 P1_0 ,D6 所对应的 I/O 口为 P1_1。

    如图为 LED 灯的驱动电路,本实验选择 P1_0 和 P1_1 I/O 引脚, P1_0 与 P1_1 分别控制 LED4(D7)和 LED3(D6),因此, 在软件上只要配置好 P1_0 口及 P1_1 口。

    无法显示图片时显示的文字


    LED 驱动电路图

    下面我们来看一下本次实验所用到的控制寄存器中每一位的取值所对应的意义:

    P1DIR (P1 方向寄存器,P0DIR 同理)

    P1SEL (P1 功能选择寄存器, P0SEL 同理)

    寄存器的设置:

    将控制寄存器的某一位置 1:

    例: P1DIR |= 0X02;

    解释:”|=“表示按位或运算,0X02 为十六进制数,转换成二进制数为 0000 0010 ,若 P1DIR 原 来的值为 0011 0000,或运算后 P1DIR 的值为 0011 0010。根据上面给出的取值表可知, 按位与运 算后 P1_1 的方向改为输出,其他 I/O 口方向保持不变。

    将控制寄存器某一位清 0:

    例: P1DIR &= ~0X02;

    解释:”&=“表示按位与运算,”~“运算符表示取反,0X02 为 0000 0010,即~0X02 为 1111 1101。 若 P1DIR 原来的值为 0011 0010,与运算后 P1DIR 的值为 0011 0000。

    1.4 实验内容

    通过上述实验原理得知,要实现 D6、D7 的点亮熄灭只需配置 P1_0、P1_1 口引脚即可, 然后将引脚适当的输出高低电平则可实现 D6、D7 的闪烁控制。 下面是源码实现的解析过程:

    /* 主函数 */
    void main(void){
        xtal_init();
        led_init();
        uart0_init(0x00, 0x00);		//初始化串口
        lcd_dis();				   //在LCD上显示实验内容、MAC地址等相关信息
        while(1){
        	led_test();
        }
    }
    

    主函数中主要实现了以下步骤:

    1)初始化 LED 灯即 led_init():设置 P1.0 和 P1.1 为普通 I/O 口, P1 方向为输出,关闭 D6、D7 灯。

    2)在主函数中使用 while(1) 等待 LED 灯开关的测试即可。

    通过下面的代码来解析 LED 灯的初始化:

    /* led初始化 */
    void led_init(void){
        P1SEL &= ~0x03;		//P1.0和P1.1为普通I/O口 
        P1DIR |= 0x03;		//输出
        D7 = 1;			   //关LED
        D6 = 1;
    }
    

    上述代码实现了 P1 选择寄存器和方向寄存器的设置,并将 LED 灯的电平置为高电平,即初始 状态下 LED 灯灭。接下来就只需要实现 LED 灯的轮流闪烁了, 通过下面的代码来解析 LED 灯开关的测试:

    /* led闪烁函数 */
    void led_test(void){
        D7 = 0;
        D6 = 1;
        Uart_Send_String("{data=D6=OFF;D7=ON}");		//在LCD上更新LED状态信息
        halWait(250);
        halWait(250);
        halWait(250);
        halWait(250);
        D7 = 1;
        D6 = 0;
        Uart_Send_String("{data=D6=ON;D7=OFF}");		//在LCD上更新LED状态信息
        halWait(250);
        halWait(250);
        halWait(250);
        halWait(250);
    }
    

    上述代码中,通过改变 LED 灯的电平高低来实现灯的亮与灭,即每隔 1s 让 LED 灯闪烁一次, 并在 LCD 上显示当前的 LED 状态。 为了增加实验效果,也可以手动更改闪烁时间。其中, 延时函数的代码如下:

    /* 延时函数 */
    void halWait(unsigned char wait){
        unsigned long largeWait;
    
        if(wait == 0){
            return;
        }
        largeWait = ((unsigned short) (wait << 7));
        largeWait += 114 * wait;
    
        largeWait = (largeWait >> CLKSPD);
        while(largeWait--);
    
        return;
    }
    

    下图 2.2.2 是本节 LED 实验的流程图:

    无法显示图片时显示的文字


    LED灯实验流程图

    通过图 2.2.2 流程图可得知,实现 D6、D7 的轮流闪烁, 会经过系统时钟初始化的过程,而且系 统时钟初始化是必须的, 8051 微处理器的正常运行,必须要经过系统初始化,也就是 xtal_init () 方法,该方法在 sys_init.c 源文件中定义。而在 main.c 中并没有看到调用系统时钟初始化的方法, 这是因为官方库文件已经将系统时钟初始化的方法的调用过程写进启动文件中了。 (在后面的所有章 节中也需要涉及到系统时钟的初始化, 将不再重复说明)

    1.5 实验步骤

    1. 正确连接 SmartRF04 仿真器到 PC 机和 ZXBee CC2530 节点板,确定按照第一章 1.2 节 设置节点板跳线为模式一, 打开 ZXBee CC2530 节点板电源(上电)。
    2. 打开实验工程: 在文件夹“05-实验例程\第 2 章\2.2-LED”下双击打开工程 LEDs.eww,选 择 Project->Rebuild All 重新编译工程。
    3. 将连接好的硬件平台上电(CC2530 务必按下开关上电),然后按下 SmartRF04 仿真器上 的复位按键。接下来选择 Project->Download and debug 将程序下载到 CC2530 节点板。
    4. 下载完后将 CC2530 重新上电或者按下复位按钮,观察两个 LED 的闪烁情况和 LCD 上的 显示内容。
    5. 修改延时函数,可以改变 LED 小灯的闪烁间隔时间。

    1.6 实验结果

    无法显示图片时显示的文字


    LED

    2 实验名称——温湿度传感器实验

    温湿度传感器实验

    2.1 实验目的

  • 掌握 DHT11 温湿度传感器的使用
  • 通过 CC2530 读取 DHT11 的温湿度数据,并通过串口显示出来
  • 2.2 实验环境

  • 硬件:ZXBee CC2530 节点板一块,温湿度传感器板一块,USB 接口 SmartRF04 仿真器,调试转接板, PC 机,USB mini 线
  • 软件: Windows XP/Windows 7/8/10 ,IAR 集成开发环境,串口调试工具(超级终端)
  • 2.3 实验原理

    本实验中通过 CC2530 IO 口模拟 DHT11 的读取时序,读取 DHT11 的温湿度数据。

    DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器 。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个 DHT11 传感器都在极为精确的 湿度校验室中进行校准。校准系数以程序的形式储存在 OTP 内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达 20 米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。使用 4 针单排引脚封装。连接方便。

    温湿度模块与 CC2530 部分接口电路如下图 3.2.1 所示:

    无法显示图片时显示的文字


    温湿度模块与CC2530 部分接口电路

    下面介绍一下 DHT11 的获取温湿度值的原理:

    DHT11 的串行接口

    DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次通讯时间 4ms 左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为 零。操作流程如下:

    一次完整的数据传输为 40bit ,高位先出。

    数据格式:8bit 湿度整数数据 +8bit 湿度小数数据 +8bit 温度整数数据 +8bit 温度小数数据+8bit 校验和数据传送正确时校验和数据等于“ 8bit 湿度整数数据 +8bit 湿度小数数据+8bit 温度整数数 据 +8bit 温度小数数据 ” 所得结果的末 8 位。 CC2530 发送一次开始信号后, DHT11 从低功耗模 式转换到高速模式, 等待主机开始信号结束后,DHT11 发送响应信号,送出 40bit 的数据,并触 发一次信号采集, 用户可选择读取部分数据。从模式下, DHT11 接收到开始信号触发一次温湿度采 集, 如果没有接收到主机发送开始信号, DHT11 不会主动进行温湿度采集。采集数据后转换到低速 模式。

    通讯过程如下所示:

    无法显示图片时显示的文字


    通讯过程(一)

    总线空闲状态为高电平,主机把总线拉低等待 DHT11 响应,主机把总线拉低必须大于 18 毫秒,保证 DHT11 能检测到起始信号。 DHT11 接收到主机的开始信号后, 等待主机开始信号结束,然后发送 80us 低电平响应信号。主机发送开始信号结束后,延时等待 20-40us 后,读取 DHT11 的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。

    无法显示图片时显示的文字


    通讯过程(二)

    总线为低电平, 说明 DHT11 发送响应信号, DHT11 发送响应信号后, 再把总线拉高 80us,准 备发送数据,每一 bit 数据都以50us 低电平时隙开始,高电平的长短定了数据位是 0 还是 1 。 格 式见下面图示。如果读取响应信号为高电平,则 DHT11 没有响应, 请检查线路是否连接正常。当最 后一 bit 数据传送完毕后, DHT11 拉低总线 50us , 随后总线由上拉电阻拉高进入空闲状态。

    数字 0 信号表示方法如下图所示:

    无法显示图片时显示的文字


    通讯过程(三)

    数字 1 信号表示方法如下图所示:

    无法显示图片时显示的文字


    通讯过程(四)

    2.4 实验内容

    本实验通过 CC2530 IO 口模拟 DHT11 的读取时序,读取 DHT11 的温湿度数据,读取到温湿 度之后通过串口打印出来。

    根据温湿度传感器 DHT11 的工作原理以及温湿度数据读取时序,通过编程实现温湿度值的采集,下面是源码实现的解析过程:

    void main(void){
        xtal_init();
        led_init();
        dht11_io_init();
        uart0_init(0x00, 0x00);		//初始化串口
    
        #ifdef SPI_LCD			//如果宏定义了SPI_LCD 
        lcd_dis();				//在屏幕上显示相关信息
        #endif
    
        while(1){
            halWait(250);
            halWait(250);
            halWait(250);
            halWait(250);
            dht11_update();
            D7 = !D7;
        }
    }
    

    主函数中主要实现了以下步骤:

    1. 初始化系统时钟 xtal_init():选用 32MHz 晶体振荡器。
    2. 初始化 LED led_init() :设置 P1.0 和 P1.1 为普通 I/O 口,设置 P1 方向为输出,然后关闭 D6、D7 灯。
    3. 初始化温湿度传感器 dht11_io_init():配置 P1.5 I/O 口。
    4. 初始化串口 uart0_init() :配置 I/O 口、设置波特率、奇偶校验位和停止位。
    5. 函数中使用 while(1) 每隔 1s 更新温湿度的值并让 D7 灯闪烁。

    上述代码实现了获取温湿度的值并将数据从串口打印输出,每更新一次数据, D7 灯闪烁一次, 其中,初始化温湿度传感器的代码如下:

    /* 初始化温湿度传感器 */
    void dht11_io_init(void){
        P0SEL &= ~0x20;		//P1为普通I/O口
        COM_OUT;
        COM_SET;
    }
    

    函数 dht11_update()实现每隔 1s 更新传感器的数值,代码如下:

    /* 更新数值 */
    void dht11_update(void){
        int flag = 1;
        unsigned char dat1, dat2, dat3, dat4, dat5, ck;
    
        //主机拉低 18ms
        COM_CLR;
        halWait(18);
        COM_SET;
    
        flag = 0;
        while (COM_R && ++flag);
        if (flag == 0) return;
    
        //总线由上拉电阻拉高 主机延时 20us
        //主机设为输入 判断从机响应信号
        //判断从机是否有低电平响应信号 如不响应则跳出, 响应则向下运行
        flag = 0;
        while (!COM_R && ++flag);
        if (flag == 0) return;
        flag = 0;
        while (COM_R && ++flag);
        if (flag == 0) return;
        dat1 = dht11_read_byte();
        dat2 = dht11_read_byte();
        dat3 = dht11_read_byte();
        dat4 = dht11_read_byte();
        dat5 = dht11_read_byte();
        ck = dat1 + dat2 + dat3 + dat4;
        if (ck == dat5) {
            sTemp = dat3;
            sHumidity = dat1;
        }
        #ifdef SPI_LCD                                              //如果宏定义了SPI_LCD
        char   dbuf[20] = {0};
        sprintf(dbuf,"{A0=%u,A1=%u}",dat1,dat3); //A0 表示湿度,A1 表示温度
        Uart_Send_String(dbuf);
        #else
        printf("湿度: %u.%u%% 温度: %u.%u℃ \r\n", dat1,dat2, dat3,dat4);
        #endif
    }
    

    无法显示图片时显示的文字


    温湿度实验流程图

    2.5 实验步骤

    1. 准备好带有温湿度传感器的 CC2530 射频板, 确定按照第一章 1.2 节设置节点板跳线为模式一,将 SmartRF04 仿真器连接到该 CC2530 射频板上,接上出厂电源。
    2. 通过 USB mini 线和调试转接板,正确的连接 PC 和 ZXBee CC2530 无线节点板 (第一次连接需要安装驱动)。
    3. 打开例程“05-实验例程\第 3 章\3.2-HumiTemp-DHT11”,双击 dht11.eww,打开本实验工程文件。
    4. 选择 Project->Rebuild All 重新编译工程。
    5. 上电 CC2530 节点板, 然后按下连接好的 SmartRF04 仿真器的复位按键;接下来点击 IAR 菜单 Project->Download and debug,将程序下载程序到 CC2530 射频板上。
    6. 在 PC 上打开超级终端或串口调试助手, 设置波特率为 38400,8 数据位, 1 停止位, 无硬 件流控。
    7. 将 CC2530 射频板上电并复位,运行刚才下载的程序。观察 PC 机串口中输出的温度、湿 度实验数据。

    2.6 实验结果

    程序运行后串口输出当前的温湿度值。 并且在节点的 LCD 上会有温湿度值的显示。

    无法显示图片时显示的文字


    温湿度实验图

    无法显示图片时显示的文字


    温湿度结果图

    3 实验名称——人体红外传感器实验

    人体红外传感器实验

    3.1 实验目的

  • 了解人体红外传感器原理;

  • 通过 CC2530 和人体红外传感器实现人体检测。

  • 3.2 实验环境

  • 硬件: ZXBee CC2530 节点板一块,人体传感器板一块,USB 接口 SmartRF04 仿真器,调试转接板, PC 机,USB mini 线;
  • 软件: Windows XP/Windows 7/8/10,IAR 集成开发环境。
  • 3.3 实验原理

    普通人体会发射 10um 左右的特定波长红外线,用专门设计的传感器就可以针对性的检测这种红外线的存在与否,当人体红外线照射到传感器上后,因热释电效应将向外释放电荷,后续电路经检测处理后就能产生控制信号。

    热释电效应同压电效应类似,是指由于温度的变化而引起晶体表面荷电的现象。热释电传感器是对温度敏感的传感器。它由陶瓷氧化物或压电晶体元件组成,在元件两个表面做成电极,在传感器监测范围内温度有ΔT的变化时,热释电效应会在两个电极上会产生电荷ΔQ,即在两电极之间产生一微弱的电压ΔV。由于它的输出阻抗极高,在传感器中有一个场效应管进行阻抗变换。热释电效应所产生的电荷ΔQ 会被空气中的离子所结合而消失,即当环境温度稳定不变时,ΔT=0,则传感器无输出。当人体进入检测区,因人体温度与环境温度有差别,产生ΔT,则有ΔT 输出;若人体进入检测区后不动,则温度没有变化,传感器也没有输出了。所以这种传感器检测人体或者动物的活动传感。由实验证明,传感器不加光学透镜(也称菲涅尔透镜),其检测距离小于 2m,而加上光学透镜后,其检测距离可大于 7m。

    红外线传感器是利用红外线的物理性质来进行测量的传感器。红外线又称红外光,它具有反射、折射、散射、干涉、吸收等性质。任何物质,只要它本身具有一定的温度(高于绝对零度),都能辐射红外线。红外线传感器测量时不与被测物体直接接触,因而不存在摩擦,并且有灵敏度高,反应快等优点。

    红外线传感器包括光学系统、检测元件和转换电路。光学系统按结构不同可分为透射式和反射式两类。检测元件按工作原理可分为热敏检测元件和光电检测元件。热敏元件应用最多的是热敏电阻。热敏电阻受到红外线辐射时温度升高,电阻发生变化(这种变化可能是变大也可能是变小,因为热敏电阻可分为正温度系数热敏电阻和负温度系数热敏电阻),通过转换电路变成电信号输出。光电检测元件常用的是光敏元件,通常由硫化铅、硒化铅、砷化铟、砷化锑、碲镉汞三元合金、锗及硅掺杂等材料制成。

    红外线传感器常用于无接触温度测量,气体成分分析和无损探伤,在医学、军事、空间技术和环境工程等领域得到广泛应用。例如采用红外线传感器远距离测量人体表面温度的热像图,可以发现温度异常的部位,及时对疾病进行诊断治疗(见热像仪);利用人造卫星上的红外线传感器对地球云层进行监视,可实现大范围的天气预报;采用红外线传感器可检测飞机上正在运行的发动机的过热情况等。

    具有红外传感器的望远镜可用于军事行动,林地战探测密林中的敌人,城市战中探测墙后面的敌人,以上均利用了红外线传感器测量人体表面温度从而得知敌人所在地。

    人体红外传感器检测到有人体活动时,其输出的 IO 值发生变化。当传感器模块检测到有人入侵时,会返回一个高电平信号,无人入侵时,返回一个低电平信号, 通过读取 io 口的状态判断是否有人体活动。

    通过查看人体红外传感器的电路原理图(出厂光盘 01-文档资料\01-原理图\传感器目录下的 Infrared – 人体红外.pdf 文件)得知, 人体红外传感器模块与CC2530 开发板部分接口电路如下:

    无法显示图片时显示的文字


    人体红外模块与 CC2530 的接口原理图

    根据 CC2530 开发板的电路原理图得知,图 3.8.1 中的 GPIO 连接到 CC2530 的 P0_5 口,因此通过检测此 IO 口电平状态的变化,可判断是否检测到周围有人靠近。

    3.4 实验内容

    通过实验原理得知, 本实验的关键就是配置 P0_5 口,将其设置成输入模式来检测人体红外传感 器输出的电平变化。 下面是源码实现的解析过程:

    /*主函数
    -------------------------------------------------------*/
    void main(void){
        xtal_init();
        led_init();
        uart0_init(0x00, 0x00);		  //初始化串口
        #ifdef SPI_LCD				 //如果宏定义了SPI_LCD 
        lcd_dis();					//在屏幕上显示相关信息
        #endif
    
        P0SEL &= ~0x20;				//P0_5 为普通io口
        P0DIR &= ~0x20;				//P0_5 输入
    
        while(1){
        	Infrared_Test();
        }
    }
    

    人体红外测试函数的源码解析如下:

    /*Infrared_Test函数
    -------------------------------------------------------*/
    void Infrared_Test(void){
        char Str[10];
        int Value;
    
        Value = P0_5;			//P0_5 与GPIO相连    
    #ifdef SPI_LCD				//如果宏定义了SPI_LCD
        char dbuf[20] = {0};
        sprintf(dbuf,"{A0=%d}",Value);
        Uart_Send_String(dbuf);		//在屏幕上更新传感器的值
    #else
        char Str[10];
        sprintf(Str,"%d\r\n",Value);
        Uart_Send_String(Str);		//串口发送数据
    #endif halWait(250);			//延时
        D7=!D7;					   //标志发送状态
        halWait(250);
        halWait(250);
    }
    

    下面是本实验的流程图:

    无法显示图片时显示的文字


    人体红外传感器实验流程图

    3.5 实验步骤

    1. 准备好带有人体红外感应传感器的 CC2530 射频板,确定按照第一章 1.2 节设置节点板跳线为模式一,将SmartRF04 仿真器连接到该 CC2530 射频板上,接上出厂电源。通过 USB mini 线和调试转接板,正确的连接 PC 和 ZXBee CC2530 无线节点板(第一次连接需要安装驱动)。
    2. 打开例程“05-实验例程\第 3 章\3.8-Infrared”,双击 Infrared.eww,打开本实验工程文件。
    3. 选择 Project->Rebuild All 重新编译工程。
    4. 上电 CC2530 节点板,然后按下连接好的 SmartRF04 仿真器的复位按键;接下来点击 IAR 菜单 Project->Download and debug,将程序下载程序到 CC2530 射频板上。
    5. 在 PC 上打开超级终端或串口调试助手, 设置波特率为 38400 ,8 数据位, 1 停止位,无硬件流控。
    6. 将 CC2530 射频板上电并复位,运行刚才下载的程序。
    7. 人体靠近节点或者用手在节点面前晃动,观察 IO 值的变化;几秒后,人体远离节点 1 米左 右,观察 IO 值的变化。

    3.6 实验结果

    当检测到有人体活动时,串口显示 IO 值为 1 。在节点的 LCD 上也有相关显示。

    无法显示图片时显示的文字


    人体红外传感器实验图

    4 实验名称——点对点通信实验

    点对点通信实验

    4.1 实验目的

  • 在 ZXBee CC2530 节点板上运行相应实验程序
  • 熟悉通过射频通信的基本方法
  • 练习使用状态机实现收发功能
  • 4.2 实验环境

  • 硬件: ZXBee CC2530 节点板 2 块、 USB 接口的 SmartRF04 仿真器 ,调试转接板 PC 机、USB mini 线
  • 软件: Windows XP/Windows 7/8/10 、IAR 集成开发环境、串口监控程序
  • 4.3 实验原理

    ZigBee 的通讯方式主要有三种:点播、组播、广播。点播, 顾名思义就是点对点通信,也就是 2 个设备之间的通讯,不容许有第三个设备收到信息;组播,就是把网络中的节点分组,每一个组员发出的信息只有相同组号的组员才能收到;广播,最广泛的也就是一个设备上发出的信息所有设备都能接收到。这也是 ZigBee 通信的基本方式。

    在点对点通信的过程中, 先将接收节点上电后进行初始化, 然后通过指令 ISRXON 开启射频接收器,等待接收数据,直到正确接收到数据为止,通过串口打印输出。发送节点上电后和接收节点进行相同的初始化,然后将要发送的数据输出到 TXFIFO 中,再调用指令 ISTXONCCA 通过射频前端发送数据。

    4.4 实验内容

    在本实验中,主要是实现 ZigBee 点播通信。发送节点将数据通过射频模块发送到指定的接收节点,接收节点通过射频模块收到数据后,再通过串口发送到 PC 机在串口调试助手中显示出来。如果发送节点发送的数据目的地址与接收节点的地址不匹配,接收节点将接收不到数据。 下面是源码实现的解析过程:

    void main(void){
        halMcuInit();			//初始化mcu
        hal_led_init();			//初始化LED
        hal_uart_init();		//初始化串口
        lcd_dis();				//在LCD上显示实验内容、 MAC地址等相关信息
    
        if (FAILED == halRfInit()) {		// halRfInit()为射频初始化函数
            HAL_ASSERT(FALSE);
        }
        // Config basicRF
        basicRfConfig.panId = PAN_ID;			//panId
        basicRfConfig.channel = RF_CHANNEL;		//通信信道
        basicRfConfig.ackRequest = TRUE;		//应答请求
    #ifdef SECURITY_CCM
        basicRfConfig.securityKey = key;		//安全秘钥
    #endif	
    
    	// Initialize BasicRF
    #if NODE_TYPE
    	basicRfConfig.myAddr = SEND_ADDR;		//发送地址
    #else
    	basicRfConfig.myAddr = RECV_ADDR;		//接收地址
    #endif
    
        if(basicRfInit(&basicRfConfig)==FAILED) { 
            HAL_ASSERT(FALSE);
        }	
    
    #if NODE_TYPE
    	rfSendData();		//发送数据
    #else
    	rfRecvData();		//接收数据
    #endif
    }
    

    主函数中主要实现了以下步骤:

    1. 初始化 mcu 即 halMcuInit() :选用 32k 时钟。
    2. 初始化 LED 灯 hal_led_init() :设置 P1.0、 P1.2 和 P1.3 为普通 I/O 口并将其作为输出, 设置 P2.0 为普通 I/O 口并将其作为输出。
    3. 初始化串口 hal_uart_init() :配置 I/O 口、设置波特率、奇偶校验位和停止位。
    4. 初始化射频模块 halRfInit() ,设置网络 ID、通信信道,定义发送地址和接收地址。
    5. 接收节点调用 rfRecvData()函数来接收数据, 发送节点调用 rfSendData()函数来发送数据。

    通过下面的代码来解析射频模块的初始化:

    uint8 halRfInit(void){
        // Enable auto ack and auto crc
        FRMCTRL0 |= (AUTO_ACK | AUTO_CRC);
    
        // Recommended RX settings
        TXFILTCFG = 0x09;
        AGCCTRL1 = 0x15;
        FSCAL1 = 0x00;
    
        // Enable random generator -> Not implemented yet
        // Enable CC2591 with High Gain Mode
        halPaLnaInit();
        // Enable RX interrupt
        halRfEnableRxInterrupt();
    
        return SUCCESS;
    }
    

    节点发送数据和接收数据的代码实现如下:

    /* 射频模块发送数据函数 */
    void rfSendData(void){                                                                             
        //定义要发送的数据
    	char pTxData[30] = {'H', 'e', 'l', 'l', 'o', ' ', 'c', 'c', '2', '5', '3', '0',' '};
    	uint8 ret;
    
        static unsigned int send_counter = 0;		//发送次数计数器
        // Keep Receiver off when not needed to save power
        basicRfReceiveOff();			//关闭射频接收器
    
        // Main loop
        while (TRUE) {		//点对点发送数据包
            ret = basicRfSendPacket(RECV_ADDR, (uint8*)pTxData, sizeof pTxData);
            printf("{data=send node send %d times}",++send_counter);         //在LCD上显示发送次数
            if (ret == SUCCESS) {
                hal_led_on(1);
                halMcuWaitMs(100);
                hal_led_off(1);
                halMcuWaitMs(900);
            } else {
                hal_led_on(1);
                halMcuWaitMs(1000);
                hal_led_off(1);
            }
        }
    }
    
    
    /* 射频模块接收数据函数 */
    void rfRecvData(void){
        uint8 pRxData[128];
        int rlen;
        static unsigned int rec_counter = 0;			//接收次数计数器
        printf("{data=recv node start up...}");
        basicRfReceiveOn();						//开启射频接收器
        // Main loop
    
        while (TRUE) {
            while(!basicRfPacketIsReady());
            rlen = basicRfReceive(pRxData, sizeof pRxData, NULL);
    
            if(rlen > 0) {
                pRxData[rlen] = 0;
                printf("{data=");                     //将收到的
                printf((char *)pRxData);			 //数据和
                printf(" %d",++rec_counter);		 //接收到数据的次数 
                printf("}");						//在LCD上显示出来
            }
    	}
    }
    
    

    接收节点和发送节点的程序流程图如下面两图所示:

    无法显示图片时显示的文字


    接收节点程序流程图                                                                发送节点程序流程图

    4.5 实验步骤

    1. 准备两个 CC2530 无线节点板(参考 1.3 章节, 将无线节点板跳线设置为模式一),分别接上出厂电源;

    2. 在 PC 机上打开串口终端软件,设置好波特率为 38400,8 数据位, 1 停止位, 无硬件流控。

    3. 双击本实验程序“第 4 章\4.1-P2P”双击 p2p.eww ,打开本实验工程文件。

    4. 打开 main.c 文件,下面对一些定义进行介绍。 RF_CHANNEL 宏定义了无线射频通信时使用的信道,在实验室中,多个小组同时进行实验时建议每组选择不同时信道,即每个小组使用不同的 RF_CHANNEL 值(可按顺序编号)。但同一组实验中两个节点需要保证在同一信道, 才能正确通 信。

    5. PAN_ID 个域网 ID 标示,用来表示不同在网络,在同一实验中,接收和发送节点需要配置为相同的值,否则两个节点将不能正常通信。

      SEND_ADDR 发送节点的地址;

      RECV_ADDR 接收节点的地址。

    6. NODE_TYPE 节点类型: 0-接收节点,1-发送节点。在进行实验时一个节点定义为发送节点用来发送数据,一个定义为接收节点用来接收数据。

    7. 修改 main.c 文件中的 NODE_TYPE 的值为 0,保存, 然后选择 Project->Rebuild All 重新编译工程。

    8. 将 SmartRF04 仿真器连接 到 串 口与 PC 机相连接 的 CC2530 节 点上,点击菜单 Project->Download and debug 下载程序到节点板。此节点以下称为接收节点。

    9. 修改 main.c 文件中的 NODE_TYPE 的值为 1,然后点击保存,然后选择 Project->Rebuild All 重新编译工程。

    10. 接下来将接收节点断电,取下 SmartRF04 仿真器连接到另外一个节点上,点击菜单 Project->Download and debug 下载程序到节点板。此节点板以下称为发送节点。

    11. 通过 USB mini 线和调试转接板连接接收节点和 PC,打开串口终端软件。

    12. 先将接收节点上电。查看 PC 机上的串口输出。接下来将发送节点上电。

    13. 从 PC 机上串口调试助手观察接收节点收到的数据。

    可以修改发送节点中发送数据的内容,然后编译并下载程序到发送节点,然后从串口调试助手 观察收到的数据。

    可以修改接收节点的地址,然后重新编译并下载程序到接收节点,然后从发送节点发送数据, 观察接收节点能正确接收数据。

    4.6 实验结果

    发送节点将数据发送出去后,接收节点接收到数据, 并通过串口调试助手打印输出。发送数据的最大长度为 125 (加上发送的数据长度和校验,实际发送的数据长度为 128 字节)。在发送节点的 LCD 上会显示发送次数,在接收节点的屏幕上会显示收到的数据和收到数据的次数。

    无法显示图片时显示的文字


    点对点通信实验图

    无法显示图片时显示的文字


    点对点通信结果图

    5 实验名称——广播通信实验

    广播通信实验

    5.1 实验目的

  • 在 ZXBee CC2530 节点板上运行自己的程序
  • 理解广播的实现方式
  • 5.2 实验环境

  • 硬件: ZXBee CC2530 节点板 3 块、USB 接口的 SmartRF04 仿真器,调试转接板,PC 机,USB mini 线
  • 软件: Windows XP/Windows 7/8/10 、IAR 集成开发环境、串口监控程序
  • 5.3 实验原理

    ZigBee 协议中, 数据包能被单播传输、组播传输或者广播传输。

    当应用程序需要将数据包发送给网络的每一个设备时使用广播模式 ,地址模式设置为 AddrBroadcast , 目标地址可以设置为下面广播地址的一种:

    NWK_BROADCAST_SHORTADDR_DEVALL(0xFFFF) ——数据包将被传送到网络上的所有设备包括睡眠中的设备。对于睡眠中的设备数据包将被保留在其父亲节点直到查询到它或者消息超时(NWK_INDIRECT_MSG_TIMEO 在 f8wConifg.cfg 中)。

    NWK_BROADCAST_SHORTADDR_DEVRXON(0xFFFD) ——数据包将被传送到网络上的所有的打开接收的空闲设备(RXONWHENIDLE) ,也就是除了睡眠中的所有设备。

    NWK_BROADCAST_SHORTADDR_DEVZCZR(0xFFFC)——数据包发送给所有的路由器,包括协调器。

    5.4 实验内容

    在本实验中,主要是实现 ZigBee 广播通信。在发送节点中设置目的地址为广播地址,让发送节点发送数据,接收节点在接收到数据后对接收到的数据的目的地址进行判断,若目的地址为自己的地址或广播地址则接收数据,否则不接收数据。

    广播通信实验在点对点射频通信实验的基础上做了如下修改:

    1. 在 main.c 文件中修改发送节点和接收节点的地址宏;
    2. 修改 basicRfSendPacket 函数的第一个参数,将其改为广播地址 0xFFFF 。修改如下:
    ret = basicRfSendPacket(0xffff,pTxData,sizeof pTxData) ;
    

    实验中一个节点通过射频向外广播数据"hello world!“,如果数据成功发送出去,则发送节点向串口打印"packet sent successfull!” ,否则打印"packet sent failed!";接收节点接收到数据后向串口打印输出"packet received!"和接收的数据内容。

    下面是源码实现的解析过程:

    void main(void){
        halMcuInit();				//初始化mcu
        hal_led_init();				//初始化LED
        hal_uart_init();			//初始化串口
        lcd_dis();
        if (FAILED == halRfInit()) {	//halRfInit()为初始化射频模块函数
        	HAL_ASSERT(FALSE);
        }
        // Config basicRF
        basicRfConfig.panId = PAN_ID;	//panID
        basicRfConfig.channel = RF_CHANNEL;		//通信信道
        basicRfConfig.ackRequest = TRUE; 		//应答请求
       
    #ifdef SECURITY_CCM
        basicRfConfig.securityKey = key; 		//安全秘钥
    #endif
    
    	// Initialize BasicRF
    #if NODE_TYPE
    	basicRfConfig.myAddr = SEND_ADDR; 		//发送地址
    #else
    	basicRfConfig.myAddr = RECV_ADDR; 		//接收地址
    #endif
        if(basicRfInit(&basicRfConfig)==FAILED) {
        	HAL_ASSERT(FALSE);
        }                  
    #if NODE_TYPE
    	rfSendData(); 			//发送数据
    #else
    	rfRecvData();			//接收数据
    #endif
    }
    

    主函数中主要实现了以下步骤:

    1. 初始化 mcu 即 halMcuInit():选用 32k 时钟。
    2. 初始化 LED 灯 hal_led_init():设置 P1.0、P1.2 和 P1.3 为普通 I/O 口并将其作为输出,设置 P2.0 为普通 I/O 口并将其作为输出。
    3. 初始化串口 hal_uart_init():配置 I/O 口、设置波特率、奇偶校验位和停止位。
    4. 初始化射频模块 halRfInit(),设置网络 ID、通信信道,定义发送地址和接收地址。
    5. 接收节点调用 rfRecvData()函数来接收数据, 发送节点调用 rfSendData()函数来发送数据。

    通过下面的代码来解析射频模块的初始化:

    /* 初始化射频模块 */
    uint8 halRfInit(void){
        // Enable auto ack and auto crc
        FRMCTRL0 |= (AUTO_ACK | AUTO_CRC);
    
        // Recommended RX settings
        TXFILTCFG = 0x09;
        AGCCTRL1 = 0x15;
        FSCAL1 = 0x00;
    
        // Enable random generator -> Not implemented yet
    
        // Enable CC2591 with High Gain Mode
        halPaLnaInit();
    
        // Enable RX interrupt
        halRfEnableRxInterrupt();
    
        return SUCCESS;
    }
    

    节点发送数据和接收数据的代码实现如下:

    /* 射频模块发送数据函数 */
    void rfSendData(void){			//定义要发送的数据
        char pTxData[30] = {'H', 'e', 'l', 'l', 'o', ' ', 'c', 'c', '2', '5', '3', '0',' '}; 
        uint8 ret;
    	static unsigned int send_counter = 0;		//发送次数计数器
    	// Keep Receiver off when not needed to save power 
        basicRfReceiveOff();		//关闭射频接收器
        // Main loop
    	while (TRUE) {
            printf("{data = ");			//通过LCD显示
            printf("Broadcast: %s", pTxData);		//广播内容
            printf("    for %d times}", ++send_counter);		//和广播次数
            ret = basicRfSendPacket(0xffff, (uint8*)pTxData, sizeof pTxData);//广播发送数据包
            if (ret == SUCCESS) {
                hal_led_on(1);
                halMcuWaitMs(100);
                hal_led_off(1);
                halMcuWaitMs(900);
            } else {
                hal_led_on(1);
                halMcuWaitMs(1000);
                hal_led_off(1);
            }
    	}
    }
    /* 射频模块接收数据函数 */
    void rfRecvData(void){
        uint8 pRxData[128];
        int rlen;
    	static unsigned int rec_counter = 0;	//接收次数计数器
    	basicRfReceiveOn();					//开启射频接收器
    	// Main loop
    	while (TRUE) {	
        	while(!basicRfPacketIsReady());
        	rlen = basicRfReceive(pRxData, sizeof pRxData, NULL);
            if(rlen > 0) {
                pRxData[rlen] = 0;
                printf("{data = ");		//在LCD上显示
                printf("My Address 0x%x,receive:", RECV_ADDR); 	//接收节点的地址
                printf((char *)pRxData);		//和接收节点收到的数据
                printf("for %d times}",++rec_counter);		//以及接收到的广播包的次数
            }
        }
    }
    

    接收节点和发送节点的程序流程图如下面两图所示:

    无法显示图片时显示的文字


    接收节点程序流程图                                                                发送节点程序流程图

    5.5 实验步骤

    1. 准备 3 个 CC2530 无线节点板(参考 1.3 章节,将无线节点板跳线设置为模式一),分别接上出厂电源。
    2. 打开光盘“第 4 章\4.2-BroadcastCommunication”,双击 p2p.eww,打开本实验工程文件。
    3. 按实验原理修改程序。先将 main.c 中的节点类型变量 NODE_TYPE 的值设置为 0 作为接收节点,然后选择 Project->Rebuild All 重新编译工程。
    4. 将 SmartRF04 仿真器连接到其中一个 CC2530 节点板,上电 CC2530 节点板,然后点击菜单 Project->Download and debug 下载程序到节点板。此节点以下称为接收节点 1。
    5. 修改 main.c 中的节点短地址 RECV_ADDR 的值为 0x2510,保存,然后选择 Project->Rebuild All 重新编译工程。接下来通过 SmartRF04 仿真器把程序下载到另外一个 CC2530 节点板中,称为接收节点 2。
    6. 将节点类型变量 NODE_TYPE 的值设置为 1,保存。然后选择 Project->Rebuild All 重新编译工程编译工程,并下载到 ZXBee CC2530 节点板中,作为发送节点。
    7. 将发送节点通过 USB mini 线和调试转接板连接到 PC 上,在 PC 机上打开串口调试助手,配置串口助手波特率为 38400,8 数据位,1 停止位,无硬件流控。
    8. 给发送节点重新上电,观察发送节点 LCD 上的显示内容。
    9. 将接收节点 1 和接收接点 2 上电,依次通过串口线连接到 PC 上,可以看到串口调试助手上打印出相关信息。

    5.6 实验结果

    实验中,只要节点为接收数据的节点,便能接收数据,实现了射频广播的功能,事实上,若不考虑收发数据的地址,即是广播。

    在广播节点 LCD 上显示:Broadcast:Hello cc2530 for 12 times,其中 12 表示广播节点的广播次数。

    在接收节点上显示 My Address 0x2520,receive:Hello cc2530 for 10 times。其中 0x2520 表示节点的地址,10 表示收到的广播包次数。不同的接收节点显示的节点地址不同。

    无法显示图片时显示的文字


    广播通信实验图

    无法显示图片时显示的文字


    广播通信结果图

    6 实验名称——网络拓扑-星状网

    网络拓扑-星状网

    6.1 实验目的

  • 理解 zigbee 协议及相关知识
  • 在 zstack 协议栈下实现星状网络拓扑的控制
  • 6.2 预备知识

    掌握在 IAR 集成开发环境中编写和调试程序的基本过程;

    了解 zstack 协议栈架构。

    6.3实验环境

  • 硬件: ZXBee CC2530 节点板, USB 接口的 SmartRF04 仿真器,PC 机 Pentium100以上;
  • 软件: PC 机操作系统 WinXP ,IAR 集成开发环境, ZigBee Sensor Monitor
  • 6.4实验原理

    ZigBee 有三种网络拓扑, 即星形、树形和网状网络,这三种网络拓扑在 zstack 协议栈下均可实现。星形网络中,所有节点只能与协调器进行通信,而他们相互之间的通信是禁止的;树形网络中,终端节点只能与它的父节点通信,路由节点可与它的父节点和子节点通信;网状网络中,全功能节点之间是可以相互通信的。

    在 zstack 中, 通过设置宏定义 STACK_PROFILE_ID 的值(在 nwk_globals.h 中定义) 可以选择不同控制模式(总共有三种控制模式, 分别为 HOME_CONTROLS 、GENERIC_STAR 和NETWORK_SPECIFIC,默认模式为 HOME_CONTROLS),再选择不同的网络拓扑(NWK_MODE),也可以只修改 HOME_CONTROLS 的网络模式 (NWK_MODE),来选择不同的网络拓扑,由于网络的组建是由协调器来控制的,因此只需修改协调器的程序即可。此外,可以设定数组 CskipRtrs 和 CskipChldrn 的值(在 nwk_globals.c 中定义)进一步控制网络的形式,CskipChldrn 数组的值代表每一级可以加入的子节点的最大数目,CskipRtrs 数组的值代表每一级可以加入的路由节点的最大数目 , 如在星形网络 中,定 义 CskipRtrs[MAX_NODE_DEPTH+1] = {5,0,0,0,0,0} ,CskipChldrn[MAX_NODE_DEPTH+1] = {10,0,0,0,0,0},代表只有协调器允许节点加入, 且协调器最多允许 10 个子节点加入,其中最多5 个路由节点,剩余的为终端节点。本实验已通过宏定义(在工 程 options 中的 preprocessor 中定义)设定了数组的大小。

    6.5 实验内容

    配置网络拓扑为星形网络,启动协调器节点,协调器节点上电后进行组网操作,再启动路由节点和终端节点,路由节点和终端节点上电后进行入网操作,成功入网后周期的将父节点的短地址,自己的节点信息封装成数据包发送给 sink 节点 (汇聚节点,也称协调器),sink 节点接收到数据包后通过串口传给 PC,从 PC 上的 ZigBee Sensor Monitor 程序查看组网情况。

    下图为本实验的数据流程图:

    无法显示图片时显示的文字


    数据流程图

    在本实验中设定路由节点、终端节点每隔 2 秒钟向协调器发送自己的网络信息包, 下面结合本实验的实验原理以及实验内容的设计,分别对终端节点、路由节点和协调器节点的源关键源程序进行解析。

    终端节点、路由节点

    根据本节内容的设计, 终端节点、路由节点加入 zigbee 网络后, 每隔一段时间上报自己的网络信息,因此终端节点和路由节点的任务事件都一样。通过 5.2 节的工程解析实验可得知,在程序源代码 MPEndPont.c 或 MPRouter.c 中 ZStack 协议栈成功启动后,设置了一个定时器事件, 当定时器事件触发后就会触发用户的 MY_REPORT_EVT 事件,触发 MY_REPORT_EVT 事件的函数入口为 MPRouter.c (或 MPEndPont.c) 中的 zb_HandleOsalEvent 函数,在该函数中编写了应用程序事件的处理过程,如下述代码所示。

    void zb_HandleOsalEvent( uint16 event ){
    	uint8 logicalType;
    
    	if(event & SYS_EVENT_MSG){		//系统事件信息
    
    	}
        if( event & ZB_ENTRY_EVENT ){		//zigbee入网事件
            // blind LED 2 to indicate starting/joining a network
            //入网成功后LED灯闪烁
            HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
            HalLedBlink ( HAL_LED_2, 0, 50, 500 );
    
    		logicalType = ZG_DEVICETYPE_ROUTER;		//设备的节点类型
    		zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);	//将数据写入NV
            
            // Start the device
    		zb_StartRequest();			//开启网络设备
    	}
        if ( event & MY_START_EVT ){		//启动ZStack协议栈事件
        	zb_StartRequest();
        }
        if ( event & MY_REPORT_EVT ){		// MY_REPORT_EVT事件触发处理
    		if (appState == APP_BINDED){
    			//调用函数发送数据
    			sendDummyReport();
            	//启动定时器,触发 MY_REPORT_EVT事件
    			osal_start_timerEx( sapi_TaskID, MY_REPORT_EVT, myReportPeriod );
    		}
    	}
    	if (event & MY_FIND_COLLECTOR_EVT){		//MY_FIND_COLLECTOR_EV事件触发处理
    		// Find and bind to a gateway device (if this node is not gateway)
    		zb_BindDevice( TRUE, DUMMY_REPORT_CMD_ID, (uint8 *)NULL );
    	}
    }
    

    通过上述源码可以看到,当处理 MY_REPORT_EVT 事件时, 调用了sendDummyReport()方法(MPEndPont.c 中的 MY_REPORT_EVT 事件调用的是 sendReport()方法),然后又设置了一个定时器事件来触发 MY_REPORT_EVT 事件 ,这样做的目的就是为了每隔一段时间循环触发 MY_REPORT_EVT 事件。了解了 MY_REPORT_EVT 事件循环触发的原理之后, 再来看看sendDummyReport()函数实现了什么功能,下面是 sendDummyReport()的源码解析过程。

    static void sendDummyReport(void){
        uint8 pData[SENSOR_REPORT_LENGTH];
        static uint8 reportNr=0;
        uint8 txOptions;
    
        //上报过程中LED灯闪烁一次
        HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );
        HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );
    
        // dummy report data
        pData[SENSOR_TEMP_OFFSET] =   0xFF;       //温度
        pData[SENSOR_VOLTAGE_OFFSET] = 0xFF;   //电压
    
        pData[SENSOR_PARENT_OFFSET] = HI_UINT16(parentShortAddr);     //父节点的短地址的高位
        pData[SENSOR_PARENT_OFFSET+ 1] = LO_UINT16(parentShortAddr);	//父节点的短地址的低位
    
        // Set ACK request on each ACK_INTERVAL report
        // If a report failed, set ACK request on next report
        if ( ++reportNr<ACK_REQ_INTERVAL && reportFailureNr==0 ) {
        	txOptions = AF_TX_OPTIONS_NONE;
        }else {
            txOptions = AF_MSG_ACK_REQUEST;
            reportNr = 0;
        }
    
        // Destination address 0xFFFE: Destination address is sent to previously
        // established binding for the commandId.
        //将数据包发送给协调器(协调器的地址为 0xFFFE)
        zb_SendDataRequest(0xFFFE, DUMMY_REPORT_CMD_ID, SENSOR_REPORT_LENGTH, pData, 0, txOptions, 0);
    }
    

    协调器

    协调器的任务就是收到终端节点、路由节点发送的数据报信息后通过串口发送给 PC 机。通过 5.2 节的工程解析实验可得知,zigbee 节点接收到数据之后, 最终调用了 zb_ReceiveDataIndication 函数,该函数的内容如下:

    void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData ){
        //处理数据格式
        gtwData.parent=BUILD_UINT16(pData[SENSOR_PARENT_OFFSET+1], Data[SENSOR_PARENT_OFFSET]);
        gtwData.source=source;
        gtwData.temp=*pData;
        gtwData.voltage=*(pData+1);
    
        // Flash LED 1 once to indicate data reception
        //接收到数据之后LED灯闪烁 1 次
        HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );
        HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );
    
        // Send gateway report
        sendGtwReport(&gtwData);	//发送网关数据
    }
    

    由于 ZStack 协议栈的运行涉及到很多任务,而且也比较复杂,所以在本节实验中,将终端节点、路由节点和协调器的程序流程图进行了简化,简化后的程序流程图如图所示。

    无法显示图片时显示的文字


    实验流程图

    6.6 实验步骤

    由于出厂源码 zigbee 网络 PAN ID 均设置为 0x2100,为了避免实验环境下多个实验平台之间 网络互相串扰,每个实验平台需要修改 PAD ID,修改工程内文件: Tools -> f8wConfig-top.cfg, 将 PAN ID 修改为个人学号的后四位(范围 0x0001~0x3FFF), 具体参考《产品手册》8.2 章节部分。

    1. 确认已安装 ZStack 的安装包。如果没有安装, 打开光盘提供的安装包, 路径为“03-系统代 码\ZStack\ZStack-CC2530-2.4.0- 1.4.0.exe”,双击之后直接安装,安装完后默认生成 C:\Texas Instruments\ZStack-CC2530-2.4.0- 1.4.0 文件夹。
    2. 准备 5 个 CC2530 射频节点板 (一个作为协调器节点, 两个作为路由节点,两个作为终端节 点),确定按照第一章 1.2 节设置节点板跳线为模式一,分别接上出厂电源。
    3. 打开例 程: 将 光 盘 中 的 例 程 “ 05- 实 验 例 程\ 第 5 章\5.5-NetworkTopology-Star\ NetworkTopology-Star ” 整个文 件 夹 拷 贝 到 C:\Texas Instruments\ZStack-CC2530-2.4.0- 1.4.0\Projects\zstack\Samples 文件夹下。双击 NetworkTopology-Star\CC2530DB\NetworkTopology-Star.eww”文件。
    4. 分别编译协调器、路由器、终端设备三个工程, 把 SmartRF04 仿真器连接到 CC2530 无线节点, 使用 Flash Programmer 工具把上述程序分别下载到对应的 CC2530 无线节点板中。
    5. 用 USB mini 线和调试转接板将协调器节点连接到 PC 上。
    6. 先拨动无线协调器的电源开关为 ON 状态,此时 D6 LED 灯开始闪烁,当正确建立好网络后,D6 LED 会常亮。
    7. 当无线协调器建立好网络后,拨动 4 个无线节点的电源开关为 ON 状态,此时每个无线节点的 D6 LED 灯开始闪烁,直到加入到协调器建立的zigbee 网络中后, D6 LED 灯开始常亮。
    8. 当有数据包进行收发时,无线协调器和无线节点的 D7 LED 灯会闪烁。
    9. 打开 ZigBee Sensor Monitor (DISK-wsnExt\04-常用工具\CC2530) 软件,在 ZigBee Sensor Monitor 软件上观察组网情况

    6.7 实验结果

    ZigBee Sensor Monitor 上显示的网络拓扑如下图所示:

    无法显示图片时显示的文字


    星状网络拓扑实验图

    无法显示图片时显示的文字


    星状网络拓扑结构

    7 实验名称——网络拓扑-树状网

    网络拓扑-树状网

    7.1 实验目的

  • 理解 zigbee 协议及相关知识
  • 在 zstack 协议栈下实现树状网络拓扑的控制
  • 7.2 预备知识

  • 掌握在 IAR 集成开发环境中编写和调试程序的基本过程
  • 了解 zstack 协议栈架构。
  • 7.3 实验环境

  • 硬件: ZXBee CC2530 节点板, USB 接口的 SmartRF04 仿真器,PC 机 Pentium100以上
  • 软件: PC 机操作系统 WinXP ,IAR 集成开发环境, ZigBee Sensor Monitor
  • 7.4 实验原理

    ZigBee 有三种网络拓扑, 即星形、树形和网状网络,这三种网络拓扑在 zstack 协议栈下均可实现。星形网络中,所有节点只能与协调器进行通信,而他们相互之间的通信是禁止的;树形网络中,终端节点只能与它的父节点通信,路由节点可与它的父节点和子节点通信;网状网络中,全功能节点之间是可以相互通信的。

    在 zstack 中,通过设置宏定义 STACK_PROFILE_ID 的值(在 nwk_globals.h 中定义) 可以选择不同控制模式(总共有三种控制模式, 分别为 HOME_CONTROLS 、GENERIC_STAR 和 NETWORK_SPECIFIC,默认模式为 HOME_CONTROLS),再选择不同的网络拓扑(NWK_MODE),也可以只修改 HOME_CONTROLS 的网络模式 (NWK_MODE),来选择不同的网络拓扑,由于网络的组建是由协调器来控制的,因此只需修改协调器的程序即可。此外,可以设定数组 CskipRtrs 和 CskipChldrn 的值(在 nwk_globals.c 中定义)进一步控制网络的形式, CskipChldrn 数组的值代表每一级可以加入的子节点的最大数目,CskipRtrs 数组的值代表每一级可以加入的路由节点的最大数目 , 如在 树状网络 中,定义 CskipRtrs[MAX_NODE_DEPTH+1] = {1,1,1,1,1,0},CskipChldrn[MAX_NODE_DEPTH+1] = {2,2,2,2,2,0},代表每级最多允许 2 个子节点加入,其中最多 1 个路由节点,剩余的为终端节点。本实验已通过宏定义(在工程 options 中的 preprocessor 中定义)设定了数组的大小。

    7.5 实验内容

    配置网络拓扑为树状网络,启动协调器节点,协调器节点上电后进行组网操作,再启动路由节点和终端节点,路由节点和终端节点上电后进行入网操作,成功入网后周期的将父节点的短地址,自己的节点信息封装成数据包发送给 sink 节点,sink 节点接收到数据包后通过串口传给 PC,从 PC上的 ZigBee Sensor Monitor 程序查看组网情况。

    下图为本实验的数据流程图:

    无法显示图片时显示的文字


    数据流程图

    在本实验中设定路由节点、终端节点每隔 2 秒钟向协调器发送自己的网络信息包, 下面结合本实验的实验原理以及实验内容的设计,分别对终端节点、路由节点和协调器节点的源关键源程序进行解析。

    终端节点、路由节点

    根据本节内容的设计, 终端节点、路由节点加入 zigbee 网络后, 每隔一段时间上报自己的网络信息,因此终端节点和路由节点的任务事件都一样。通过 5.2 节的工程解析实验可得知,在程序源代码 MPEndPont.c 或 MPRouter.c 中 ZStack 协议栈成功启动后,设置了一个定时器事件, 当定时器事件触发后就会触发用户的 MY_REPORT_EVT 事件,触发 MY_REPORT_EVT 事件的函数入口为 MPRouter.c (或 MPEndPont.c) 中的 zb_HandleOsalEvent 函数,在该函数中编写了应用程序事件的处理过程,如下述代码所示。

    void zb_HandleOsalEvent( uint16 event ){
    	uint8 logicalType;
    	if(event & SYS_EVENT_MSG){            //系统事件信息
        }
    	if( event & ZB_ENTRY_EVENT ){       //zigbee入网事件
            // blind LED 2 to indicate starting/joining a network
            //入网时LED灯闪烁
            HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
            HalLedBlink ( HAL_LED_2, 0, 50, 500 );
    
            logicalType = ZG_DEVICETYPE_ROUTER;        //设备类型为路由节点
            zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);       //将信息写入NV
    
            // Start the device
            zb_StartRequest();
    	}
        
        if ( event & MY_START_EVT ) {	//启动ZStack协议栈事件
            zb_StartRequest();
    	}
        if ( event & MY_REPORT_EVT ) {	// MY_REPORT_EVT事件触发处理
    		if (appState == APP_BINDED){
                //调用函数
                sendDummyReport();
                //设置定时器,触发 MY_REPORT_EVT事件
                osal_start_timerEx( sapi_TaskID, MY_REPORT_EVT, myReportPeriod );
    		}
    	}
        if ( event & MY_FIND_COLLECTOR_EVT ){     //查找网关事件
    		// Find and bind to a gateway device (if this node is not gateway)
    		zb_BindDevice( TRUE, DUMMY_REPORT_CMD_ID, (uint8 *)NULL );
    	}
    }
    

    通过上述源码可以看到,当处理 MY_REPORT_EVT 事件时, 调用了sendDummyReport()方法(MPEndPont.c 中的 MY_REPORT_EVT 事件调用的是 sendReport()方法),然后又设置了一个定时器事件来触发 MY_REPORT_EVT 事件 ,这样做的目的就是为了每隔一段时间循环触发 MY_REPORT_EVT 事件。了解了 MY_REPORT_EVT 事件循环触发的原理之后,再来看看sendDummyReport()函数实现了什么功能,下面是 sendDummyReport()的源码解析过程。

    static void sendDummyReport(void){
        uint8 pData[SENSOR_REPORT_LENGTH];
        static uint8 reportNr=0;
        uint8 txOptions;
        //上报过程中LED灯闪烁一次
        HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );
        HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );
    
        // dummy report data
        pData[SENSOR_TEMP_OFFSET] =   0xFF;       //温度
        pData[SENSOR_VOLTAGE_OFFSET] = 0xFF;   //电压
    
        pData[SENSOR_PARENT_OFFSET] =   HI_UINT16(parentShortAddr);       //父节点的短地址的最高位
        pData[SENSOR_PARENT_OFFSET+ 1] =   LO_UINT16(parentShortAddr); //父节点的短地址的最低位
    
        // Set ACK request on each ACK_INTERVAL report
        // If a report failed, set ACK request on next report
        if ( ++reportNr<ACK_REQ_INTERVAL && reportFailureNr==0 ){
    		txOptions = AF_TX_OPTIONS_NONE;
    	}else{          //发送失败
            txOptions = AF_MSG_ACK_REQUEST;
            reportNr = 0;
    	}
    
        // Destination address 0xFFFE: Destination address is sent to previously
        // established binding for the commandId.
        //将数据包发送给协调器(协调器的地址为0xFFFE)
        zb_SendDataRequest(0xFFFE, DUMMY_REPORT_CMD_ID, SENSOR_REPORT_LENGTH, pData, 0, txOptions, 0);
    }
    

    协调器

    协调器的任务就是收到终端节点、路由节点发送的数据报信息后通过串口发送给 PC 机。通过 5.2 节的工程解析实验可得知,zigbee 节点接收到数据之后, 最终调用了 zb_ReceiveDataIndication函数,该函数的内容如下:

    void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData   ){
        //处理数据格式
        gtwData.parent=BUILD_UINT16(pData[SENSOR_PARENT_OFFSET+1], Data[SENSOR_PARENT_OFFSET]);
        gtwData.source=source;
        gtwData.temp=*pData;
        gtwData.voltage=*(pData+1);
    
        // Flash LED 1 once to indicate data reception
        //接收到数据之后LED灯闪烁 1 次
        HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );
        HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );
    
        // Send gateway report
        //发送网关数据
        sendGtwReport(&gtwData);
    }
    

    本节实验中,终端节点、路由节点和协调器的程序流程图如下图所示:

    无法显示图片时显示的文字


    实验流程图

    7.6 实验步骤

    由于出厂源码 zigbee 网络 PAN ID 均设置为 0x2100,为了避免实验环境下多个实验平台之间网络互相串扰,每个实验平台需要修改 PAD ID,修改工程内文件:Tools -> f8wConfig-top.cfg,将 PAN ID 修改为个人学号的后四位(范围 0x0001~0x3FFF),具体参考《产品手册》8.2 章节部分。

    1. 确认已安装 ZStack 的安装包。如果没有安装,打开光盘提供的安装包,路径为“03-系统代码\ZStack\ZStack-CC2530-2.4.0-1.4.0.exe”,双击之后直接安装,安装完后默认生成 C:\Texas Instruments\ZStack-CC2530-2.4.0-1.4.0 文件夹。
    2. 准备 5 个 CC2530 射频节点板(一个作为协调器节点,两个作为路由节点,两个作为终端节点),确定按照第一章 1.2 节设置节点板跳线为模式一,分别接上出厂电源。
    3. 打 开 例 程 : 将光 盘 中 的例 程 “ 05- 实 验 例程 \ 第 5 章 \5.6-NetworkTopology-Tree\NetworkTopology-Tree ” 整 个 文 件 夹 拷 贝 到 C:\Texas Instruments\ZStack- CC2530-2.4.0-1.4.0\Projects\zstack\Samples 文件夹下。双击 NetworkTopology-Tree \CC2530DB\NetworkTopology-Tree.eww”文件。
    4. 分别编译协调器、路由器、终端设备三个工程,把 SmartRF04 仿真器连接到 CC2530 无线节点,使用 Flash Programmer 工具把上述程序分别下载到对应的 CC2530 无线节点板中。
    5. 用 USB mini 线和调试转接板将协调器节点连接到 PC 上。
    6. 先拨动无线协调器的电源开关为 ON 状态,此时 D6 LED 灯开始闪烁,当正确建立好网络后,D6 LED 会常亮。
    7. 当无线协调器建立好网络后,拨动 4 个无线节点的电源开关为 ON 状态,此时每个无线节点的 D6 LED 灯开始闪烁,直到加入到协调器建立的 zigbee 网络中后,D6 LED 灯开始常亮。
    8. 当有数据包进行收发时,无线协调器和无线节点的 D7 LED 灯会闪烁。
    9. 打开 ZigBee Sensor Monitor 软件,在 ZigBee Sensor Monitor 软件上观察组网情况。

    7.7 实验结果

    ZigBee Sensor Monitor 上显示的网络拓扑如下图 5.7.3 所示:

    无法显示图片时显示的文字


    树状网络拓扑实验图

    无法显示图片时显示的文字


    树状网络拓扑结构

    tack 的安装包。如果没有安装,打开光盘提供的安装包,路径为“03-系统代码\ZStack\ZStack-CC2530-2.4.0-1.4.0.exe”,双击之后直接安装,安装完后默认生成 C:\Texas Instruments\ZStack-CC2530-2.4.0-1.4.0 文件夹。
    2. 准备 5 个 CC2530 射频节点板(一个作为协调器节点,两个作为路由节点,两个作为终端节点),确定按照第一章 1.2 节设置节点板跳线为模式一,分别接上出厂电源。
    3. 打 开 例 程 : 将光 盘 中 的例 程 “ 05- 实 验 例程 \ 第 5 章 \5.6-NetworkTopology-Tree\NetworkTopology-Tree ” 整 个 文 件 夹 拷 贝 到 C:\Texas Instruments\ZStack- CC2530-2.4.0-1.4.0\Projects\zstack\Samples 文件夹下。双击 NetworkTopology-Tree \CC2530DB\NetworkTopology-Tree.eww”文件。
    4. 分别编译协调器、路由器、终端设备三个工程,把 SmartRF04 仿真器连接到 CC2530 无线节点,使用 Flash Programmer 工具把上述程序分别下载到对应的 CC2530 无线节点板中。
    5. 用 USB mini 线和调试转接板将协调器节点连接到 PC 上。
    6. 先拨动无线协调器的电源开关为 ON 状态,此时 D6 LED 灯开始闪烁,当正确建立好网络后,D6 LED 会常亮。
    7. 当无线协调器建立好网络后,拨动 4 个无线节点的电源开关为 ON 状态,此时每个无线节点的 D6 LED 灯开始闪烁,直到加入到协调器建立的 zigbee 网络中后,D6 LED 灯开始常亮。
    8. 当有数据包进行收发时,无线协调器和无线节点的 D7 LED 灯会闪烁。
    9. 打开 ZigBee Sensor Monitor 软件,在 ZigBee Sensor Monitor 软件上观察组网情况。

    7.7 实验结果

    ZigBee Sensor Monitor 上显示的网络拓扑如下图 5.7.3 所示:

    无法显示图片时显示的文字


    树状网络拓扑实验图

    无法显示图片时显示的文字


    树状网络拓扑结构

    物联沃分享整理
    物联沃-IOTWORD物联网 » 探索物联网实验的奥秘

    发表评论