SM32W108无线射频模块两节点之间通信实例
[复制链接]
本文基于802.15.4/ZigBee的SimpleMac协议栈编写程序,实现两个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.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.longAddr[k]!=rxData.packet[14+k])
break;
k++;
}
if(k==8)
{
planetTable.active = TRUE;
shortAddrCounter++;
planetTable.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.active) {
planetTable.active = TRUE;
shortAddrCounter++;
planetTable.shortAddr = shortAddrCounter;
memcpy(planetTable.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; //加入网络失败
}
|