迪加Zigbee学习历程九 ZigBee信号传输质量检测
本帖最后由 迪加 于 2012-9-22 14:37 编辑前言:PER(误包率检测)实验是BasicRF的第二个实验,和无线点灯一样是没有使用协议栈的点对点通讯。通过无线点灯大家应该对zigbee的发射和接收有个感性的认识,本次实验讲解不会像无线点灯一样讲得那么详细,因为接收发射的过程基本上是一样的,但也希望初学者能自己认真学习一下这个实验,相信会对无线传输会有一个更清晰的认识。
实现平台:两块WeBee base_board及两块WeBee无线模块
图1 网蜂ZigBee开发平台
实验现象:两块WeBee模块通信,一个模块作发射,另外一个模块接收,接收模块通过串口不在PC机上显示当前的误包率、RSSI值和接收到数据包的个数。
实验详解:例程的源代码CC2530 BasicRF.rar是TI官网上下载的,打开\CC2530 BasicRF\ide\srf05_cc2530\iar里面的per_test.eww工程,由于我们的硬件平台不同于TI的开发板,所以我们需要在per_test中加入串口发送函数,才能在串口调试助手上看到我们的实验现象。
打开工程,在application文件夹点per_test.c我们的主要功能函数都在这里
图2
在这个.c文件中添加串口发送函数
INCLUDES中添加:#include "string.h"
图3
然后继续添加串口初始化和发送函数:
图4
很简单地就把串口搞定了,因为只有接收模块才会用到串口,所以串口的初始化只需要放在appReceiver ( )函数中
下面分析整个工程的发送和接收过程
首先还是要先找到main.c
/******************************************************************************
* @fn main
*
* @brief This is the main entry of the "PERtest" application.
*
* @param basicRfConfig - file scope variable.Basic RF configuration data
* appState - file scope variable.Holds application state
* appStarted - file scope variable.Used to control start and stop of
* transmitter application.
*
* @return none
*/
1. voidmain (void)2. {3. uint8appMode;4. appState= IDLE;5. appStarted= TRUE;6. // Config basicRF 配置Basic RF7. basicRfConfig.panId= PAN_ID;8. basicRfConfig.ackRequest= FALSE;
9. // Initialise board peripherals 初始化外围硬件10. halBoardInit();
11. // Initalise hal_rf 初始化hal_rf12. if(halRfInit()==FAILED){13. HAL_ASSERT(FALSE);14. }
15. // Indicate that device is powered16. halLedSet(1);17. // Print Logo and splash screen on LCD18. utilPrintLogo("PERTester");
19. // Wait for user to press S1 to enter menu20. halMcuWaitMs(350);21. // Set channel22. //设置信道,规范要求信道只能为为11——25。这里选择信道11 23. basicRfConfig.channel= 0x0B;
//设置模块的模式,一个作为发射,另一个为接收,看是否define MODE_SEND
24. #ifdefMODE_SEND25. appMode= MODE_TX;26. #else27. appMode= MODE_RX;28. #endif29. // Transmitter application30. if(appMode== MODE_TX) {// No return from here 如果define MODE_SEND则进入appTransmitter();发射模式
31. appTransmitter();32. }33. // Receiver application34. else if(appMode== MODE_RX) {35. // No return from here如果没有define MODE_SEND则进入appReceiver ();接收模式36. appReceiver();37. }
38. // Role is undefined. This code should not be reached39. HAL_ASSERT(FALSE);40. }
大家看注释也应该知道main.c做了哪些事情:
1、 一大堆的初始化(都是必须的)2、 设置信道,发射和接收模块的信道必须一致3、 选择为发射或者接收模式
发射函数define MODE_SEND则进入appTransmitter();
/*********************************************************
* @fn appTransmitter
*
* @brief Applicationcode for the transmitter mode. Puts MCU in endless
* loop
*
* @param basicRfConfig - file scope variable. Basic RF configuration data
* txPacket -file scope variable of type perTestPacket_t
* appState -file scope variable. Holds application state
* appStarted- file scope variable. Controls start and stop of
* transmission
*
* @return none
*/
1. static void appTransmitter()2. {3. uint32 burstSize=0;4. uint32 pktsSent=0;5. uint8 appTxPower;6. uint8 n;7. // Initialize BasicRF /* 初始化Basic RF */8. basicRfConfig.myAddr = TX_ADDR;9. if(basicRfInit(&basicRfConfig)==FAILED) 10. {
11. HAL_ASSERT(FALSE);
12. }
13. // Set TX outputpower /* 设置输出功率 */14. halRfSetTxPower(2); //HAL_RF_TXPOWER_4_DBM
15. // Set burstsize /* 设置进行一次测试所发送的数据包数量 */16. burstSize = 1000;
17. // Basic RF puts onreceiver before transmission of packet, and turns off after packet is sent18. basicRfReceiveOff();
19. /*************************************************************/
20. Config timer andIO 配置定时器和IO21. *************************************************************/22. appConfigTimer(0xC8);
23. // Initalise packetpayload /* 初始化数据包载荷 */24. txPacket.seqNumber = 0;
25. for(n = 0; n <sizeof(txPacket.padding); n++) 26. {
27. txPacket.padding = n;
28. }
//************************进入循环*******************//
29. while (TRUE)
30. {
31. while(appStarted)
32. {
33. if (pktsSent < burstSize)
34. {
35. // Make suresequence number has network byte order36. UINT32_HTON(txPacket.seqNumber);// 改变发送序号的字节顺序
37. basicRfSendPacket(RX_ADDR,(uint8*)&txPacket, PACKET_SIZE);
38. // Change byte orderback to host order before increment /* 在增加序号前将字节顺序改回为主机顺序 */39. UINT32_NTOH(txPacket.seqNumber);
40. txPacket.seqNumber++; //数据包序列号自加1
41. pktsSent++;
42. appState = IDLE;
43. halLedToggle(1); //改变LED1的亮灭状态
44. halMcuWaitMs(500);
45. }
46. else
47. appStarted = !appStarted;
48. // Reset statisticsand sequence number/* 复位统计和序号 */49. pktsSent = 0;
50. }
51. }
52. }
总结appTransmitter函数完成的任务:
1、初始化BasicRF
2、设置发射功率
3、设定测试的数据包量
4、配置定时器和IO
5、初始化数据包载荷
6、进行循环函数,不断地发送数据包,每发送完一次,下一个数据包的序列号自加1再发送;
接收函数没有define MODE_SEND则进入appReceiver ()
接收函数比较长,担心大家看到会反感,而且查看不方便,此处只把有必要说明的地方才贴出来,具体的全部代码内容肯定是打开工程看最好啦。。。
/***********************************************************************************
*@fn appReceiver*
*@brief Application code for thereceiver mode. Puts MCU in endless loop*
*@param basicRfConfig - file scopevariable. Basic RF configuration data* rxPacket - file scope variable oftype perTestPacket_t*
* @return none
*/
1. staticvoid appReceiver()2. {3. initUART(); // 初始化串口 4. basicRfConfig.myAddr= RX_ADDR;5. if(basicRfInit(&basicRfConfig)==FAILED)Initialize BasicRF //初始化Basic RF6. {7. HAL_ASSERT(FALSE);8. }9. basicRfReceiveOn();10. while(TRUE) 11. {12. while(!basicRfPacketIsReady()); // 等待新的数据包13. if(basicRfReceive((uint8*)&rxPacket,MAX_PAYLOAD_LENGTH, &rssi)>0) {14. halLedSet(3);//*************P1_415. UINT32_NTOH(rxPacket.seqNumber);// 改变接收序号的字节顺序16. segNumber= rxPacket.seqNumber 17. //若统计被复位,设置期望收到的数据包序号为已经收到的数据包序号 18. if(resetStats)19. {20. rxStats.expectedSeqNum= segNumber;21. resetStats=FALSE;22. } 23. // Subtract old RSSI value from sum24. rxStats.rssiSum-= perRssiBuf;// 从sum中减去旧的RSSI值25. // Store new RSSI value in ring buffer, will add it to sum later26. perRssiBuf=rssi;// 存储新的RSSI值到环形缓冲区,之后它将被加入sum27. rxStats.rssiSum+= perRssiBuf;// 增加新的RSSI值到sum28. if(++perRssiBufCounter== RSSI_AVG_WINDOW_SIZE) {29. perRssiBufCounter= 0; // Wrap ring buffer counter 30. }31. // Check if received packet is the expected packet 检查接收到的数据包是否是所期望收到的数据包32. if(rxStats.expectedSeqNum== segNumber)//是所期望收到的数据包 33. {34. rxStats.expectedSeqNum++;35. }36. // If there is a jump in the sequence numbering this means somepackets inbetween has been lost.37. elseif(rxStats.expectedSeqNum < segNumber) //大于期望收到的数据包的序号38. { // 认为丢包39. rxStats.lostPkts+= segNumber - rxStats.expectedSeqNum;40. rxStats.expectedSeqNum= segNumber + 1;41. }42. else // 小于期望收到的数据包的序号43. { 44. rxStats.expectedSeqNum= segNumber + 1;45. rxStats.rcvdPkts= 0;46. rxStats.lostPkts= 0;47. }48. rxStats.rcvdPkts++;49. /*******************以下为串口打印部分的函数*********************/50. temp_receive=(int32)rxStats.rcvdPkts;51. if(temp_receive>1000)52. {53. if(halButtonPushed()==HAL_BUTTON_1){54. resetStats= TRUE;55. rxStats.rcvdPkts= 1;56. rxStats.lostPkts= 0;57. }58. }59. Myreceive=temp_receive/100+'0'; //打印接收到数据包的个数60. Myreceive=temp_receive%100/10+'0';61. Myreceive=temp_receive%10+'0';62. Myreceive='\0';63. UartTX_Send_String("RECE:",strlen("RECE:"));64. UartTX_Send_String(Myreceive,4);65. UartTX_Send_String(" ",strlen(" ")); 66. temp_per=(int32)((rxStats.lostPkts*1000)/(rxStats.lostPkts+rxStats.rcvdPkts));67. Myper=temp_per/100+'0'; //打印当前计算出来的误包率68. Myper=temp_per%100/10+'0';69. Myper='.';70. Myper=temp_per%10+'0';71. Myper='%';72. UartTX_Send_String("PER:",strlen("PER:"));73. UartTX_Send_String(Myper,5);74. UartTX_Send_String(" ",strlen(" "));75. temp_rssi=(0-(int32)rxStats.rssiSum/32);//打印上32个数据包的RSSI值的平均值76. Myrssi=temp_rssi/10+'0';77. Myrssi=temp_rssi%10+'0';78. UartTX_Send_String("RSSI:-",strlen("RSSI:-"));79. UartTX_Send_String(Myrssi,2); 80. UartTX_Send_String("\n",strlen("\n"));81. halLedClear(3);82. halMcuWaitMs(300);83. } 84. }85. }那么长,有点头晕是吧。不用一句句地看,撒几眼你就知道这个函数干了什么事了…但还是建议直接打开工程学习。
接收函数的作用:
1、 串口在此初始化2、 初始化BasicRF3、 不断地接收数据包,并检查数据包序号是否为期望值,作出相应处理4、 串口打印出,接收包的个数\误包率及上32个数据包的RSSI值的平均值
有几个比较重要的数据作个简要的说明一下:
为了获取传输的性能参数,接收器中包含了如下几个数据(包含在rxStats 变量中,其类型为perRxStats_t)rxStats.expectedSeqNum 预计下一个数据包的序号,其值等于“成功接收的数据包”+“丢失的数据包”+1 rxStats.rssiSum 上32 个数据包的 RSSI 值的和
rxStats.rcvdPkts 每次PER 测试中,成功接收到的数据包的个数
rxStats.lostPkts 丢失数据包的个数
这些数据具体是怎么得来,我们没有必要具体去分析,直接读取我们感兴趣的数据就可以了。
误包率又是怎么计数的呢?TI公司的使用文档有说明的
如果大家想了解具体的话就可以去\CC2530 BasicRF\docs 文件夹中找到CC2530_Software_Examples.pdf 文档4.2章节有详细介绍的
实验操作:1、下载发射模块,在per_test.c中,找到:/********************important select or shelt****************************/#defineMODE_SEND //屏蔽时:appReceiver //不屏蔽时:appTransmitter/******************************************************************/不要屏蔽#define MODE_SEND 编译下载到发射模块 2、下载接收模块,同样的找到/********************important select or shelt****************************///#define MODE_SEND //屏蔽时:appReceiver //不屏蔽时:appTransmitter/******************************************************************/要屏蔽#define MODE_SEND编译下载到接收模块 3、 接收模块USB连接PC机并给发射模块供电,打开串口调试助手,并设置好相应的COM口和波特率,先开接收模块,再开发送模块。然后就可以看到我们的实验现象了。如图5所示。 由于距离比较近,所以掉包不明显的,有兴趣的可以把发送节点拿到较远的地方,然后观察掉包率。或者先打开发送模块,再打开接收模块来测试掉包,会显示出掉包情况。
图5 实验现象(包数量-掉包率-RSS)
至此,信号传输质量检测结束。和历程八一样,这次也是没用到协议栈的内容。在下一次教程中,我们正式进入协议栈内容。
附网蜂开源程序:
(有莫友提及到,这些内容在网蜂《zigbee实战演练》已经提及了,为什么还要再花时间发帖出来。迪加在这里需要说明一下,我们在学习每个内容过程中总遇到问题,这也很可能是后来者将会遇到的问题,我们把问题记录在帖子里,那么以后的人就能看到或者搜索到相关内容,从而节省解决问题的时间。这对他们是有很大帮助的。群讨论能解决当前问题,而帖子的魅力却能解决以后的问题,感谢大家对网蜂的支持。) 请问 lz 目前zigbee点对点 传输的话, 距离 最远可以做到 多少?
zegbee 的 强项是不是在自动组网,而不是在 单点传输上 比 距离上?
zigbee的 速率可以做到 多大,是实时传 640*48030fps的 视频? rei1984 发表于 2012-9-22 10:40 static/image/common/back.gif
请问 lz 目前zigbee点对点 传输的话, 距离 最远可以做到 多少?
zegbee 的 强项是不是在自动组网,而 ...
要是zigbee也能传视频,让wifi情何以堪 Zigbee的优势在于自组网,但是不支持休眠唤醒,所以功耗一直降不下来,实际应用不知道怎么样了?
TI的协议栈代码看着好乱,以前在学校的时候看着那些变量定义啊,函数什么的感觉好晦涩,不知道现在是不是这样?
协议栈封装了网络层,开发主要是在应用层,我一直认为网络层才是重中之重,所有的应用都是基于网络的基础才实现的,始终感觉TI的Zigbee协议栈适合于学习不适合商用.
以上个人观点,有不对的地方请指教!
PS:TI的协议栈已经几年没有更新了, rei1984 发表于 2012-9-22 10:40 static/image/common/back.gif
请问 lz 目前zigbee点对点 传输的话, 距离 最远可以做到 多少?
zegbee 的 强项是不是在自动组网,而 ...
1.距离需要看你模块的性能。
2.basicRF能给你们对组网一个提前的感知认识。
3.理论250KB/S。不能传输视频和音频。优势是适合做无线传感网。 hongshuang 发表于 2012-9-22 13:01 static/image/common/back.gif
Zigbee的优势在于自组网,但是不支持休眠唤醒,所以功耗一直降不下来,实际应用不知道怎么样了?
TI的协议 ...
协议栈还是使用 2007 pro . 另外zigbee是支持定时唤醒和无线唤醒的。 {:victory:} 好贴支持下先 好贴支持下先{:smile:} 迪加 发表于 2012-9-22 14:28 static/image/common/back.gif
协议栈还是使用 2007 pro . 另外zigbee是支持定时唤醒和无线唤醒的。
定时唤醒可以由MCU去实现,但是休眠的时候路由应该会受到很大影响,请教一下Zigbee在这方面是怎么处理的?
无线唤醒我只知道TI的CC1101这类支持,下一步准备用它去组网,CC2520/2530也支持吗?能够做休眠的点我觉得只适合做END而不适合做Router,这样一样功耗还是降不下去! 楼主开源精神值得学习,马克备用 hongshuang 发表于 2012-9-26 22:46 static/image/common/back.gif
定时唤醒可以由MCU去实现,但是休眠的时候路由应该会受到很大影响,请教一下Zigbee在这方面是怎么处理的 ...
官方也是了。 协调器和路由器需要组网和中继,不推荐睡眠的。 楼主,我应用CC2530做了一款普通功率的ZIGBEE产品,实际通讯距离是130米左右,我想从硬件上修改一下,来使传输距离加大;
我想用巴伦器件接RF_P与RF_N端的形式(以前是用TI给的原理图做的),如下图所示:的方式改进天线部分的电路,不知道这样改进怎么样,楼主有这方面的经验吗? 很有道理,有必要把实践教程里面的各个章节拿出来发帖,这样大家更容易交流了,具有问题的针对性. iar是什么版本的啊? mark{:smile:}{:smile:} 谢谢分享,除了通过串口,可以用单片机显示出来吗?
页:
[1]