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

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[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; //加入网络失败

}

时间: 2024-10-18 23:38:36

SM32W108无线射频模块两节点之间通信实例的相关文章

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

本文基于802.15.4/ZigBee的SimpleMac协议栈编写程序,实现两个STM32W108无线节点之间的通信.节点分为SUN节点和PLANET节点,SUN节点使用STM32W108无线开发板,PLANET节点使用STM32W108无线节点,SUN节点可与PC机进行通信. 程序设计与实现 程序的设计基于SimpleMac协议栈进行,根据官方提供的MAC协议栈示例代码进行的裁剪更改,第10章已对协议栈代码进行了解析,在此就不详细说明,以下只给出部分主要相关代码. 文件solar-syste

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

STM32W108无线射频模块多节点之间通信实例 基于STM32W108的SimpleMac协议栈编写程序,实现多个无线节点之间的通信.节点分为SUN节点和PLANET节点,SUN节点使用STM32W108无线开发板,PLANET节点使用STM32W108无线数据采集节点,SUN节点可与PC机进行通信. 编程与实现 程序的设计基于SimpleMac协议栈进行,以下给出部分主要相关代码.该实例中的部分代码与第11章中的两节点通信实例代码相同,本章不再重复说明. 文件solar-system.c部分

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

分别对SUN节点和PLANET节点进行说明.SUN节点流程图如图12.2 所示,节点上电是首先进行硬件及相应变量的初始化,然后创建网络,循环检测是否有数据包.如果接到数据包,对其进行解析,根据不同类型的数据包执行不同的操作.于此同时读取串口信息,如果串口有输入命令,对命令进行解析,执行不同的操作. PLANET节点流程图如图12.3所示,PLANET节点首先进行一些初始化工作,然后申请加入网络,加网成功后,循环监测是否有数据包及按键是否被按下,如果有数据包对其进行解析,执行相应的操作,如果按键被

STM32W108无线射频模块外部中断接口应用实例

STM32W108无线射频模块外部中断接口应用实例 编写中断服务程序,响应外部中断,实现通过按键触发中断,然后通过LED显示相应的状态. 1 STM32W108开发环境与硬件说明 硬件:STM32W108 Zigbee开发板.5V 1A电源.J-LINK烧写器.PC机等. 软件:IAR Embedded Workbench开发软件. 为开发板中的按键连接原理图,按键与STM32W108无线模块连接的原理图. 按键连接图 2软件设计与规划 测试程序的流程图如下所示,节点首先初始化硬件,然后注册中断

STM32W108无线射频模块通用IO接口应用实例

STM32W108无线射频模块通用IO接口应用实例 本实例编写STM32W108的GPIO测试程序,通过控制GPIO引脚,实现对LED灯的控制. 开发环境与硬件说明 硬件:STM32W108无线开发板,5V 1A电源,J-Link烧写器,PC机等. 软件:IAR Embedded Workbench for ARM开发软件. 硬件连接的原理图如图6.15所示:通过STM32W108无线模块的GPIO引脚PA3控制LED1,GPIO引脚PC2控制LED2. 硬件规划:其中用到的控制管脚为GPIO_

linux程序设计——pipe调用在两进程之间通信(第十三章)

13.4    pipe调用 在看过高级的popen函数之后,再来看看底层的pipe函数.通过这个函数在两个程序之间传递数据不需要启动一个shell来解释请求的命令.它同时提供了对读写数据的更多控制. pipe函数的原型如下所示: #include <unistd.h> int pipe(int file_descriptor[2]); 参数:是一个由两个整数类型的文件描述符组成的数组. 返回值:该函数在数组中填上两个新的文件描述符,如果成功则返回0,如果失败则返回-1并设置errno来表明失

在二进制树中的节点之间的最大距离(最长路径树)——递归解决方案

上一篇文章即是对这一主题的变化.并给出了一个非递归溶液. 我给出原题的一种递归解法. 将会看到,现比較上篇博文.今天给出的递归解法的代码实现是相当简洁的. 问题描写叙述: 假设我们把二叉树看成一个图.父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数. 写一个程序.求一棵二叉树中相距最远的两个节点之间的距离.測试用的树: n1 /             \ n2             n3 /        \ n4          n5 /     \  

STM32W108无线射频模块AD转换器应用实例

STM32W108无线射频模块AD转换器应用实例 STM32W108 AD转换器是一个一阶∑-△转换器,具有以下特性: l  分辨率可达12位 l  采样最小时间5.33us(188KHz) l  6个外部和4个内部输入源,可进行差分和单端转换 l  两个电压转换范围(差分):-VREF~+VREF,-VDD_PADS~+VDD_PADS l  可选择内部和外部参考标准VREF:内部的VREF可用于输出 l  数字偏移和增益校准 l  专用DMA通道,通道支持一次和连续的操作模式 应用实例解析

STM32W108无线射频模块串行通信接口编程实例

STM32W108无线射频模块UART通信应用实例 基于STM32W108芯片,编写串口测试程序,测试串口通信,完成PC通过串口与STM32W108进行通信. 开发环境与硬件平台 硬件:STM32W108无线开发板,5V1A电源,J-LINK烧写器,串口线,PC机等. 软件:IAREmbedded Workbench开发工具,SimpleMac协议栈. 硬件连接的原理图,PB2是芯片STM32W108的接收端,PB1是芯片STM32W108的发送端. 硬件规划:其中用到的管脚有PB1,PB2,通