ZigBee开发(11)--组网实验PER

Posted tianxxl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZigBee开发(11)--组网实验PER相关的知识,希望对你有一定的参考价值。

PER(误包率检测)实验是 BasicRF 的第二个实验,和无线点灯一样是没有使用协议栈的点对点通讯。

通过无线点灯大家应该对 zigbee 的发射和接收有个感性的认识,本次实验讲解不会像无线点灯一样讲得那么详细,因为接收发射的过程基本上是一样的,

但也希望初学者能自己认真学习一下这个实验,相信会对无线传输会有一个更清晰的认识。

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

实验详解:

  例程的源代码 CC2530 BasicRF.rar TI 官网上下载的,打开CC2530BasicRFidesrf05_cc2530iar 里面的 per_test.eww 工程,

  由于我们的硬件平台不同于 TI 的开发板,所以我们需要在 per_test 中加入串口发送函数,才能在串口调试助手上看到我们的实验现象。

打开工程,在 application 文件夹点 per_test.c 我们的主要功能函数都在这里   ,在这个.c 文件中添加串口发送函数 INCLUDES 中添加: #include “string.h”

然后继续添加串口初始化和发送函数:

技术分享图片
/****************************************************************
串口初始化函数
****************************************************************/
void initUART(void)
{ 
    PERCFG = 0x00;              //位置1 P0口
    P0SEL = 0x0c;              //P0_2,P0_3用作串口(外部设备功能)
    P2DIR &= ~0XC0;                   //P0优先作为UART0

    U0CSR |= 0x80;              //设置为UART方式
    U0GCR |= 11;                       
    U0BAUD |= 216;              //波特率设为115200
    UTX0IF = 0;                       //UART0 TX中断标志初始置位0
}
/****************************************************************
串口发送字符串函数            
****************************************************************/
void UartTX_Send_String(int8 *Data,int len)
{
  int j;
  for(j=0;j<len;j++)
  {
    U0DBUF = *Data++;
    while(UTX0IF == 0);
    UTX0IF = 0;
  }
}
View Code

 

