SM32W108無線射頻模塊多個節點之間通信實例

SM32W108無線射頻模塊多個節點之間通信實例中分別對SUN節點和PLANET節點進行說明。節點上電是首先進行硬件及相應變量的初始化,然後創建網絡,循環檢測是否有數據包。如果接到數據包,對其進行解析,根據不同類型的數據包執行不同的操作。於此同時讀取串口信息,如果串口有輸入命令,對命令進行解析,執行不同的操作。

PLANET節點首先進行一些初始化工作,然後申請加入網絡,加網成功後,循環監測是否有數據包及按鍵是否被按下,如果有數據包對其進行解析,執行相應的操作,如果按鍵被按下,則向SUN節點發送數據包,並讓LED3閃爍一次。

程序的設計基於SimpleMac協議棧進行,以下給出部分主要相關代碼。該實例中的部分代碼與11章中的兩節點通信實例代碼相同,本章不再重複說明。

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

部分變量全局變量定義:

//負載類型定義

#define  PT_SLEEPING      (0x08)

#define  PT_LED           (0x09)

#define  PT_TRSEND        (0x0A)

 

//數據包類型定義

#define  SYN_SLEEPING_WAITTIME    ((FT_DATA <<4)  | (PT_SLEEPING   <<0))

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

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

 

函數processRxPacket()

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

功能描述:對接收的數據包進行解析,並執行相應的操作

輸入參數:無

輸出參數:無

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

void  processRxPacket(void)

{

  ......

......

  …… 

  //不同類型數據包進行不同處理

  switch(packetType) {

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

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

#ifdef  SUN_ROLE

      halToggleLed(LED_D1); //讓LED1閃爍

      halCommonDelayMilliseconds(500);//延遲500ms

      halClearLed(LED_D1); //關閉LED1

#endif

#ifdef  PLANET_ROLE

      halToggleLed(LED_D3); //讓LED3閃爍

      halCommonDelayMilliseconds(500); //延遲500ms

       halClearLed(LED_D3); //關閉LED3

#endif

    rxData.lqi = calculateLqi(rxData.errors,  (rxData.packet[0]+3)); //計算通信鏈路質量

printf("RX: Addr=0x%04X,  VDD=%dmV, RxSFD=0x%05X, ", shortSrcAddr,

((rxData.packet[payloadStart+1]<<0)|(rxData.packet[payloadStart+2]<<8)),  rxData.time);

if(rxData.packet[payloadStart+5]&0x80)   //判斷數據包是否包含SFD

{

        //獲取TX SFD數據,並輸出

        rxData.packet[payloadStart+5] &=  ~0x80;

        printf("TxSFD=0x%05X, ", ((rxData.packet[payloadStart+3]<<  0)|

(rxData.packet[payloadStart+4]<<  8)| (rxData.packet[payloadStart+5]<<16)));

}

else

{

printf("TxSFD=-------,  ");

}

printf("RSSI=%ddBm,  LQI=0x%02X\r\n", rxData.rssi, rxData.lqi);

break;

 

#ifdef  PLANET_ROLE

    case (SYN_SLEEPING_WAITTIME):  //PT_SLEEPING類型數據包

        printf("SYN_SLEEPING_WAITTIME\r\n");

             halToggleLed(LED_D3); //閃爍LED3

             halCommonDelayMilliseconds(1000); //延遲1000ms

        halClearLed(LED_D3); //關閉LED3

        break;

    case (SYN_LED_WAITTIME): //PT_LED類型數據包

         printf("SYN_LED_WAITTIME\r\n");

             halToggleLed(LED_D3);    //閃爍LED3

             halCommonDelayMilliseconds(500); //延遲500ms

        halClearLed(LED_D3); //關閉LED3

        halCommonDelayMilliseconds(500);

        halToggleLed(LED_D3);   

             halCommonDelayMilliseconds(500);

        halClearLed(LED_D3);

        halCommonDelayMilliseconds(500);

        halToggleLed(LED_D3);   

             halCommonDelayMilliseconds(500);

        halClearLed(LED_D3);

        break;

#endif

    case (TRSEND_PACKET): //PT_TRSEND類型數據包

         sendVddDataPacket(0x0000,0x0001,TRUE); //向節點1發送數據包

        printf("trsend  success\r\n");

        break;

……

……

……  

    default:

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

      goto stopProcessing;

  }

 

stopProcessing:

  rxData.packetBeingProcessed = FALSE;

}

 

