STM32W108無線射頻模塊兩節點之間通信實例

本文基於802.15.4/ZigBeeSimpleMac協議棧編寫程序,實現兩個STM32W108無線節點之間的通信。節點分爲SUN節點和PLANET節點,SUN節點使用STM32W108無線開發板,PLANET節點使用STM32W108無線節點,SUN節點可與PC機進行通信。

程序設計與實現

程序的設計基於SimpleMac協議棧進行,根據官方提供的MAC協議棧示例代碼進行的裁剪更改,10章已對協議棧代碼進行了解析,在此就不詳細說明,以下只給出部分主要相關代碼。

文件solar-system.c部分內容:

部分全局變量定義:

//負載類型

#define  PT_LED           (0x09)

#define  PT_TRSEND        (0x0A)

#define  PT_GENERIC_DATA8 (0x0B)

#define  PT_GENERIC_DATA32 (0x0C)

 

//數據包類型

#define  GENERIC_DATA8_PACKET  ((FT_DATA <<4)  | (PT_GENERIC_DATA8 <<0))

#define  GENERIC_DATA32_PACKET  ((FT_DATA  <<4) | (PT_GENERIC_DATA32 <<0))

#define  LED_PACKET     ((FT_DATA <<4) |  (PT_LED <<0)) 

#define  TRSEND_PACKET        ((FT_DATA  <<4) | (PT_TRSEND <<0)) 

 

函數processRxPacket()

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

功能描述:對接收的數據包進行解析解碼處理,並根據不同類型的數據包執行不同的操作,數據包信息通過數據包回調函數保存在結構體變量rxData

輸入參數:無

輸出參數:無

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

void processRxPacket(void)

