信號傳輸質量檢測
重點在代碼分析部分...就是廢話比較多...
一、實驗平台
兩個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 }