您的位置:首页 > 理论基础 > 计算机网络

SM32W108无线射频模块多个节点之间通信实例

2015-08-12 10:00 671 查看
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.
4000
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_Radio
ede5
GetPanId()>>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嵌入式无线传感器网络》邱铁,夏锋,周玉编著.清华大学出版社,2014年5月

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息