函數sendVddDataPacket()

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

功能描述:向參數中傳入的地址發送類型負載類型爲PT_GENERIC_DATA的數據包

輸入參數:vddMillivolts爲發送的16位數據,dstShortAddr爲目的地址,sendDirectly爲調用不同發送函數的表示符。

輸出參數:無

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

void  sendVddDataPacket(u16 vddMillivolts,u16 dstShortAddr, boolean sendDirectly)

{

  u8 packet[128];

 

  //數據包封裝

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

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

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

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

  packet[3] = currSeqNum;

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

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

  packet[6] =  (dstShortAddr>>0)&0xFF; //目標短地址

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

  packet[8] = (ST_RadioGetNodeId()>>0)&0xFF;  //源短地址

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

  packet[10] = PT_GENERIC_DATA; //負載類型

  packet[11] =  (vddMillivolts>>0)&0xFF; //發送的16位數據

  packet[12] =  (vddMillivolts>>8)&0xFF;

 

//歸零Tx SFD有效負載,MSB用於指示SFD有效

  packet[13] = 0;

  packet[14] = 0;

  packet[15] = 0;

  enqueueTxPacket(sendDirectly, dstShortAddr,  packet, 15); //發送數據包

  printf("send already!\r\n");

}

 

函數sendVddDataPacket1()

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

功能描述:向參數中傳入的地址發送類型負載類型爲PT_SLEEPING的數據包

輸入參數:vddMillivolts爲發送的16位數據,dstShortAddr爲目的地址,sendDirectly爲調用不同發送函數的表示符。

輸出參數:無

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

void  sendVddDataPacket1(u16 vddMillivolts,u16 dstShortAddr,boolean sendDirectly)

{

  u8 packet[128];

 

  //數據包封裝

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

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

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

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

  packet[3] = currSeqNum;

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

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

  packet[6] =  (dstShortAddr>>0)&0xFF; //目標短地址

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

  packet[8] =  (ST_RadioGetNodeId()>>0)&0xFF; //源短地址

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

  packet[10] = PT_SLEEPING; //負載類型

  packet[11] =  (vddMillivolts>>0)&0xFF; //發送的16位數據

  packet[12] =  (vddMillivolts>>8)&0xFF;

 

//歸零Tx SFD有效負載,MSB用於指示SFD有效

  packet[13] = 0;

  packet[14] = 0;

  packet[15] = 0; 

  enqueueTxPacket(sendDirectly, dstShortAddr,  packet, 15); //發送數據包

#ifdef  SUN_ROLE 

  halToggleLed(LED_D2); //LED2閃爍

  halCommonDelayMilliseconds(500); //延時500ms

  halClearLed(LED_D2);

#endif

  printf("send sleeping packet to every  planet!\r\n");

}

 

函數sendVddDataPacket2()

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

功能描述:向參數中傳入的地址發送類型負載類型爲PT_LED的數據包

輸入參數:vddMillivolts爲發送的16位數據,dstShortAddr爲目的地址,sendDirectly爲調用不同發送函數的表示符。

輸出參數:無

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

void  sendVddDataPacket2(u16 vddMillivolts,u16 dstShortAddr,boolean sendDirectly)

{

  u8 packet[128];

 

  //數據包封裝

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

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

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

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

  packet[3] = currSeqNum;

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

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

  packet[6] =  (dstShortAddr>>0)&0xFF; //目標短地址

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

  packet[8] =  (ST_RadioGetNodeId()>>0)&0xFF; //源短地址

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

  packet[10] = PT_LED; //負載類型

  packet[11] =  (vddMillivolts>>0)&0xFF; //發送的16位數據

  packet[12] =  (vddMillivolts>>8)&0xFF;

 

//歸零Tx SFD有效負載,MSB用於指示SFD有效

  packet[13] = 0;

  packet[14] = 0;

  packet[15] = 0;

  enqueueTxPacket(sendDirectly, dstShortAddr,  packet, 15); //發送數據包

#ifdef  SUN_ROLE

  halToggleLed(LED_D1); //LED1閃爍

  halCommonDelayMilliseconds(500); //延時500ms

  halClearLed(LED_D1);

#endif

  printf("send message to every  planet!\r\n");

}

 

