「ZigBee模块」组网实验-信号传输质量检测

信号传输质量检测

重点在代码分析部分...就是废话比较多...

一、实验平台

两个ZigBee模块

一个方口USB线

一个编译器

二、实验现象

两块ZigBee模块通信,一个模块作发射,另外一个模块作接收,接收模块通过串口在PC机上显示当前的误包率、RSSI值和接收到数据包的个数

三、准备工作

由于硬件平台不同,所以我们需要在per_test中加入串口发送函数

1. 打开工程—>application—>per_test.c

在per_test.c文件中添加串口发送函数

2. INCLUDES中添

 #include "string.h"

3. 在函数声明中添加

void uartInit(void);//**************************
void uartSend(int8 *Data,int len);//**********************

4. 添加串口初始化函数

 1 /****************************************************************
 2 串口初始化函数
 3 ****************************************************************/
 4 void initUART(void)
 5 {
 6     PERCFG = 0x00;              //位置1 P0口
 7     P0SEL = 0x0c;              //P0_2,P0_3用作串口(外部设备功能)
 8     P2DIR &= ~0XC0;          //P0优先作为UART0
 9
10     U0CSR |= 0x80;              //设置为UART方式
11     U0GCR |= 11;
12     U0BAUD |= 216;              //波特率设为115200
13     UTX0IF = 0;               //UART0 TX中断标志初始置位0
14 }

5. 添加串口发送函数

 1 /****************************************************************
 2 串口发送字符串函数
 3 ****************************************************************/
 4 void uartSend(int8 *Data,int len)
 5 {
 6   int j;
 7   for(j=0;j<len;j++)
 8   {
 9     U0DBUF = *Data++;
10     while(UTX0IF == 0);
11     UTX0IF = 0;
12   }
13 }

6. 因为只有接收模块使用到串口,把串口初始化放入appReceiver()即可

四、分析per_test.c的代码

看代码前还是想先解释一下,这里一个数据包就是一个结构体数据类型,里面包括6个字节的内容和1个字节的序号 我们是利用序号来判断有没有发生误包的。

第一步,先找到main函数

 1 void main (void)
 2 {
 3     //变量声明
 4     uint8 appMode;         //用来选择模式(发送或接收)
 5
 6     appState = IDLE;
 7
 8     //配置basic RF
 9     basicRfConfig.panId = PAN_ID;
10     basicRfConfig.ackRequest = FALSE;
11
12     //初始化外围设备
13     halBoardInit();
14
15     //初始化hal_rf
16     if(halRfInit()==FAILED) {
17       HAL_ASSERT(FALSE);
18     }
19
20     //点亮led1(P1.0)用以表示程序开始运行
21     halLedSet(1);
22
23     //信道设置 11—25都可以
24     basicRfConfig.channel = 0x0B;
25
26     //这里就是模式选择啦,选择完进入那个函数,然后main函数就不需要啦
27     //这个怎么选??
28     //看MODE_SEND,go to definition,找到定义的地方
29     //把那行代码注释掉就是接收部分,不注释就是发送
30     #ifdef MODE_SEND
31      appMode = MODE_TX;
32     #else
33      appMode = MODE_RX;
34     #endif
35     // Transmitter application
36     if(appMode == MODE_TX) {
37         // No return from here
38         appTransmitter();
39     }
40     // Receiver application
41     else if(appMode == MODE_RX) {
42         // No return from here
43         appReceiver();
44     }
45     // Role is undefined. This code should not be reached
46     HAL_ASSERT(FALSE);
47 }

看完main函数,再来看一下发送的函数吧~

