关闭

STM32W108无线射频模块两节点之间通信实例

标签: STM32W108射频模块无线ZigBee无线传感器网络无线模块
514人阅读 评论(0) 收藏 举报
分类:

本文基于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

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:12938次
    • 积分:359
    • 等级:
    • 排名:千里之外
    • 原创:21篇
    • 转载:0篇
    • 译文:1篇
    • 评论:4条
    文章分类
    文章存档
    最新评论