现在的位置: 首页 > 综合 > 正文

Zigbee入门指导(三)——一个接近实用的WSN系统

2013年09月21日 ⁄ 综合 ⁄ 共 4958字 ⁄ 字号 评论关闭
文章目录

Zigbee入门指导(三)

——一个接近实用的WSN系统

logiclimit

      在之前的两篇指导当中,大家已经了解到了基于Ti CC2430的Zigbee开发的一些基本的概念和知识,也成功的运行了Ti自带的例程,然而这些与实用还相差甚远。作为入门指导的最后一篇,将对如何建立一个实用的WSN系统进行探讨。

      Zigbee的出现是为了满足WSN(Wireless Sensor Network)的要求,一般而言WSN有以下几个特征:

1.采集点众多,分布面积广

2.网络节点间的位置关系不定,节点动态加入或脱离网络

3.采集点无法和市电网络相连,依赖于电池供电,要求有很好的节电及电源管理

为了实现节能的特性,还跟CC2430模块以外的采集模块有关,本文主要关注的是CC2430自身的管理使用,故对外界数据的采集简化为从AD中采集数据。目标系统将具备以下功能:

1.协调器建立网络,终端节点加入网络

2.节点能采集多种数据

      从例程中选用一个合适的范例作为模板可以大大缩短开发时间,节约成本。选用SimpleApp作为模板。SimpleApp中有两个例程,一个是控制器-开关,一个是收集器-传感器,将使用收集器-传感器例程。收集器-传感器例程中以传感器终端的温度及电源电压为数据源,传感器定时采集这两个数据,送往收集器,收集器收到数据后通过串口传给PC机。可以说SimpleApp本身就是一个接近实用的WSN例程,本文的目标在于学习SimpleApp的使用,并加上一个通过AD采集数据的功能。此外,由于SimpleApp的传感器终端启动后就一直采集发送数据,无法由收集器控制其采集的开启/关停,将增添由PC发送指令到收集器,再由收集器发送指令控制某终端的某项采集功能的开启/关闭。

一、建立新工程

      为了和例程SimpleApp区分开,新建工程命名为WSNApp,其中只包含Collector和Sensor,且只为EB板设置,本节内容不会对程序的运行有实质影响,修改工程名只是为了管理上的方便。也可不修改工程名,只做功能上的修改,直接跳到下一节的内容。先原地复制SimpleApp工程文件夹,并修改目录名为WSNApp。WSNApp中有两个目录,为中的为应用程序,删除SimpleController.c和SimpleSwitch.c,将SimpleApp.h更名为WSNApp.h。中存放的具体的Project的设置,如果还没打开过相关工程的话,里面应该只有三个文件SimpleApp.ewd、SimpleApp.ewp和SimpleApp.eww,将这三个文件均改名为WSNApp,扩展名保持不变。这三个文件都是XML格式的文本文件,可以用记事本等工具打开修改,我使用的Notepad++,其支持XML语言的高亮显示及折叠功能。

      修改WSNApp.eww,先将所有的SimpleApp替换为WSNApp。里面的代码结构如下

member>

  project>WSNAppproject>

  configuration>SimpleCollectorDBconfiguration>

member>

member>

  project>WSNAppproject>

  configuration>SimpleCollectorEBconfiguration>

member>

member>

  project>WSNAppproject>

  configuration>SimpleControllerDBconfiguration>

member>

每个member下是相应的project及相关的设置,删除所有的DB及Controller、Switch。最后只保留以下内容

member>

  project>WSNAppproject>

  configuration>SimpleCollectorEBconfiguration>

member>

member>

  project>WSNAppproject>

  configuration>SimpleSensorEBconfiguration>

member>

      修改WSNApp.ewp,WSNApp.ewp有8902行,如果所用的文本编辑器不支持XML语言会改得比较痛苦。先将所有的SimpleApp替换为WSNApp。WSNApp.ewp存放的是工程的目录结构,WSNApp.ewp中的configuration段定义的是各个project 的设置,还有group段定义的是各个project中各文件的关联关系。删除有关DB及Controller、Switch的configuration段。修改App的group段的中的DB及Controller、Switch段落。

      修改WSNApp.ewd,先删除有关DB及Controller、Switch的configuration段即可。

二、Collector的修改

      Collector程序要添加PC和Collector的间的通讯、通过无线发送指令到Sensor。要为Collector添加一个用户事件,用于发送数据。

1、串口设置

      Ti的协议栈中已经有了有关的串口通信的驱动,可直接调用,使用串口有关的指令,需包含"hal_uart.h"头文件,在SimpleCollector.c和sapi.c中均要包含。要添加预编译指令HAL_UART。使用halUARTCfg_t来配置串口,配置串口时需配置输入/输出缓冲区的大小等信息。由于用户task的初始化在sapi.c中,串口的初始化也放在sapi.c中。先在sapi.h中定义以下常量

