实现无线传感器网络的相关协议层出不穷,如红外、蓝牙、ZigBee、WiFi等。但是目前这些协议都存在种种问题,例如红外技术遇到障碍物就失灵,蓝牙比较耗电,ZigBee协议比较复杂等等[1]。针对这些问题,Cypress公司推出了CyFi低功耗无线解决方案,同时还推出了针对新手的PSoC FirstTouch入门套件CY3271以及其他扩展套件。本文使用此套件组建CyFi无线传感器网络,并在PC机上通过USB接口实现节点的绑定及数据的采集。
1 CyFi简介
Cypress公司先前推出的WirelessUSB技术已被广泛应用于无线鼠标、键盘、游戏手柄等产品中。在此基础之上,Cypress公司又推出了针对嵌入式控制领域的一款低成本、低功耗、高可靠性的无线射频解决方案——CyFi。CyFi的市场定位使其具有可靠、简化、低功耗、多信道等特点[2]。
① 可靠。通过使用直接序列扩频(DSSS)调制技术,CyFi能够使传输的数据从可能的错误中恢复回来,从而提供出色的连接可靠性。对于来自同样工作在非常拥挤的2.4 GHz频段的WiFi、蓝牙、ZigBee等其他无线技术的干扰,CyFi的跳频技术能以预设的频段间隔自动搜索干净的信道进行通信,如图1所示。同时,CyFi的链接管理功能可以根据网络环境将发射功率、传输速率自动调整到保证可靠链接的最优配置上。DSSS调制、跳频技术和成熟的链接管理算法使得CyFi成为2.4 GHz频段的高可靠性无线解决方案。

图1 CyFi跳频技术
② 简化。CyFi提供的轻量级星型协议栈CYFISNP尺寸非常小,应用于Hub仅占用8 KB,而应用于节点仅为6 KB,如图2所示。CYFISNP协议栈可直接在PSoC Designer中使用,其所提供的用户模块使开发者只需简单的拖放即可实现创新的无线设计,用户无需自行编写任何通信协议或编码,与PSoC可编程片上系统的结合使其在研发过程的任何阶段都可进行重新编程。

图2 协议栈大小比较
③ 低功耗。为了实现低功耗,CyFi尽量工作在睡眠模式。这意味着在干扰较弱的情况下,CyFi将以尽可能快的速度(1 Mbps)传输,以缩短传输时间;而在干扰较强的情况下,将启用DSSS调制技术并提高RF发射功率以250 kbps的速率传输,从而减少重传的可能。当节点与Hub的距离较近时,节点也能降低发射功率从而减小功耗。这种有效的电源管理机制使得采用CyFi的典型传感器应用只靠2节AA电池就可使用4年之久[3]。
④ 多信道。由于CyFi仅占用1 MHz的带宽,故可用信道多达80个,而ZigBee等仅能使用16个5 MHz的信道。
2 CY3271简介
CY3271是Cypress公司针对新手推出的一款带CyFi的低成本USB接口套件,包括PSoC集成开发环境PSoC Designer、用于数据采集的感应控制软件SCD、带RF功能的PC桥FTPC、多功能板FTMF、支持长距离无线应用并带功率放大器的RF扩展板FTRF,以及2个电池板。其中,PC桥FTPC作为CyFi的Hub设备使用;RF扩展板FTRF作为CyFi的节点设备使用,同时带有一个超低功耗的温度传感器;而多功能板FTMF中带有CapSense触摸传感器、接近式传感器、温度传感器、光传感器和红、黄、蓝3个LED灯。本文中仅以CapSense触摸传感器为例。
3 硬件结构
由于CyFi使用的是星型广播式网络协议,所有消息需要经过中心Hub,故实现节点A到节点B数据通信的过程如下:节点A通过I2C协议采集多功能板A的CapSense触摸滑块的位置、3个LED灯的亮灭情况等数据,并与目标节点B的ID号一起通过RF发送出去;Hub检测到网络中有消息后,再根据消息中的目标节点ID将消息转发出去,同时将数据保存到缓存中等待PC机读取;节点B接收到消息之后根据消息中的数据,同样通过I2C协议控制多功能板B上的3个LED灯的亮灭。其中Hub所在设备FTPC有2个PSoC内核: 主内核实现USB—I2C转换和各个板卡(包括从内核)的编程功能;从内核实现Hub功能,同时通过I2C与主内核连接。系统功能框图如图3所示。