总结一下就是一大堆初始化然后依次发送数据包

 1 static void appTransmitter()
 2 {
 3   //声明变量
 4   uint32 burstSize=0;     //设定进行一次测试所发送的数据包数量
 5   uint32 pktsSent=0;      //指示当前已经发了多少个数据包
 6   uint8 n;
 7
 8   //初始化Basic RF
 9   basicRfConfig.myAddr = TX_ADDR;
10   if(basicRfInit(&basicRfConfig)==FAILED)
11   {
12     HAL_ASSERT(FALSE);
13   }
14
15   //置输出功率
16   halRfSetTxPower(2);
17
18   //设置进行一次测试所发送的数据包数量
19   burstSize = 1000;
20
21   //关闭接收模块,省电
22   basicRfReceiveOff();
23
24   //配置定时器和IO
25   //暂时不知道有什么用...以后补上
26   appConfigTimer(0xC8);
27
28   //初始化数据包载荷
29   //txPacket是什么? 就是一个数据包~在per_test.h中!
30   //里面有两个变量,seqNumber和padding[6]
31   //就是说一个数据包里面有6个字节的内容和一个表示序号的seqNumber
32   //讲一下seqNumber 就是拿来当序号用,发送时按012345这样的顺序发送,所以理应012345这样接受
33   //如果这次收到3,下次收到5,那就表示丢包了
34   txPacket.seqNumber = 0;
35   for(n = 0; n < sizeof(txPacket.padding); n++)  //初始化下,数据包里面就是012345
36   {
37     txPacket.padding[n] = n;
38   }
39
40   //主循环
41   while (TRUE)
42   {
43     if (pktsSent < burstSize) //如果数据包还没有发送完,继续执行
44     {
45       // 改变发送序号的字节顺序
46       //我也不知道为什么要改变顺序再改回来,可能和数据发送的一些协议有关吧,以后知道再补上
47       UINT32_HTON(txPacket.seqNumber);
48
49       //发送数据函数(发给谁, 发的内容, 数据长度) 重点就是这行代码!
50       //注意下,发送的就是txPacket这一整个数据,包括实际内容和序号,这是一个完整的数据包
51       basicRfSendPacket(RX_ADDR, (uint8*)&txPacket, PACKET_SIZE);
52
53       //在增加序号前将字节顺序改回为主机顺序
54       UINT32_NTOH(txPacket.seqNumber);
55       txPacket.seqNumber++; //发的序号+1
56
57       pktsSent++;           //发送了一个数据包了 +1
58
59       halLedToggle(1);   //改变LED1的亮灭状态
60       halMcuWaitMs(500); //延时
61     }
62       //数据包清零
63      pktsSent = 0;
64
65   }
66 }

最后是接收的部分

