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

分别对SUN节点和PLANET节点进行说明。SUN节点流程图如图12.2

所示,节点上电是首先进行硬件及相应变量的初始化,然后创建网络,循环检测是否有数据包。如果接到数据包,对其进行解析,根据不同类型的数据包执行不同的操作。于此同时读取串口信息,如果串口有输入命令,对命令进行解析,执行不同的操作。

PLANET节点流程图如图12.3所示,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嵌入式无线传感器网络》邱铁,夏锋,周玉编著.清华大学出版社,2014年5月

时间: 2024-10-29 19:10:38

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

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

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

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

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

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

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

Cocos2dx 3.2 节点之间相互通信与设置触摸吞噬的方法

实际开发中,我们经常会遇到这样的情况.我们有一个层layer1,这个层包含一个menu层,menu1层里又包含了一个节点按钮button1.现在需要实现一个效果:点击button1弹出一个对话框,这个对话框里也包含一个menu2和一个按钮button2,点击button2能够关闭这个对话框.这个情况很普遍,在游戏ui中我们有大量的二级弹窗都需要用到这种效果(在这里我们不考虑直接在layer2里removefromparent,这样就不能达成学习目的了).我们可以用三种方法实现这个效果,分别是:

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

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

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通道,通道支持一次和连续的操作模式 应用实例解析

部署tomcat负载均衡集群,实现节点之间内存中的Session共享。

在实验之前先来了解下tomcat会话管理器(Manager) Manger对象用于实现HTTP会话管理的功能,介绍下几种常见的: 1.StandardManager(标准会话管理器) 用于非集群环境中对单个处于运行状态的Tomcat实例会话进行管理.当Tomcat关闭时,这些会话相关的数据会被写入磁盘上的一个名叫SESSION.ser的文件,并在Tomcat下次启动时读取此文件.如果tomcat正常关闭会话不会丢失,如果是tomcat主机崩溃或者进程崩溃那会话是一定会丢失的. 2.Persist

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

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

Prism 4 文档 ---第9章 松耦合组件之间通信

当构建一个大而负责的应用程序时,通用的做法时将功能拆分到离散的模块程序集中.将模块之间的静态引用最小化.这使得模块可以被独立的开发,测试,部署和升级,以及它迫使松散耦合的沟通. 当在模块之间通信时,你需要知道不同通信方式之间的区别,那样你才能确定哪种方式对于你的特定的场景最合适,Prism类库提供了以下几种通信方式: 命令.当希望对于用户的交互马上采取动作时使用. 事件聚合.用于ViewModel,展现层,或者控制之间没有所期望的直接动作时. 区域上下文.使用它可以提供宿主和宿主区域的View之