{

…...

//不同的數據包類型,不同的處理

     switch(packetType) {

     case (GENERIC_DATA_PACKET): //普通類型數據包

         RX_DETAILS(printf("GENERIC_DATA_PACKET\r\n");)

#ifdef SUN_ROLE

     case (LED_PACKET): //PT_LED數據包

         printf("Message from my PLANET\r\n");       

         halSetLed(LED_D1); //點亮LED

            halCommonDelayMilliseconds(500);//延時500ms

         halClearLed(LED_D1);

        break;

#endif

     case (SUN_SEARCH_PACKET): //處理搜索父節點的數據包

       RX_DETAILS(printf("SUN_SEARCH_PACKET\r\n");)

       for(i=0;i<PLANET_TABLE_SIZE;i++)   //掃描子節點數組

{

         if(!planetTable[i].active) //判斷是否有有效空間

{         

           packet[0] = (24+2); //數據包長度

           packet[1] = FCF_DATA; //幀類型

           packet[2] = FCF_LONGDST + FCF_LONGSRC; //地址類型

           currSeqNum++; //數據包序列號

           packet[3]=currSeqNum;

           packet[4] = (0xFFFF>>0)&0xFF; //16位短目標地址

           packet[5] = (0xFFFF>>8)&0xFF;

           memcpy((packet+6), longSrcAddr, 8); //64位長目標地址

           packet[14] = (ST_RadioGetPanId()>>0)&0xFF; //16位源PAN ID

           packet[15] = (ST_RadioGetPanId()>>8)&0xFF;

           memcpy((packet+16), ST_RadioGetEui64(), 8); //64位長源地址

           packet[24] = PT_SUN_AVAILABLE; //負載類型

           enqueueTxPacket(TRUE, 0xFFFF, packet, 0); //廣播

           break;

         }

       }

       break;

     case (SUN_AVAILABLE_PACKET): //SUN節點發送的父節點可用數據包

       RX_DETAILS(printf("SUN_AVAILABLE_PACKET\r\n");)

       if(availableSunFound) //如果已加入網絡,則停止父節點搜索

{

         return;

       }

       if(srcPanId!=MyPANID) //如果PAN ID不同,則不處理此數據包

       {

          goto stopProcessing;

       }

       availableSunFound=TRUE;

      ST_RadioSetPanId(srcPanId); //設置節點PAN ID

 

       packet[0] = (22+2); //數據包長度

       packet[1] = FCF_DATA + FCF_ACKREQ + FCF_INTRAPAN; //幀類型

       packet[2] = FCF_LONGDST + FCF_LONGSRC; //地址類型

       currSeqNum++;  //數據包序列號

       packet[3]=currSeqNum;

      packet[4] =  (ST_RadioGetPanId()>>0)&0xFF; //16位短目標地址

       packet[5] = (ST_RadioGetPanId()>>8)&0xFF;

       memcpy((packet+6), longSrcAddr, 8); //64位長目標地址

       memcpy((packet+14), ST_RadioGetEui64(), 8); //64位長源地址

       packet[22] = PT_JOIN_REQUEST; //負載類型

       enqueueTxPacket(TRUE, 0xFFFF, packet, 0); //單播發送請求加入網絡數據包

       break;

 

       case (JOIN_REQUEST_PACKET): //SUN節點收到請求加網的包

       RX_DETAILS(printf("JOIN_REQUEST_PACKET\r\n");)  //串口終端顯示

       {

         u8 flag=0;

         u8 pt = PT_JOIN_DENIED;  //負載類型

         u8 assignedShortId[2] = {0xFE, 0xFF};

         packet[0] = (24+2); //數據包長度

         packet[1] = FCF_DATA + FCF_ACKREQ + FCF_INTRAPAN; //幀類型

         packet[2] = FCF_LONGDST + FCF_LONGSRC; //地址類型

         currSeqNum++;  //數據包序列號

         packet[3]=currSeqNum;

         packet[4] = (ST_RadioGetPanId()>>0)&0xFF; //16位短目標地址

         packet[5] = (ST_RadioGetPanId()>>8)&0xFF;

         memcpy((packet+6), longSrcAddr, 8); //64位長目標地址

         memcpy((packet+14), ST_RadioGetEui64(), 8); //64位長源地址

       

        /*搜尋表中是否存在與加網節點相同的64位長地址,如果有則覆蓋,若沒有則繼續遍歷表*/

         for(i=0;i<PLANET_TABLE_SIZE;i++)

{

           u8 k=0;

           while(k<8)

           {

if(planetTable[i].longAddr[k]!=rxData.packet[14+k])

               break;

             k++;

           }

           if(k==8)

           {

            planetTable[i].active = TRUE;

            shortAddrCounter++;

            planetTable[i].shortAddr =  shortAddrCounter;

            pt = PT_JOIN_ACCEPTED; //允許加入網絡負載類型

            assignedShortId[0] =  (shortAddrCounter>>0)&0xFF;

            assignedShortId[1] =  (shortAddrCounter>>8)&0xFF;

            printf("Join: Planet 0x%04X  (index %d) has joined the network\r\n",

shortAddrCounter, i);

            flag=1;

            break;

           }

         }

 

       if(flag==0)   //如果沒有找到相同長地址,則查找空缺位置加進去

       {

           for(i=0;i<PLANET_TABLE_SIZE;i++)

            if(!planetTable[i].active) {

            planetTable[i].active = TRUE;

            shortAddrCounter++;

            planetTable[i].shortAddr =  shortAddrCounter;

            memcpy(planetTable[i].longAddr,  longSrcAddr, 8);

            pt = PT_JOIN_ACCEPTED;  //允許加入網絡負載類型

            assignedShortId[0] =  (shortAddrCounter>>0)&0xFF;

            assignedShortId[1] =  (shortAddrCounter>>8)&0xFF;

            printf("Join: Planet 0x%04X  (index %d) has joined the network\r\n",

shortAddrCounter, i);

            break;

           }

         }

         packet[22] = pt; //負載類型

         packet[23] = assignedShortId[0];

         packet[24] = assignedShortId[1];

         enqueueTxPacket(TRUE, 0xFFFF, packet, 0); //單播迴應

       }

       break;  

     case (JOIN_ACCEPTED_PACKET): //PLANET節點處理加入網絡允許數據包

       RX_DETAILS(printf("JOIN_ACCEPTED_PACKET\r\n");)

       ST_RadioSetNodeId((rxData.packet[payloadStart+1]<<0)|

                           (rxData.packet[payloadStart+2]<<8)); //設置NodeID

       networkJoinedStopSearching = TRUE; //加入網絡成功,停止搜索

       break;

     case (JOIN_DENIED_PACKET): //PLANET節點處理加入網絡拒絕數據包

       RX_DETAILS(printf("JOIN_DENIED_PACKET\r\n");)

       ST_RadioSetPanId(0xFFFF); //重設PAN ID

       break;     

……

……   

     default:

       RX_DETAILS(printf("Unknown payload type\r\n");)

       goto stopProcessing;

   } 

stopProcessing:

   rxData.packetBeingProcessed = FALSE;

}

 