很简单地就把串口搞定了,因为只有接收模块才会用到串口,所以串口的初始化只需要放在 appReceiver ( )函数中
  下面分析整个工程的发送和接收过程
    首先还是要先找到 main.c

 1 /***********************************************************************************
 2 * @fn          main
 3 *
 4 * @brief       This is the main entry of the "PER test" application.
 5 *
 6 * @param       basicRfConfig - file scope variable. Basic RF configuration data
 7 *              appState - file scope variable. Holds application state
 8 *              appStarted - file scope variable. Used to control start and stop of
 9 *              transmitter application.
10 *
11 * @return      none
12 */
13 void main (void)
14 {
15     uint8 appMode;
16     
17     appState = IDLE;
18     appStarted = TRUE;//*****************************by boo
19     
20     // Config basicRF    配置 Basic RF 
21     basicRfConfig.panId = PAN_ID;
22     basicRfConfig.ackRequest = FALSE;
23 
24     // Initialise board peripherals     初始化外围硬件 
25     halBoardInit();
26 
27     // Initalise hal_rf初始化 hal_rf 
28     if(halRfInit()==FAILED) {
29       HAL_ASSERT(FALSE);
30     }
31     
32     // Indicate that device is powered
33     halLedSet(1);
34 
35     // Print Logo and splash screen on LCD
36     utilPrintLogo("PER Tester");
37 
38     // Wait for user to press S1 to enter menu
39 //    while (halButtonPushed()!=HAL_BUTTON_1);***********************
40     halMcuWaitMs(350);
41 //    halLcdClear();************************************
42 
43     // Set channel
    //设置信道,规范要求信道只能为为 11——25。这里选择信道 11
44 // basicRfConfig.channel = appSelectChannel(); 45 basicRfConfig.channel = 0x0B; 46 47 48 // Set mode 49 // appMode = appSelectMode();****************** 50 51 #ifdef MODE_SEND 52 appMode = MODE_TX; 53 #else 54 appMode = MODE_RX; 55 #endif 56 // Transmitter application 57 if(appMode == MODE_TX) { 58 // No return from here 59 appTransmitter(); 60 } 61 // Receiver application 62 else if(appMode == MODE_RX) { 63 // No return from here 64 appReceiver(); 65 } 66 // Role is undefined. This code should not be reached 67 HAL_ASSERT(FALSE); 68 }

大家看注释也应该知道 main.c 做了哪些事情:
  1、 一大堆的初始化(都是必须的)
  2、 设置信道,发射和接收模块的信道必须一致
  3、 选择为发射或者接收模式
发射函数 define MODE_SEND 则进入 appTransmitter();

/***********************************************************************************
* @fn          appTransmitter
*
* @brief       Application code 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
*/
static void appTransmitter()
{
  uint32 burstSize=0;
  uint32 pktsSent=0;
  uint8 appTxPower;
  uint8 n;

        // Initialize BasicRF               /* 初始化Basic RF */
  basicRfConfig.myAddr = TX_ADDR;
  if(basicRfInit(&basicRfConfig)==FAILED) 
  {
    HAL_ASSERT(FALSE);
  }

     // Set TX output power                      /* 设置输出功率 */
  //appTxPower = appSelectOutputPower();
  halRfSetTxPower(2);//HAL_RF_TXPOWER_4_DBM
//  halRfSetTxPower(appTxPower);

   // Set burst size                 /* 设置进行一次测试所发送的数据包数量 */
  //burstSize = appSelectBurstSize();
  burstSize = 1000;
  
  // Basic RF puts on receiver before transmission of packet, and turns off
  // after packet is sent
  basicRfReceiveOff();

      // Config timer and IO          /* 配置定时器和IO *************************/
  //n= appSelectRate();
  appConfigTimer(0xC8);
  //halJoystickInit();

     // Initalise packet payload            /* 初始化数据包载荷 */
  txPacket.seqNumber = 0;
  for(n = 0; n < sizeof(txPacket.padding); n++) 
  {
    txPacket.padding[n] = n;
  }
  
  //halLcdClear();
  //halLcdWriteCharString(0,HAL_LCD_LINE_1, "Mode:Transmitter");
  //halLcdWriteCharString(0,HAL_LCD_LINE_2, "CENTER to start/stop");

    // Main loop          /* 主循环 */
  while (TRUE) 
  {
    // Wait for user to start application
    //while(!halJoystickPushed());  // 等待用户启动应用
    //appStartStop();   

    while(appStarted)
      {
    //{
      //if( halJoystickPushed()) 
      //{
      //  appStartStop();
      //}

      if (pktsSent < burstSize) 
      {
        //if( appState == TRANSMIT_PACKET ) 
        //{
        // Make sure sequence number has network byte order
          UINT32_HTON(txPacket.seqNumber);  // 改变发送序号的字节顺序
          basicRfSendPacket(RX_ADDR, (uint8*)&txPacket, PACKET_SIZE);

        // Change byte order back to host order before increment     /* 在增加序号前将字节顺序改回为主机顺序 */
          UINT32_NTOH(txPacket.seqNumber);
          txPacket.seqNumber++;

          pktsSent++;
   /*      #ifdef SRF04EB
          utilLcdDisplayValue(HAL_LCD_LINE_2, "Sent: ", (int32)pktsSent, NULL);
          #else
          utilLcdDisplayValue(HAL_LCD_LINE_3, "Sent: ", (int32)pktsSent, NULL);
          #endif*/
          appState = IDLE;
          halLedToggle(1);   //改变LED1的亮灭状态
          halMcuWaitMs(5000);
        //}
      }
      else
        appStarted = !appStarted;
      
    //}

      // Reset statistics and sequence number/* 复位统计和序号 */
     pktsSent = 0;
    //txPacket.seqNumber = 0;
    //halLcdClear();
    //halLedClear(3);
    //halLcdWriteCharString(0,HAL_LCD_LINE_1, "Mode:Transmitter");
    //halLcdWriteCharString(0,HAL_LCD_LINE_2, "CENTER to start/stop");
    }
  }
}

总结 appTransmitter 函数完成的任务:
  1、初始化 Basic RF
  2、设置发射功率
  3、设定测试的数据包量
  4、配置定时器和 IO
  5、初始化数据包载荷
  6、进行循环函数,不断地发送数据包,每发送完一次,下一个数据包的序
列号自加 1 再发送

 

接收函数没有 define MODE_SEND 则进入 appReceiver ()  ///接收函数比较长,

/***********************************************************************************
* @fn          appReceiver
*
* @brief       Application code for the receiver mode. Puts MCU in endless loop
*
* @param       basicRfConfig - file scope variable. Basic RF configuration data
*              rxPacket - file scope variable of type perTestPacket_t
*
* @return      none
*/
static void appReceiver()
{
  uint32 segNumber=0;                              // 数据包序列号 
  int16 perRssiBuf[RSSI_AVG_WINDOW_SIZE] = {0};    // Ring buffer for RSSI 存储RSSI的环形缓冲区
  uint8 perRssiBufCounter = 0;                     // Counter to keep track of the 计数器用于RSSI缓冲区统计
     // oldest newest byte in RSSI
    // ring buffer
  perRxStats_t rxStats = {0,0,0,0};      
   int16 rssi;
  uint8 resetStats=FALSE;
  
  int8 Myper[5];        
  int8 Myrssi[2];
  int8 Myreceive[4];
  int32 temp_per;           //存放掉包率
  int32 temp_receive;       //存放接收的包的个数
  int32 temp_rssi;          //存放前32个rssi值的平均值
  initUART();                  // 初始化串口
  
#ifdef INCLUDE_PA
  uint8 gain;

  // Select gain (for modules with CC2590/91 only)
  gain =appSelectGain();
  halRfSetGain(gain);
#endif
    
   // Initialize BasicRF     初始化Basic RF 
  basicRfConfig.myAddr = RX_ADDR;
  if(basicRfInit(&basicRfConfig)==FAILED) 
  {
    HAL_ASSERT(FALSE);
  }
  basicRfReceiveOn();

  //halLcdClear();
    
  //halLcdWriteCharString(0,HAL_LCD_LINE_1, "Mode:Receiver");
  //halLcdWriteCharString(0,HAL_LCD_LINE_3, "Ready");
  /* 主循环 */
  UartTX_Send_String("PER_test: ",strlen("PER_test: "));
    // Main loop
  while (TRUE) 
  {
    while(!basicRfPacketIsReady());  // 等待新的数据包
    if(basicRfReceive((uint8*)&rxPacket, MAX_PAYLOAD_LENGTH, &rssi)>0) {
         halLedToggle(1);//*************P1_0
            
        // Change byte order from network to host order
      UINT32_NTOH(rxPacket.seqNumber);  // 改变接收序号的字节顺序
      segNumber = rxPacket.seqNumber;
            
     // If statistics is reset set expected sequence number to
     // received sequence number 若统计被复位,设置期望收到的数据包序号为已经收到的数据包序号     
      if(resetStats)
      {
        rxStats.expectedSeqNum = segNumber;
        
        resetStats=FALSE;
      }      
      // Subtract old RSSI value from sum
      rxStats.rssiSum -= perRssiBuf[perRssiBufCounter];  // 从sum中减去旧的RSSI值
      // Store new RSSI value in ring buffer, will add it to sum later
      perRssiBuf[perRssiBufCounter] =  rssi;  // 存储新的RSSI值到环形缓冲区,之后它将被加入sum

      rxStats.rssiSum += perRssiBuf[perRssiBufCounter];  // 增加新的RSSI值到sum
      if(++perRssiBufCounter == RSSI_AVG_WINDOW_SIZE) {
        perRssiBufCounter = 0;      // Wrap ring buffer counter 
      }

      
     // Check if received packet is the expected packet   检查接收到的数据包是否是所期望收到的数据包
      if(rxStats.expectedSeqNum == segNumber)  // 是所期望收到的数据包 
      {
        rxStats.expectedSeqNum++;  
      }
      
      // If there is a jump in the sequence numbering this means some packets in
       // between has been lost.
      else if(rxStats.expectedSeqNum < segNumber)  // 不是所期望收到的数据包(大于期望收到的数据包的序号)
      {                                            // 认为丢包
        rxStats.lostPkts += segNumber - rxStats.expectedSeqNum;
        rxStats.expectedSeqNum = segNumber + 1;
      }
      
       // If the sequence number is lower than the previous one, we will assume a
       // new data burst has started and we will reset our statistics variables.
      else  // (小于期望收到的数据包的序号)
      {      
        // Update our expectations assuming this is a new burst*****认为是一个新的测试开始,复位统计变量
        rxStats.expectedSeqNum = segNumber + 1;
        rxStats.rcvdPkts = 0;
        rxStats.lostPkts = 0;
      }
      rxStats.rcvdPkts++;
      
           // reset statistics if button 1 is pressed
            temp_receive=(int32)rxStats.rcvdPkts;
             if(temp_receive>1000)
            {
             if(halButtonPushed()==HAL_BUTTON_1){
             resetStats = TRUE;
             rxStats.rcvdPkts = 1;
             rxStats.lostPkts = 0;
              }
            }

            Myreceive[0]=temp_receive/100+0;
            Myreceive[1]=temp_receive%100/10+0;
            Myreceive[2]=temp_receive%10+0;
            Myreceive[3]=;
            UartTX_Send_String("RECE:",strlen("RECE:"));
            UartTX_Send_String(Myreceive,4);
            UartTX_Send_String("    ",strlen("    "));   
            
            temp_per = (int32)((rxStats.lostPkts*1000)/(rxStats.lostPkts+rxStats.rcvdPkts));
            Myper[0]=temp_per/100+0;
            Myper[1]=temp_per%100/10+0; 
            Myper[2]=.;
            Myper[3]=temp_per%10+0;
            Myper[4]=%;
            UartTX_Send_String("PER:",strlen("PER:"));
            UartTX_Send_String(Myper,5);
            UartTX_Send_String("    ",strlen("    "));
           
            temp_rssi=(0-(int32)rxStats.rssiSum/32);
            Myrssi[0]=temp_rssi/10+0;
            Myrssi[1]=temp_rssi%10+0;
            UartTX_Send_String("RSSI:-",strlen("RSSI:-"));
            UartTX_Send_String(Myrssi,2);        
            UartTX_Send_String("
",strlen("
"));

       halLedClear(3);


      halMcuWaitMs(300);
            // Update LCD
            // PER in units per 1000
   /*         utilLcdDisplayValue(HAL_LCD_LINE_1, "PER: ", (int32)((rxStats.lostPkts*1000)/(rxStats.lostPkts+rxStats.rcvdPkts)), " /1000");
            utilLcdDisplayValue(HAL_LCD_LINE_2, "RSSI: ", (int32)rxStats.rssiSum/32, "dBm");
            #ifndef SRF04EB
            utilLcdDisplayValue(HAL_LCD_LINE_3, "Recv‘d: ", (int32)rxStats.rcvdPkts, NULL);
            #endif
            halLedClear(3);*/
    }
                    
  }
}

接收函数的作用:
  1、 串口在此初始化
  2、 初始化 Basic RF
  3、 不断地接收数据包,并检查数据包序号是否为期望值,作出相应处理
  4、 串口打印出,接收包的个数误包率及上 32 个数据包的 RSSI 值的平均值
有几个比较重要的数据作个简要的说明一下:
  为了获取传输的性能参数,接收器中包含了如下几个数据(包含在 rxStats变量中,
其类型为 perRxStats_t

rxStats.expectedSeqNum        预计下一个数据包的序号, 其值等于成功接收的数据包”+“丢失的数据包”+1

rxStats.rssiSum       上32个数据包的RSSI值的和

rxStats.rcvdPkts       每次PER测试中,成功接受到的数据包的个数

rxStats.lostPkts        丢失数据包的个数
这些数据具体是怎么得来,我们没有必要具体去分析,直接读取我们感兴趣的数据就可以了

误包率又是怎么计数的呢? TI 公司的使用文档有说明的如果大家想了解具体的话就可以去CC2530 BasicRFdocs 文件夹中找到

CC2530_Software_Examples.pdf 文档 4.2 章节有详细介绍的

实验操作:
a) 下载发射模块,在 per_test.c 中,找到:

/********************important select or
shelt****************************/
#define MODE_SEND //屏蔽时: appReceiver
//不屏蔽时: appTransmitter
/******************************************************************/

不要屏蔽#define MODE_SEND   编译下载到发射模块

b) 下载接收模块,同样的找到

/********************important select or shelt****************************/
//#define MODE_SEND //屏蔽时: appReceiver
//不屏蔽时: appTransmitter
/******************************************************************/

要屏蔽#define MODE_SEND     编译下载到接收模块

3、 接收模块 USB 连接 PC 机并给发射模块供电,打开串口调试助手,并设置好相应的 COM 口和波特率,先开接收模块,再开发送模块。

然后就可以看到我们的实验现象了。如图 5 所示。由于距离比较近,所以掉包不明显的,有兴趣的可以把发送节点拿到较远的地方,然后观察掉包率。

或者先打开发送模块,再打开接收模块来测试掉包,会显示出掉包情况。

 

 

完整PER_test.c代码:

技术分享图片
/***********************************************************************************
  Filename:     per_test.c

  Description:  This application functions as a packet error rate (PER) tester.
  One node is set up as transmitter and the other as receiver. The role and
  configuration parameters for the PER test of the node is chosen on initalisation
  by navigating the joystick and confirm the choices with S1.

  The configuration parameters are channel, burst size and tx power. Push S1 to
  enter the menu. Then the configuration parameters are set by pressing
  joystick to right or left (increase/decrease value) and confirm with S1.

  After configuration of both the receiver and transmitter, the PER test is
  started by pressing joystick up on the transmitter. By pressing joystick up
  again the test is stopped.

***********************************************************************************/

/***********************************************************************************
* INCLUDES
*/
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_int.h"
#include "hal_timer_32k.h"
#include "hal_joystick.h"
#include "hal_button.h"
#include "hal_board.h"
#include "hal_rf.h"
#include "hal_assert.h"
#include "util_lcd.h"
#include "basic_rf.h"
#include "per_test.h"
#include "string.h"

/***********************************************************************************
* CONSTANTS
*/
// Application states
#define IDLE                      0
#define TRANSMIT_PACKET           1


/*****************************important select or shelt***********************************/
#define MODE_SEND              //屏蔽时:appReceiver
                               //不屏蔽时:appTransmitter
/*******************************************************************************/


/***********************************************************************************
* LOCAL VARIABLES
*/
static basicRfCfg_t basicRfConfig;
static perTestPacket_t txPacket;
static perTestPacket_t rxPacket;
static volatile uint8 appState;
static volatile uint8 appStarted;

/***********************************************************************************
* LOCAL FUNCTIONS
*/
static void appTimerISR(void);
static void appStartStop(void);
static void appTransmitter();
static void appReceiver();
void initUART(void);//**************************
void UartTX_Send_String(int8 *Data,int len);//**********************


/****************************************************************
串口初始化函数
****************************************************************/
void initUART(void)
{ 
    PERCFG = 0x00;              //位置1 P0口
    P0SEL = 0x0c;              //P0_2,P0_3用作串口(外部设备功能)
    P2DIR &= ~0XC0;                   //P0优先作为UART0

    U0CSR |= 0x80;              //设置为UART方式
    U0GCR |= 11;                       
    U0BAUD |= 216;              //波特率设为115200
    UTX0IF = 0;                       //UART0 TX中断标志初始置位0
}
/****************************************************************
串口发送字符串函数            
****************************************************************/
void UartTX_Send_String(int8 *Data,int len)
{
  int j;
  for(j=0;j<len;j++)
  {
    U0DBUF = *Data++;
    while(UTX0IF == 0);
    UTX0IF = 0;
  }
}


/***********************************************************************************
* @fn          appTimerISR
*
* @brief       32KHz timer interrupt service routine. Signals PER test transmitter
*              application to transmit a packet by setting application state.
*
* @param       none
*
* @return      none
*/
static void appTimerISR(void)
{
    appState = TRANSMIT_PACKET;
}


/***********************************************************************************
* @fn          appStartStop
*
* @brief       Joystick up interrupt service routine. Start or stop 32KHz timer,
*              and thereby start or stop PER test packet transmission.
*
* @param       none
*
* @return      none
*/
static void appStartStop(void)
{
    // toggle value
    appStarted ^= 1;

    if(appStarted) {
        halTimer32kIntEnable();
    }
    else {
        halTimer32kIntDisable();
    }
}


/***********************************************************************************
* @fn          appConfigTimer
*
* @brief       Configure timer interrupts for application. Uses 32KHz timer
*
* @param       uint16 rate - Frequency of timer interrupt. This value must be
*              between 1 and 32768 Hz
*
* @return      none
*/
static void appConfigTimer(uint16 rate)
{
    halTimer32kInit(TIMER_32K_CLK_FREQ/rate);
    halTimer32kIntConnect(&appTimerISR);
}


/***********************************************************************************
* @fn          appReceiver
*
* @brief       Application code for the receiver mode. Puts MCU in endless loop
*
* @param       basicRfConfig - file scope variable. Basic RF configuration data
*              rxPacket - file scope variable of type perTestPacket_t
*
* @return      none
*/
static void appReceiver()
{
  uint32 segNumber=0;                              // 数据包序列号 
  int16 perRssiBuf[RSSI_AVG_WINDOW_SIZE] = {0};    // Ring buffer for RSSI 存储RSSI的环形缓冲区
  uint8 perRssiBufCounter = 0;                     // Counter to keep track of the 计数器用于RSSI缓冲区统计
     // oldest newest byte in RSSI
    // ring buffer
  perRxStats_t rxStats = {0,0,0,0};      
   int16 rssi;
  uint8 resetStats=FALSE;
  
  int8 Myper[5];        
  int8 Myrssi[2];
  int8 Myreceive[4];
  int32 temp_per;           //存放掉包率
  int32 temp_receive;       //存放接收的包的个数
  int32 temp_rssi;          //存放前32个rssi值的平均值
  initUART();                  // 初始化串口
  
#ifdef INCLUDE_PA
  uint8 gain;

  // Select gain (for modules with CC2590/91 only)
  gain =appSelectGain();
  halRfSetGain(gain);
#endif
    
   // Initialize BasicRF     初始化Basic RF 
  basicRfConfig.myAddr = RX_ADDR;
  if(basicRfInit(&basicRfConfig)==FAILED) 
  {
    HAL_ASSERT(FALSE);
  }
  basicRfReceiveOn();

  //halLcdClear();
    
  //halLcdWriteCharString(0,HAL_LCD_LINE_1, "Mode:Receiver");
  //halLcdWriteCharString(0,HAL_LCD_LINE_3, "Ready");
  /* 主循环 */
  UartTX_Send_String("PER_test: ",strlen("PER_test: "));
    // Main loop
  while (TRUE) 
  {
    while(!basicRfPacketIsReady());  // 等待新的数据包
    if(basicRfReceive((uint8*)&rxPacket, MAX_PAYLOAD_LENGTH, &rssi)>0) {
         halLedToggle(1);//*************P1_0
            
        // Change byte order from network to host order
      UINT32_NTOH(rxPacket.seqNumber);  // 改变接收序号的字节顺序
      segNumber = rxPacket.seqNumber;
            
     // If statistics is reset set expected sequence number to
     // received sequence number 若统计被复位,设置期望收到的数据包序号为已经收到的数据包序号     
      if(resetStats)
      {
        rxStats.expectedSeqNum = segNumber;
        
        resetStats=FALSE;
      }      
      // Subtract old RSSI value from sum
      rxStats.rssiSum -= perRssiBuf[perRssiBufCounter];  // 从sum中减去旧的RSSI值
      // Store new RSSI value in ring buffer, will add it to sum later
      perRssiBuf[perRssiBufCounter] =  rssi;  // 存储新的RSSI值到环形缓冲区,之后它将被加入sum

      rxStats.rssiSum += perRssiBuf[perRssiBufCounter];  // 增加新的RSSI值到sum
      if(++perRssiBufCounter == RSSI_AVG_WINDOW_SIZE) {
        perRssiBufCounter = 0;      // Wrap ring buffer counter 
      }

      
     // Check if received packet is the expected packet   检查接收到的数据包是否是所期望收到的数据包
      if(rxStats.expectedSeqNum == segNumber)  // 是所期望收到的数据包 
      {
        rxStats.expectedSeqNum++;  
      }
      
      // If there is a jump in the sequence numbering this means some packets in
       // between has been lost.
      else if(rxStats.expectedSeqNum < segNumber)  // 不是所期望收到的数据包(大于期望收到的数据包的序号)
      {                                            // 认为丢包
        rxStats.lostPkts += segNumber - rxStats.expectedSeqNum;
        rxStats.expectedSeqNum = segNumber + 1;
      }
      
       // If the sequence number is lower than the previous one, we will assume a
       // new data burst has started and we will reset our statistics variables.
      else  // (小于期望收到的数据包的序号)
      {      
        // Update our expectations assuming this is a new burst*****认为是一个新的测试开始,复位统计变量
        rxStats.expectedSeqNum = segNumber + 1;
        rxStats.rcvdPkts = 0;
        rxStats.lostPkts = 0;
      }
      rxStats.rcvdPkts++;
      
           // reset statistics if button 1 is pressed
            temp_receive=(int32)rxStats.rcvdPkts;
             if(temp_receive>1000)
            {
             if(halButtonPushed()==HAL_BUTTON_1){
             resetStats = TRUE;
             rxStats.rcvdPkts = 1;
             rxStats.lostPkts = 0;
              }
            }

            Myreceive[0]=temp_receive/100+0;
            Myreceive[1]=temp_receive%100/10+0;
            Myreceive[2]=temp_receive%10+0;
            Myreceive[3]=;
            UartTX_Send_String("RECE:",strlen("RECE:"));
            UartTX_Send_String(Myreceive,4);
            UartTX_Send_String("    ",strlen("    "));   
            
            temp_per = (int32)((rxStats.lostPkts*1000)/(rxStats.lostPkts+rxStats.rcvdPkts));
            Myper[0]=temp_per/100+0;
            Myper[1]=temp_per%100/10+0; 
            Myper[2]=.;
            Myper[3]=temp_per%10+0;
            Myper[4]=%;
            UartTX_Send_String("PER:",strlen("PER:"));
            UartTX_Send_String(Myper,5);
            UartTX_Send_String("    ",strlen("    "));
           
            temp_rssi=(0-(int32)rxStats.rssiSum/32);
            Myrssi[0]=temp_rssi/10+0;
            Myrssi[1]=temp_rssi%10+0;
            UartTX_Send_String("RSSI:-",strlen("RSSI:-"));
            UartTX_Send_String(Myrssi,2);        
            UartTX_Send_String("
",strlen("
"));

       halLedClear(3);


      halMcuWaitMs(300);
            // Update LCD
            // PER in units per 1000
   /*         utilLcdDisplayValue(HAL_LCD_LINE_1, "PER: ", (int32)((rxStats.lostPkts*1000)/(rxStats.lostPkts+rxStats.rcvdPkts)), " /1000");
            utilLcdDisplayValue(HAL_LCD_LINE_2, "RSSI: ", (int32)rxStats.rssiSum/32, "dBm");
            #ifndef SRF04EB
            utilLcdDisplayValue(HAL_LCD_LINE_3, "Recv‘d: ", (int32)rxStats.rcvdPkts, NULL);
            #endif
            halLedClear(3);*/
    }
                    
  }
}


/***********************************************************************************
* @fn          appTransmitter
*
* @brief       Application code 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
*/
static void appTransmitter()
{
  uint32 burstSize=0;
  uint32 pktsSent=0;
  uint8 appTxPower;
  uint8 n;

        // Initialize BasicRF               /* 初始化Basic RF */
  basicRfConfig.myAddr = TX_ADDR;
  if(basicRfInit(&basicRfConfig)==FAILED) 
  {
    HAL_ASSERT(FALSE);
  }

     // Set TX output power                      /* 设置输出功率 */
  //appTxPower = appSelectOutputPower();
  halRfSetTxPower(2);//HAL_RF_TXPOWER_4_DBM
//  halRfSetTxPower(appTxPower);

   // Set burst size                 /* 设置进行一次测试所发送的数据包数量 */
  //burstSize = appSelectBurstSize();
  burstSize = 1000;
  
  // Basic RF puts on receiver before transmission of packet, and turns off
  // after packet is sent
  basicRfReceiveOff();

      // Config timer and IO          /* 配置定时器和IO *************************/
  //n= appSelectRate();
  appConfigTimer(0xC8);
  //halJoystickInit();

     // Initalise packet payload            /* 初始化数据包载荷 */
  txPacket.seqNumber = 0;
  for(n = 0; n < sizeof(txPacket.padding); n++) 
  {
    txPacket.padding[n] = n;
  }
  
  //halLcdClear();
  //halLcdWriteCharString(0,HAL_LCD_LINE_1, "Mode:Transmitter");
  //halLcdWriteCharString(0,HAL_LCD_LINE_2, "CENTER to start/stop");

    // Main loop          /* 主循环 */
  while (TRUE) 
  {
    // Wait for user to start application
    //while(!halJoystickPushed());  // 等待用户启动应用
    //appStartStop();   

    while(appStarted)
      {
    //{
      //if( halJoystickPushed()) 
      //{
      //  appStartStop();
      //}

      if (pktsSent < burstSize) 
      {
        //if( appState == TRANSMIT_PACKET ) 
        //{
        // Make sure sequence number has network byte order
          UINT32_HTON(txPacket.seqNumber);  // 改变发送序号的字节顺序
          basicRfSendPacket(RX_ADDR, (uint8*)&txPacket, PACKET_SIZE);

        // Change byte order back to host order before increment     /* 在增加序号前将字节顺序改回为主机顺序 */
          UINT32_NTOH(txPacket.seqNumber);
          txPacket.seqNumber++;

          pktsSent++;
   /*      #ifdef SRF04EB
          utilLcdDisplayValue(HAL_LCD_LINE_2, "Sent: ", (int32)pktsSent, NULL);
          #else
          utilLcdDisplayValue(HAL_LCD_LINE_3, "Sent: ", (int32)pktsSent, NULL);
          #endif*/
          appState = IDLE;
          halLedToggle(1);   //改变LED1的亮灭状态
          halMcuWaitMs(5000);
        //}
      }
      else
        appStarted = !appStarted;
      
    //}

      // Reset statistics and sequence number/* 复位统计和序号 */
     pktsSent = 0;
    //txPacket.seqNumber = 0;
    //halLcdClear();
    //halLedClear(3);
    //halLcdWriteCharString(0,HAL_LCD_LINE_1, "Mode:Transmitter");
    //halLcdWriteCharString(0,HAL_LCD_LINE_2, "CENTER to start/stop");
    }
  }
}


/***********************************************************************************
* @fn          main
*
* @brief       This is the main entry of the "PER test" 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
*/
void main (void)
{
    uint8 appMode;
    
    appState = IDLE;
    appStarted = TRUE;//*****************************by boo
    
    // Config basicRF
    basicRfConfig.panId = PAN_ID;
    basicRfConfig.ackRequest = FALSE;

    // Initialise board peripherals
    halBoardInit();

    // Initalise hal_rf
    if(halRfInit()==FAILED) {
      HAL_ASSERT(FALSE);
    }
    
    // Indicate that device is powered
    halLedSet(1);

    // Print Logo and splash screen on LCD
    utilPrintLogo("PER Tester");

    // Wait for user to press S1 to enter menu
//    while (halButtonPushed()!=HAL_BUTTON_1);***********************
    halMcuWaitMs(350);
//    halLcdClear();************************************

    // Set channel
//  basicRfConfig.channel = appSelectChannel();
    basicRfConfig.channel = 0x0B;

    
    // Set mode
//   appMode = appSelectMode();******************

    #ifdef MODE_SEND
     appMode = MODE_TX;
    #else
     appMode = MODE_RX;
    #endif  
    // Transmitter application
    if(appMode == MODE_TX) {
        // No return from here
        appTransmitter();
    }
    // Receiver application
    else if(appMode == MODE_RX) {
        // No return from here
        appReceiver();
    }
    // Role is undefined. This code should not be reached
    HAL_ASSERT(FALSE);
}


/***********************************************************************************
  Copyright 2008 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED 揂S IS?WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
***********************************************************************************/
View Code

 



 



 

 

 












































以上是关于ZigBee开发(11)--组网实验PER的主要内容,如果未能解决你的问题,请参考以下文章

物联仓储系统ZigBee组网原理

zigbee组网函数在哪儿

zigbee技术的组网优势在哪?

基于zigbee农业物联网项目实战课程

Zigbee技术入门教程-01Zigbee无线组网技术入门的学习路线

Zigbee组网原理详解