图3 系统功能框图
4 软件设计
4.1 PSoC软件设计
CY3271套件的光盘中提供了各个PSoC的设计样例[4],本文中PSoC部分的设计就是在这些样例的基础上修改而成的。
为了实现上述功能,需要在节点A发送的消息中添加目的节点B的ID信息,以便Hub将接收到的消息再转发出去。每个CyFi收发器有2种ID: 一种为6字节的Radio ID,此ID在收发器出厂时烧入,不可更改且全球唯一;另一种为1字节的Node ID,此ID在节点绑定时确定,可以事先指定也可以由Hub动态分配。由于Radio ID较复杂,开发人员在开发过程中可以忽略Radio ID,而只关注Node ID。
对于多功能板A可直接使用光盘上的MF_CS_SLIDE样例,不需要修改。对于节点A使用的RF_I2C_BRIDGE样例,主函数中需修改调用CYFISNP_BindStart()函数时的参数,如下:
for (;;) {
if (CheckBindButton()) {//若按下绑定键
CYFISNP_BindStart(DEV_ID_TX);//则使用DEV_ID_TX为ID绑定节点A
LED_GRN_ON;
}
if (CheckWakeButton()) {//若按下唤醒键
sendNewTxMsg();//则强制采集并发送一次消息
}
……
}
其中,采集并发送消息的函数sendNewTxMsg()中发送的消息类型必须修改为CYFISNP_API_TYPE_CONF_BCDR,且应在调用的loadTxData()函数中添加如下一句以添加节点B的ID信息:
txApiPkt.payload\[I2C_PAYLOAD_MAX\] = DEV_ID_RX;
对于Hub使用的RF_HUB样例,首先需要将用户模块CYFISNP的Device ID assignment属性设置为Preassigned Device ID,以便节点A、B使用指定的ID绑定成功。重新编译后,在ServeSNPPackets()函数中接收到CYFISNP_API_TYPE_CONF_BCDR类型的消息之后,添加如下代码:
if (pApiPkt﹥devId == DEV_ID_TX) {//来自节点A的消息才转发
testPacket.length = pApiPkt﹥length;//testPacket为预先定义的转发消息
testPacket.rssi = pApiPkt﹥rssi;
testPacket.type = pApiPkt﹥type;
testPacket.devId = pApiPkt﹥payload[length1];
for (index = 0; index ﹤ length 1; index++) {
testPacket.payload\[index\]=pApiPkt﹥payload\[index\];
}
testPacket.payload[length1] = pApiPkt﹥devId;//消息结尾存入源节点ID以便验证检查消息的长度及目标节点是否已绑定,若满足条件且网络空闲则转发消息
if (testPacket.length﹤=CYFISNP_BCD_PAYLOAD_MAX&& (CYFISNP_EEP_DEV_REC_ADR+testPacket.devId)﹥devId !=0) {
if (CYFISNP_TxDataPend(testPacket.devId) == CYFISNP_TX_DATA_EMPTY) {
CYFISNP_TxDataPut(&testPacket);
}
}
}
对于节点B使用的RF_I2C_BRIDGE样例,其主函数同样需要修改CYFISNP_BindStart()函数的参数,同时还需暂存接收到的消息。核心代码如下:
for (;;) {
if (CheckBindButton()) {//若按下绑定键
CYFISNP_BindStart(DEV_ID_RX);//则使用DEV_ID_RX为ID绑定节点B
LED_GRN_ON;
}
if (CheckWakeButton()) {//若按下唤醒键
receiveNewRxMsg();//则强制接收一次消息并控制多功能板B
}
……
if (CYFISNP_RxDataPend() == TRUE) {//接收到消息
CYFISNP_API_PKT *pRxApiPkt;
pRxApiPkt = CYFISNP_RxDataGet();//使用txApiPkt暂存
for (ivar=0; ivar ﹤ pRxApiPkt﹥length; ++ivar){
txApiPkt.payload[ivar] = pRxApiPkt﹥payload\[ivar\];
}
CYFISNP_RxDataRelease();
}
……
}
其中,负责接收消息并且控制多功能板B的函数receiveNewRxMsg()中必须与节点A对应的将消息类型修改为CYFISNP_API_TYPE_CONF_BCDR,且在其中调用的SetI2CData()函数如下:
static void SetI2CData(void) {
WORD dataDelay;//等待RF准备就绪
ChipSelect_ON;
CYFISNP_TimeSet(&dataDelay, DATA_READY_TIME);
while (!CYFISNP_TimeExpired(&dataDelay) && !IS_DataReady_ON);//启动I2C写操作
I2C_bWriteBytes(SLAVE_ADDRESS, txBuffer, 8, I2C_CompleteXfer);//等待I2C写操作完成
while ((I2C_bReadI2CStatus() & I2CHW_WR_COMPLETE) == FALSE);
I2C_ClrWrStatus();
ChipSelect_OFF;
}
对于多功能板B使用的MF_CS_SLIDE样例,首先使用PSoC Designer的工程克隆功能,将样例中PSoC Express编写的系统级工程克隆为PSoC Designer的芯片级工程,否则不能直接修改程序中的代码。然后在主函数中添加如下核心代码:
I2CHW_Start();//使用I2C模块
I2CHW_EnableSlave();//设置I2C模块为从设备
I2CHW_EnableInt();//使能I2C中断
I2CHW_InitWrite(WriteBuffer, 8);//初始化供主设备(节点B)写入的缓存
while(1) {//当检测到写完成标志时开始操作
if (I2CHW_bReadI2CStatus() & I2CHW_WR_COMPLETE) {
LED_State = WriteBuffer\[0\];
I2CHW_ClrWrStatus();//清除写完成标志
I2CHW_InitWrite(WriteBuffer, 8);//重新初始化供主设备(节点B)写入的缓存
}//根据接收到的LED_State设置3个LED灯的亮灭
CMX_RGBLED_SetValue(&pse_LED, LED_State);
}
这样,5个部分的PSoC程序全部编写完成,最后分别编译各个程序再使用PSoC Programmer烧录到各个板卡中即可。
4.2 上位机软件设计
尽管CY3271的配套光盘中已包含了用于数据采集和感应控制的软件SCD,但为了弄清楚FTPC设备USB接口的读写过程,以及今后将Hub移植到其他平台,还是编写了功能可定制的上位机软件。此软件使用Visual C++ 2005编写,同时使用了TeeChart图表显示控件。
由于CY3271中的FTPC设备采用USB接口与PC机连接,且此USB设备已模拟成标准的HID设备,故上位机软件与FTPC设备通信时只需要使用标准的HID设备的控制及读写函数。对FTPC设备的读写过程大致如下[5]:
① 使用HidD_GetHidGuid()函数获取本机HID设备的接口类GUID。
② 使用SetupDiGetClassDevs()函数获取HID类中所有设备的信息集合。
③ 在该设备信息集合中,使用SetupDiEnumDeviceInterfaces()函数获取每个设备的信息。
④ 使用SetupDiGetDeviceInterfaceDetail()函数获取某个设备的详细信息。要获取某个设备的详细信息,此函数必须调用2次。第1次调用是为了得到保存设备信息需要的缓冲区大小,第2次调用才是真正地获取设备详细信息。
⑤ 获得设备的详细信息后,使用设备详细信息结构体中的DevicePath作为CreateFile()函数的参数打开指定的设备。
⑥ 打开设备后,使用HidD_GetAttributes()函数获取设备的属性(属性中包含了厂商编号VID、产品编号PID以及产品版本号等信息)。然后比较VID、PID是否与FTPC的一致。如果一致(VID=04B4,PID=F115),则退出查找,说明设备已经找到;如果不一致,则切换到下一个设备,然后重复前面的步骤③~⑥。
找到设备后,就可以对设备进行数据读写了。使用Bus Hound软件查看USB设备及抓取USB数据包。经分析发现,FTPC设备是使用HID设备中的中断端点传输数据的,故应调用ReadFile()和WriteFile()函数实现读写[5]。由于FTPC设备为HID从设备,故对FTPC设备的每个读或写的过程都同时有先写后读的操作。也就是说,写FTPC设备时是先写入相关的写命令和欲写入的数据,再读出写入是否成功的反馈;读FTPC设备时是先写入相关的读命令,再读出欲读取的数据。
按照上述方法,再结合Hub的PSoC程序中定义的命令和Bus Hound抓包得到的结果,就可以对FTPC设备中的Hub执行相应的操作了,如进入绑定状态,读取绑定结果,读取接收到的消息等。节点绑定成功之后, 即可查看实时的数据采集情况,包括数据采集的时间和滑块位置值等,如图4所示。

图4 数据采集界面
结语
CyFi的出现使无线传感器网络中的各种问题迎刃而解,而PSoC的用户模块方式极大地方便了开发人员,使开发人员只需通过拖放及添加简单的代码,就能轻松地完成复杂的无线传感器网络应用的设计与开发。同时,入门套件的Hub设备模拟成标准的HID设备,也使PC机上应用程序的开发变得轻而易举。