总结一下,开始还是一大堆初始化,然后一直接收数据、判断是不是丢包了、处理数据、串口发送

  1 static void appReceiver()
  2 {
  3   uint32 segNumber=0;                              // 数据包序列号
  4   int16 perRssiBuf[RSSI_AVG_WINDOW_SIZE] = {0};    // 存储RSSI的环形缓冲区
  5   uint8 perRssiBufCounter = 0;                     // 计数器用于RSSI缓冲区统计
  6
  7   perRxStats_t rxStats = {0,0,0,0};
  8    int16 rssi;
  9   uint8 resetStats=FALSE;
 10
 11   int8 Myper[5];
 12   int8 Myrssi[2];
 13   int8 Myreceive[4];
 14   int32 temp_per;           //存放掉包率
 15   int32 temp_receive;       //存放接收的包的个数
 16   int32 temp_rssi;          //存放前32个rssi值的平均值
 17   uartInit();               // 初始化串口
 18
 19 #ifdef INCLUDE_PA
 20   uint8 gain;
 21
 22   // Select gain (for modules with CC2590/91 only)
 23   gain =appSelectGain();
 24   halRfSetGain(gain);
 25 #endif
 26
 27    // Initialize BasicRF     初始化Basic RF
 28   basicRfConfig.myAddr = RX_ADDR;
 29   if(basicRfInit(&basicRfConfig)==FAILED)
 30   {
 31     HAL_ASSERT(FALSE);
 32   }
 33   //打开接收模块
 34   basicRfReceiveOn();
 35
 36   /* 主循环 */
 37   uartSend("PER_test: ",strlen("PER_test: ")); //串口发送数据
 38     // Main loop
 39   while (TRUE)
 40   {
 41     while(!basicRfPacketIsReady());  // 等待新的数据包
 42     //查看之后发行这里的rxPacket和发送里面的txPacket是同一种数据类型
 43     //basicRfReceive(指向数据缓冲区的指针,缓冲区最大数据长度,这个包的rssi值)
 44     //返回缓冲区实际数据长度
 45     if(basicRfReceive((uint8*)&rxPacket, MAX_PAYLOAD_LENGTH, &rssi)>0) {
 46          halLedSet(2);//*************P1_1 LED2点亮
 47
 48       UINT32_NTOH(rxPacket.seqNumber);  // 改变接收序号的字节顺序
 49       segNumber = rxPacket.seqNumber;   //读取包的序号
 50
 51       // If statistics is reset set expected sequence number to
 52       // received sequence number
 53       //若统计被复位,设置期望收到的数据包序号为已经收到的数据包序号
 54       //怎么样被认为统计复位?在后面~
 55       if(resetStats)
 56       {
 57         rxStats.expectedSeqNum = segNumber;
 58
 59         resetStats=FALSE;
 60       }
 61
 62       //下面这几行代码是用来计算上32个包的RSSI值的
 63       //先预设一个32个长度的数组,用来存放RSSI值,一个指针,指示最旧的一个RSSI值
 64       //每次获取新的包后,把最旧的RSSI值从总和处减去,再把新的RSSI值放入,并把它的值加入总和
 65       // Subtract old RSSI value from sum
 66       rxStats.rssiSum -= perRssiBuf[perRssiBufCounter];  // 从sum中减去旧的RSSI值
 67       // Store new RSSI value in ring buffer, will add it to sum later
 68       perRssiBuf[perRssiBufCounter] =  rssi;  // 存储新的RSSI值到环形缓冲区,之后它将被加入sum
 69       rxStats.rssiSum += perRssiBuf[perRssiBufCounter];  // 增加新的RSSI值到sum
 70       //如果指针超出数组最大值,复位指针
 71       if(++perRssiBufCounter == RSSI_AVG_WINDOW_SIZE) {
 72         perRssiBufCounter = 0;
 73       }
 74
 75
 76       //检查接收到的数据包是否是所期望收到的数据包
 77       // 是所期望收到的数据包
 78       if(rxStats.expectedSeqNum == segNumber)
 79       {
 80         rxStats.expectedSeqNum++;
 81       }
 82
 83       // 不是所期望收到的数据包(大于期望收到的数据包的序号)
 84       // 认为丢包
 85       else if(rxStats.expectedSeqNum < segNumber)
 86       {
 87         rxStats.lostPkts += segNumber - rxStats.expectedSeqNum;
 88         rxStats.expectedSeqNum = segNumber + 1;
 89       }
 90
 91       // (小于期望收到的数据包的序号)
 92       //认为是一个新的测试开始,复位统计变量
 93       else
 94       {
 95         rxStats.expectedSeqNum = segNumber + 1;
 96         rxStats.rcvdPkts = 0;
 97         rxStats.lostPkts = 0;
 98       }
 99       rxStats.rcvdPkts++;
100
101       //以下代码都是用于串口输出计算值的
102       temp_receive=(int32)rxStats.rcvdPkts;
103        if(temp_receive>1000)
104       {
105        if(halButtonPushed()==HAL_BUTTON_1){
106        resetStats = TRUE;
107        rxStats.rcvdPkts = 1;
108        rxStats.lostPkts = 0;
109         }
110       }
111
112       Myreceive[0]=temp_receive/100+‘0‘;
113       Myreceive[1]=temp_receive%100/10+‘0‘;
114       Myreceive[2]=temp_receive%10+‘0‘;
115       Myreceive[3]=‘\0‘;
116       uartSend("RECE:",strlen("RECE:"));
117       uartSend(Myreceive,4);
118       uartSend("    ",strlen("    "));
119
120       temp_per = (int32)((rxStats.lostPkts*1000)/(rxStats.lostPkts+rxStats.rcvdPkts));
121       Myper[0]=temp_per/100+‘0‘;
122       Myper[1]=temp_per%100/10+‘0‘;
123       Myper[2]=‘.‘;
124       Myper[3]=temp_per%10+‘0‘;
125       Myper[4]=‘%‘;
126       uartSend("PER:",strlen("PER:"));
127       uartSend(Myper,5);
128       uartSend("    ",strlen("    "));
129
130       temp_rssi=(0-(int32)rxStats.rssiSum/32);
131       Myrssi[0]=temp_rssi/10+‘0‘;
132       Myrssi[1]=temp_rssi%10+‘0‘;
133       uartSend("RSSI:-",strlen("RSSI:-"));
134       uartSend(Myrssi,2);
135       uartSend("\n",strlen("\n"));
136
137       halLedClear(2);
138
139       halMcuWaitMs(300);
140     }
141   }
142 }
时间: 2024-11-07 17:48:52

「ZigBee模块」组网实验-信号传输质量检测的相关文章

「ZigBee模块」组网实验-无线点灯

ZigBee入门小实验——无线点灯 写在前面:无线点灯实验不涉及协议栈,只是对Basic RF的应用,但是其中关于数据收发的思想和协议栈类似,可以借鉴.这个代码和实验过程都是参考某教程的,然后有加上自己的理解......欢迎纠错(*^__^*) 一.设备 两个ZigBee模块 一个方口USB线(这个只是供电用,要看自己模块用什么接口,不一定是方口的,用电池也行) 一个编译器 二.几个名词解释 CCM -Counter with CBC-MAC(mode of operation) 就知道和加密有

「ZigBee模块」基础实验(5)串口通讯

一.补充基础知识 在CC2530 中,USART0 和USART1 是串行通信接口,它们能够分别运行于异步USART 模式或者同步SPI 模式.两个USART 的功能是一样的,并且各自有单独的IO 引脚.USART里面的A指的就是asynchronous(异步),S指的是synchronous(同步).这里我们使用异步通信方式. UART模式特征: ·一次传8或9个比特的数据 ·奇校验.偶校验或者无校验位 ·配置起始位和停止位点平 ·配置LSB或者MSB首先传送 ·独立收发中断 ·独立收发DMA