#ifdef COLLECTOR

  #define SERIAL_PORT_THRESH 48

  #define SERIAL_PORT_RX_MAX  64

  #define SERIAL_PORT_TX_MAX  64

  #define SERIAL_PORT_IDLE  6

  #define SERIAL_PORT_RX_CNT  80

#endif

由于sapi.h和sapi.c是collector和sensor共用的,故使用的条件编译的方式定义常量。
      在sapi.c中,先定义串口的配置变量。
void SAPI_Init( byte task_id ) 

{ 

  uint8 startOptions; 

#ifdef COLLECTOR 

  halUARTCfg_t uartConfig; 

#endif

在SAPI_Init()的末尾初始化串口
 
#ifdef COLLECTOR

  uartConfig.configured           = TRUE;              // 2430 don't care.

  uartConfig.baudRate             = HAL_UART_BR_38400;  // CC2430 only allow 38.4k or 115.2k

  uartConfig.flowControl          = HAL_UART_FLOW_OFF;  // Turn off flow control to fit most serial ports' setting

  uartConfig.flowControlThreshold = SERIAL_PORT_THRESH;

  uartConfig.rx.maxBufSize        = SERIAL_PORT_RX_MAX;

  uartConfig.tx.maxBufSize        = SERIAL_PORT_TX_MAX;

  uartConfig.idleTimeout          = SERIAL_PORT_IDLE;   // 2430 don't care.

  uartConfig.intEnable            = TRUE;              // 2430 don't care.

  uartConfig.callBackFunc         = rxCB;

  HalUARTOpen (HAL_UART_PORT_0, &uartConfig);

#endif

 

  // Set an event to start the application

  osal_set_event(task_id, ZB_ENTRY_EVENT);

}

此处有两个需要注意的地方,串口波特率只能为38400或115.2k,接收数据的回调函数是rxCB。定义函数rxCB来处理来自串口的数据,收到数据后触发相关的事件。
      在SimpleCollector.c中,向PC机传送数据的指令位于zb_ReceiveDataIndication()中,为
#if defined( MT_TASK )

    debug_str( (uint8 *)buf );

#endif

由于使用自定义的串口操作,需在预编译中去除MT_TASK,故无法使用其debug_str()函数向PC发送数据,将相关代码替换为
HalUARTWrite ( HAL_UART_PORT_0, buf, 32 ); 

2、接收来自PC的数据

收到数据后要通知OS收到了串口数据,在SimpleCollector.c中定义了相关的事件。

#define SERIAL_PORT_MSG_RCV_EVT    0x0008

定义指向数据的指针和数据长度

static uint8 *otaBuf = NULL; 

static uint8 otaLen;

rxCB的定义如下

void rxCB( uint8 port, uint8 event )

{

  uint8 *buf, len;

 

  if (!otaBuf)

  {

    if ( !(buf = osal_mem_alloc( SERIAL_PORT_RX_CNT )) )

    {

      return;

    }

  }

 

  len = HalUARTRead( port, buf, SERIAL_PORT_RX_CNT );

 

  if ( !len )  // Length is not expected to ever be zero.

  {

    osal_mem_free( buf );

    return;

  }

  

  otaBuf = buf;

  otaLen = len;

 

  osal_set_event( sapi_TaskID, SERIAL_PORT_MSG_RCV_EVT );

}

当数据接收完毕后,触发事件SERIAL_PORT_MSG_RCV_EVT。

3、Collector向Sensor发送指令

      从sapi.c中的

if ( events & ( ZB_USER_EVENTS ) )

{

  // User events are passed to the application

  zb_HandleOsalEvent( events );

 

  // Do not return here, return 0 later

}

可知,在zb_HandleOsalEvent()中处理用户自定义的事件,当收到PC传来的数据后触发了SERIAL_PORT_MSG_RCV_EVT,将无线发送指令的程序作为此事件的响应,原有的SimpleCollector.c中的void zb_HandleOsalEvent( uint16 event )是空的,为其添加以下内容

void zb_HandleOsalEvent( uint16 event )

{

  if ( event & SERIAL_PORT_MSG_RCV_EVT )

  {

    Collector_SendData( otaBuf, otaLen );

  }

}

其中Collector_SendData()的定义如下

void Collector_SendData( uint8 *buf, uint8 len )

{

  volatile uint16 tempDstAddr;

  tempDstAddr = buf[0];

  tempDstAddr = tempDstAddr 


    
  tempDstAddr += buf[1];

  zb_SendDataRequest( tempDstAddr, COLLECTOR_CMD_ID, 1, &buf[2], 0, 0, AF_DEFAULT_RADIUS );

  osal_mem_free( otaBuf );

} 

其中的zb_SendDataRequest()即为通过无线发送指令的函数,其中的参数COLLECTOR_CMD_ID是Endpoint中的发送cluster。原有的Collector程序只能接受无线数据,不能发送无线数据,是通过设置发送cluster为实现的,增添发送cluster

#define NUM_OUT_CMD_COLLECTOR                1

 

const cId_t zb_OutCmdList[NUM_OUT_CMD_COLLECTOR] =

抱歉!评论已关闭.