函數sendVddDataPacket3()

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

功能描述:向參數中傳入的地址發送類型負載類型爲PT_TRSEND的數據包

輸入參數:vddMillivolts爲發送的16位數據,dstShortAddr爲目的地址,sendDirectly爲調用不同發送函數的表示符。

輸出參數:無

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

void  sendVddDataPacket3(u16 vddMillivolts,u16 dstShortAddr,boolean sendDirectly)

{

  u8 packet[128];

 

  //數據包封裝

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

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

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

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

  packet[3] = currSeqNum;

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

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

  packet[6] =  (dstShortAddr>>0)&0xFF; //目標短地址

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

  packet[8] =  (ST_RadioGetNodeId()>>0)&0xFF; //源短地址

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

  packet[10] = PT_TRSEND; //負載類型

  packet[11] =  (vddMillivolts>>0)&0xFF; //發送的16位數據

  packet[12] =  (vddMillivolts>>8)&0xFF;

 

//歸零Tx SFD有效負載,MSB用於指示SFD有效

  packet[13] = 0;

  packet[14] = 0;

  packet[15] = 0;

  enqueueTxPacket(sendDirectly, dstShortAddr,  packet, 15); //發送數據包

#ifdef  PLANET_ROLE

  halToggleLed(LED_D3); //LED3閃爍

  halCommonDelayMilliseconds(500); //延遲500ms

  halToggleLed(LED_D3);

  halCommonDelayMilliseconds(500);

#endif

  printf("trsend already!\r\n");

}

 

函數planetTableCmd()

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

功能描述:實現列出SUN節點的子節點信息,當SUN節點收到命令’t後執行此函數

輸入參數:

輸出參數:無

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

void  planetTableCmd(void)

{

  u8 i,k;

  printf("\r\n");

  if(!activeInNetwork) {

    printf("Not active in a  network\r\n");

    return;

  }

  if(ST_RadioGetNodeId() != 0x0000) {

    printf("Not a sun\r\n");

    return;

  }

 

  printf("Planet Table\r\n");

  printf("Active | DataPending | Short  Address |    Long Address\r\n");

  for(i=0;i<PLANET_TABLE_SIZE;i++)  //輸出子節點信息

{

    printf("   %d    | ", planetTable[i].active);

    printf("      %d      | ", isDataPendingForShortId(planetTable[i].shortAddr));

    printf("    0x%04X     | 0x", planetTable[i].shortAddr);

    k=8;

while(k--)

{

      printf("%02X",  planetTable[i].longAddr[k]);

    }

    printf("\r\n");

  }

}

 

函數main()

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

功能描述:主函數,實現節點硬件初始化,及節點功能的實現

輸入參數:無

輸出參數:無

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

int main(void)