「ZigBee模块」基础实验(3)外部中断

1.实现功能 使用中断方式实现: 按键KEY1按下LED1依次亮灭 按键KEY2按下LED2依次亮灭 2.元件连接方式 P1_0连接LED1 P1_1连接LED2 P0_0连接KEY1 P0_1连接KEY2 3.中断相关寄存器 PXIEN P0IEN P1IEN P2IEN 地址 0xAB 0x8D 0xAC PX[7:0] 各个控制口中断使能 (0:中断禁止 1:中断使能) PICTL: D0~D3设置各个端口的中断触发方式(0:上升沿触发 1:下降沿触发) D7控制I/O引脚在输出模式下的驱

「ZigBee模块」基础实验(1)点亮LED

1.IO配置 CC2530 的 IO 口配置需要三个寄存器:PXSEL.PXDIR.PXINP . IO口寄存器 P0 P1 P2 地址 0x80 0x90 0xA0 PXSEL P0SEL P1SEL P2SEL 地址 0xF3 0xF4 0xF5 PX[7:0]功能设置寄存器,默认普通IO口 (0:普通 IO 口 1:第二功能) PXDIR P0DIR P1DIR P2DIR 地址 0xFD 0xFE 0xFF PX[7:0] 输入输出设置寄存器 (0:输入 1:输出) PXINP P0IN

「ZigBee模块」基础实验(2)按键

1.实现功能 按键KEY1按下LED1依次亮灭 按键KEY2按下LED2依次亮灭 2.元件连接方式 P1_0连接LED1 P1_1连接LED2 P0_0连接KEY1 P0_1连接KEY2 3.部分代码分析 按键需要消抖(因为按键选择之后的代码较少,直接写这里面啦) void keyScan() { if(KEY1 == 0) { delayms(10); if(KEY1 == 0) { while(!KEY1); LED1 = !LED1; } } if(KEY2 == 0) { delayms

「ZigBee模块」协议栈-Z-Stack协议栈基础和数据传输实验

花了好久写的...感觉还不错的呢...如果看,请细看...Mua~ Z-Stack协议栈基础和数据传输实验 一.实验目的 终端节点将数据无线发送到协调器,协调器通过串口将数据发送到PC端,并在屏幕上显示出来.串口优化把有线串口传输改为无线蓝牙传输. 二.实验平台 硬件:2个zigbee节点,1个编译器,1根方口转USB数据线,一个蓝牙模块 软件:实验基于SampleApp工程进行. 三.实验步骤 串口初始化代码 发送部分代码 接收部分代码 四.协议栈基础 做实验之前先了解一点关于协议栈的基础知识

「ZigBee模块」协议栈-串口透传,打造无线串口模块

前面写比较仔细,后面一个么因为和前面重复了,不多说了,还有个原因...我懒...O(∩_∩)O哈哈~ 串口透传,打造无线串口模块 一.实验目的 两台PC机各使用串口连接一个zigbee模块,连接正确后打开串口调试助手发送信息.利用zigbee将从串口接收到的数据无线传送给另一个zigbee模块,另一个zigbee模块通过串口将数据传给PC端并在屏幕上显示. 二.实验平台 硬件:两个zigbee模块,两台PC机(其实一台也许,连接不同串口即可),编译器,方口转USB数据线两根 软件:基于Z-sta

「ZigBee模块」网络通讯实验-点播、组播、广播

预告下,明天还有最后一个实验<zigbee协议栈管理>......太棒了~马上就如期完成任务啦!哈哈哈 点播.组播.广播 一.基础知识补充 Zigbee的通信方式主要有三种:点播.组播.广播. 点播就是点对点通信,也就是两个设备之间的通信,不允许第三个设备收到信息. 组播就是把网络中的节点分组,每一个组员发出的信息只有相同组号的组员才能收到. 广播,最广泛的就是1个设备上发出的信息所以设备都能接收到. 二.点播实验步骤 因为要将收到的数据通过串口显示在屏幕上,所以在程序开始之前先把串口初始化吧

「ZigBee模块」zigbee协议栈网络管理

Zigbee协议栈网络管理 一.补充基础知识 每个cc2530芯片出厂时候都有一个全球唯一的32位MAC地址,当设备连入网络的时候,每个设备都能获得由协调器分配的16位短地址,协调器默认地址0x0000,很多时候网络就是通过短地址进行管理. 二.实验现象 路由器.设备终端发送自己定义的设备号给协调器,协调器通过接收到的设备号判断设备类型,并且获取设备的短地址,通过串口打印出来. 三.实验步骤 串口初始化 图1 先在SampleApp.c添加串口通信的头文件.(如图1) #include “MT_