函數joinCmd()

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

功能描述:PLANET節點執行請求加入網絡的操作,循環11~26信道,分別發送PT_SUN_PACKET類型數據包

輸入參數:無

輸出參數:無

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

void joinCmd(void)

{

   u8 packet[128];

   u8 searchChannel;

   u32 lastTime;

   StStatus status = ST_SUCCESS;

   printf("\r\n");

   if(activeInNetwork) {

     printf("Already in network\r\n");

     return;

  }

   printf("Inactive node joining network and becoming a  planet\r\n"); 

   initNetworkState(); //初始化網絡狀態 

   TURN_RADIO_ON(); //打開無線

   activeInNetwork = TRUE; //加入網絡成功,如果加入網絡失敗,會重新設置爲FALSE

 

   //構造發送請求加入網絡的數據包

   packet[0] = (18+2);

   packet[1] = FCF_DATA; //幀類型

   packet[2] = FCF_SHORTDST + FCF_LONGSRC; //地址類型

   packet[4] = (0xFFFF>>0)&0xFF; //目標PAN ID

   packet[5] = (0xFFFF>>8)&0xFF;

   packet[6] = (0xFFFF>>0)&0xFF; //目標Node ID

   packet[7] = (0xFFFF>>8)&0xFF;

   packet[8] = (0xFFFF>>0)&0xFF; //PAN ID

   packet[9] = (0xFFFF>>8)&0xFF;

   memcpy((packet+10), ST_RadioGetEui64(), 8); //64位長地址

   packet[18] = PT_SUN_SEARCH; //負載類型

 

   printf("Trying channel");

   //循環搜索所有信道

   for(searchChannel=ST_MIN_802_15_4_CHANNEL_NUMBER;

       searchChannel<=ST_MAX_802_15_4_CHANNEL_NUMBER; searchChannel++)

{

//信道搜索過程中會延遲200ms,所以每次都需要重置看門狗,防止觸發復位

     halResetWatchdog();

     printf(" %d", searchChannel);

     status = ST_RadioSetChannel(searchChannel);

assert(status==ST_SUCCESS);

 

     currSeqNum++; //數據包序列號

     packet[3]=currSeqNum;

 

     availableSunFound = FALSE;

     enqueueTxPacket(TRUE, 0xFFFF, packet, 0); //廣播搜索父節點

    

     //延遲200ms等待回覆

     lastTime = halCommonGetInt32uMillisecondTick();

     do {

       processRxPacket(); //處理接收的數據包

       txTick();

}  while(elapsedTimeInt32u(lastTime,  halCommonGetInt32uMillisecondTick())<200);

    

     //判斷是否加入網絡成功

if(networkJoinedStopSearching) 

{

       printf("\r\n");

       printf("Joined on channel %d with PAN ID 0x%04X.  My ID is now 0x%04X.\r\n",

             ST_RadioGetChannel(), ST_RadioGetPanId(),  ST_RadioGetNodeId());

       activeInNetwork = TRUE;

#ifdef PLANET_ROLE

       autoSendRate = 60; //設置子節點向父節點數據包發送週期

       halSetLed(LED_D4); //加入網絡成功,點亮LED4

#endif

       return;

     }

  }

   printf("\r\n");

   printf("Did not join.   Returning to inactive state.\r\n");

   activeInNetwork = FALSE; //加入網絡失敗

}

 

 

本文出自《STM32W108嵌入式無線傳感器網絡》邱鐵,夏鋒,周玉編著.清華大學出版社,20145

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章