{

     u32 seed;

     StStatus status = ST_SUCCESS;

     halInit(); //初始化硬件

     uartInit(115200, 8, PARITY_NONE, 1); //初始化UART

  

     //配置PA4和PA4引腳爲複用功能,用於數據包的跟蹤

     halGpioConfig(PORTA_PIN(4),GPIOCFG_OUT_ALT);

     halGpioConfig(PORTA_PIN(5),GPIOCFG_OUT_ALT);

     GPIO_IRQDSEL = PORTB_PIN(2); //將IRQD連接到PB2/SC1RXD

    

     //允許IRQD標誌位激活任何的IRQD

     GPIO_INTCFGD = (3<<GPIO_INTMOD_BIT);

     INT_GPIOFLAG = INT_IRQDFLAG;

     INT_PENDCLR = INT_IRQD;

     INTERRUPTS_ON();

 

#ifdef PLANET_ROLE

     halInitLed();   //初始化LED燈

     halInitButton(); //初始化按鍵

printf("\r\nSimpleMAC  (%s) Sample Application: 'Planet role'!\r\n",

SIMPLEMAC_VERSION_STRING);

#endif

 

#ifdef SUN_ROLE

     halInitLed();   //初始化LED燈

     halInitButton(); //初始化按鍵

printf("\r\nSimpleMAC  (%s) Sample Application: 'Sun role'!\r\n",

SIMPLEMAC_VERSION_STRING);

#endif

  

     //生成隨機種子

     ST_RadioGetRandomNumbers((u16 *)&seed, 2);

     halCommonSeedRandom(seed);

  

     //初始化無線射頻模塊

     ST_RadioEnableOverflowNotification(TRUE);

     status = ST_RadioInit(radioPowerState);

     assert(status==ST_SUCCESS); 

     printf("Enter ? for list of commands\r\n");

     printf("\r\n> ");

    

//SUN節點操作部分

#ifdef SUN_ROLE

     u8 ch;

     formCmd(); //SUN節點首先創建網絡

     while(TRUE)

     {

         do

         {

            processRxPacket();//檢測收到數據包並處理

            halCommonDelayMilliseconds(10);//延時10毫秒

         }while ((!__io_getcharNonBlocking(&ch))); //獲取串口發送的命令

        

         if(ch=='s') //命令s,向第一個子節點發送數據包

         {

            printf("s command is  running!\n");

            u16  dstShortAddr=planetTable[0].shortAddr;//第一個子節點地址

             sendVddDataPacket(0x0000,dstShortAddr,TRUE);//向第一個子節點發送數據包

         }

         else if(ch=='b') //命令b,發送廣播數據

         {

            printf("b command is  running!\n");

            u16 dstShortAddr=0xffff;//將此處的地址改爲0xffff,即廣播地址

             sendVddDataPacket(0x0000,dstShortAddr,TRUE);

         }

         else if(ch=='d') //命令d,依次向所有節點發送LED閃爍數據包

         {

            printf("d command is  running!\n");

            u8 cl1=PLANET_TABLE_SIZE;//定義節點總數

            u8 m1=0;//定義臨時計數變量m1

            u16 base1=10000;//定義等待基時間

 

            //定義存儲每個節點等待時間的數組

             u16 led_time[PLANET_TABLE_SIZE];

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

                    led_time[m1]= (cl1-m1)*1000+base1; //給每個節點等待時間賦值

            u8 i=0;//定義臨時計數變量i

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

            {

                //遍歷planetTabl中的每個PLANET節點併發送信息

                if(planetTable[i].active)

                {

                    sendVddDataPacket2(led_time[i],planetTable[i].shortAddr,TRUE); 

                     halCommonDelayMilliseconds(500);//延遲500ms

                }

             }

         }

         else if(ch=='l') //命令l,依次向所有節點發送睡眠數據包

         { 

            u8 cl=PLANET_TABLE_SIZE;

            u8 m=0;

            u16 base=10000;

            u16 sleep_time[PLANET_TABLE_SIZE]; 

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

                 sleep_time[m]= (cl-m)*1000+base; //睡眠時間

            u8 i=0;

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

            {

              if(planetTable[i].active)

              {

                //向Planet節點發送睡眠數據包

                sendVddDataPacket1(sleep_time[i],planetTable[i].shortAddr,TRUE);

              }

            }

         }

         else if(ch=='t') //命令t

         {

            planetTableCmd(); //列出子節點信息

         }

         else if(ch=='?') //命令?,列出當前支持命令

         {

            printf("s     send message to the first  PLANET\n");

            printf("d     send message to every PLANET one by  one\n");

            printf("b     broadcast\n");

            printf("l     syn sleep\n");

            printf("t      PlanetTable\n");

            printf("?     help  command\n");

         }

         else

            printf("Unknown  Commamd\r\n");

         INT_GPIOFLAG = INT_IRQDFLAG;

         INT_PENDCLR = INT_IRQD;

     }

#endif

 

//PLANET節點操作部分

#ifdef PLANET_ROLE

     activeInNetwork = FALSE;

     do

     {

         joinCmd(); //請求加入網絡

     }while(!activeInNetwork);

     while(TRUE)

     {

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

         halCommonDelayMilliseconds(10); //延時10ms

        

         //如果S3被按下,向Sun節點發送信息

         if(halGetButtonStatus(BUTTON_S3) == BUTTON_PRESSED)

         {

            sendVddDataPacket3(0x0001,  0x0000, TRUE); //向SUN節點發送數據包

            halCommonDelayMilliseconds(400);  //延遲400ms

         }       

         INT_GPIOFLAG = INT_IRQDFLAG;

         INT_PENDCLR = INT_IRQD;

     }

#endif

}

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

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