请选择 进入手机版 | 继续访问电脑版
查看: 23280|回复: 43

我的ZigBee项目—医疗无线监护系统—开发历程分享(一)

[复制链接]
wwh199169 发表于 2011-10-28 02:20:55 | 显示全部楼层 |阅读模式
本帖最后由 wwh199169 于 2011-10-28 11:14 编辑

今天下午终于结束了本项目的一个重要阶段——中期检查答辩。从答辩的过程来看,评委老师们对本项目完成的进度和质量还是很满意的,特别是得知我所学并非电气专业,而是机械专业之后,更是夸奖有加,呵呵···。与参加答辩的其它项目组比起来,我的项目还是很有希望通过国创(国家大学生创新实践计划)项目的审核,成功申请到那个一万元资金的项目!      当然,来这里发帖不是为了炫耀而来的,只是表达一下如释重负,付出有得之后的喜悦心情。为了这次答辩,更为了能成功申请到国创项目,我这些天可以说是茶饭不思、废寝忘食的在学习、编程、调试,之前还因为遇到阻碍在论坛里发了两篇求助贴。其实后来更是不断的遇到问题,但经过数日夜以继昼的鏖战,都一一克服了,以至于今天能自信的走上讲台进行我的项目展示,想来实在感慨良多···
      感慨完了,想到自己开发经历的艰辛也许也是许多和我一样的ZigBee初学者们的感受,就发出此帖,以自己的项目为例,尽量详细的写出开发的过程、遇到的问题以及解决的方法。希望能给初学者们一点借鉴,也希望高手们能给我更高层次的指导,在下不胜感激!
      好了,前奏就啰嗦到这里,下面进入正题...
      首先,向大家简单介绍一下我的项目结构。本项目是一个基于ZigBee技术的无线医疗监视网络(呵呵,网上好像有不少类似的文章),硬件部分组成如下图所示:


      图中上面外挂了传感器和蜂鸣器电路的是两个是温度采集节点(属于终端节点设备),下面带LCD模块的是数据收集显示节点(属于协调器设备)。模块中主要的元器件见图中注释说明。
      系统的工作过程如下图所示:


      过程并不复杂,就是测温节点将传感器采集到的数据无线发送给显示节点处理、显示。这只是原来的预期功能,未能够申请国创项目,我经过这几天的努力,加入了如下功能:
1,温度数值超出上下限时,显示节点能自动报警;


2,病人能够通过采集节点上的按键发出求助信息,显示节点能够显示提示并报警;


3,显示节点在报警过程中可通过按键取消报警,表示正在处理报警事件;


4,加入与计算机的串口通信功能,即通过串口调试助手软件在计算机上显示测温节点传送来的64位地址和温度数值;


       以上各功能弱是指针对一个节点都很容易实现,但是,如果不止一个,那么对不同测温节点发出的报警信息要区分对待,不能一概取消,否则当两个测温节点同时出现报警时,可能会有一个被误取消而得不到处理,那样的话病人就有麻烦了。而这部分正是我这几天的工作重点和难点,为此我在程序中尝试了许多方法,最终才找到一个勉强可行的方法。这种方法原则上可行,但实际运行中也有问题,后面会详细说明,希望高手们看到后能给与在下指点!
      下面从头开始说起,很久很久以前,有一个······呵呵,开玩笑的。   本项目是基于TI给出的一个无线测温例程改编的,程序结构如下图:


      可以看出,该工程是由LocDongle(显示节点程序)和RefNode(测温节点程序)两个子工程组成的,分别下载到对应的节点模块中即可各自运行。这里需要指出,其实测温节点和显示节点模块除了分别外挂了传感器和液晶模块外,其他硬件是完全一样的,所谓的“分别下载”是指在两个子工程的Project--Options--C/C++ Compiler--Preprocessordifine symbols命令行里分别添加LOCATION_DONGLELOCATION_RefNode定义,另外,显示模块由于需要液晶功能,还要加入LCD_SUPPORTED,后面加入串口功能还要添加HAL_UART_BIG_TX_BUF=1定义。如下图所示:


       众所周知,添加自己的应用应该在APP子层进行。从上面的协议栈结构图中可以看到,APP层下面包含了3个.c文件,分别是LocationProfile.c、SampleApp.cSensor_18B20.c
       LocationProfile.c文件下面包含了许多.h文件,仔细看其中还有两个.c文件:LocDongle.cRefNode.c,显然,在预处理命令行定义不同的节点属性时LocationProfile.c加载对应的LocDongle.c或RefNode.c文件,我想工程就是从这里开始区分两个子工程的。虽然包含了很多文件,但是这个LocationProfile.c自己却很精悍短小,只有几行代码,如下:
/*********************************************************************
* INCLUDES
*/

#include "LocationProfile.h"

/*********************************************************************
* CONSTANTS
*/

/*********************************************************************
* TYPEDEFS
*/

/*********************************************************************
* GLOBAL VARIABLES
*/

/*********************************************************************
* LOCAL VARIABLES
*/

/*********************************************************************
* LOCAL FUNCTIONS
*/
#if defined ( LCD_SUPPORTED )
  #include "lcd128_64.h"
#endif
#if defined ( LOCATION_REFNODE )
  #include "RefNode.c"
#endif

#if defined ( LOCATION_BLINDNODE )
  #include "BlindNode.c"
  #include "LocationEngine.c"
#endif

#if defined ( LOCATION_DONGLE )
  #include "LocDongle.c"
#endif

/*********************************************************************
*********************************************************************/

      呵呵,我还是第一次看到#include后面跟着.c文件呢!代码很简单,相当于各个子工程的入口。但是大家请注意我用蓝色标出的注释段,可以看出,文件里的诸多定义,如INCLUDES、CONSTANTS等都是分类好了的,而且这种分明的层次结构在所有的文件里都有,TI这种条理清晰、结构井然的编程风格是很值得我们学习的哦!
     第二个SampleApp.c文件虽然代码很长,但好像只有两段最重要,其它的似乎都没有被执行,至少我在单步调试的时候没发现程序运行到它们,不知事实如何?代码中最重要的那两段如下:
第一段
/*********************************************************************
* GLOBAL VARIABLES
*/

uint8 SampleApp_TaskID;

// The order in this table must be identical to the task initialization calls below in osalInitTask.
// 本表中的顺序必须与osalInitTask()函数下的人物初始化函数调用顺序一致,这样做是为了保证一个事件标志能够与相应的任务初始化函数一一对应,否则,一个事件发生后将导致错误的初始化函数运行,就像张冠李戴所说的那样···
const pTaskEventHandlerFn tasksArr[] = {
#if defined( ZMAC_F8W )
  macEventLoop,
#endif
#if !defined( NONWK )
  nwk_event_loop,
#endif
  Hal_ProcessEvent,
#if defined( MT_TASK )
  MT_ProcessEvent,
#endif
#if !defined( NONWK )
  APS_event_loop,
  ZDApp_event_loop,
#endif
  SampleApp_ProcessEvent,
#if defined ( LOCATION_REFNODE )
  RefNode_ProcessEvent
#endif
#if defined ( LOCATION_BLINDNODE )
  BlindNode_ProcessEvent
#endif
#if defined ( LOCATION_DONGLE )
  LocDongle_ProcessEvent
#endif
};

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
uint16 *tasksEvents;



第二段
void osalInitTasks( void )
{
  uint8 taskID = 0;

  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  /*osal_mem_alloc()为当前OSAL中的各任务分配存储空间(实际上是一个任务数组),
  函数返回指向任务缓冲区的指针,因此tasksEvents指向该任务数组(任务队列).注意
  tasksEvents和后面谈到的tasksArr[]里的顺序是一一对应的, tasksArr[ ]中的第i个
  事件处理函数对应于tasksEvents中的第i个任务的事件.*/
  
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
  /*osal_memset()把开辟的内存全部设置为0;sizeof( uint16 )是4个字节,即一个任务
    的长度(同样是uint16定义),乘以任务数量tasksCnt,即全部内存空间*/

#if defined( ZMAC_F8W )
  macTaskInit( taskID++ );
#endif
#if !defined( NONWK )
nwk_init( taskID++ );
#endif
  Hal_Init( taskID++ );
#if defined( MT_TASK )
  MT_TaskInit( taskID++ );
#endif
#if !defined( NONWK )
APS_Init( taskID++ );
  ZDApp_Init( taskID++ );//红色标出的这几个初始化任务是建立ZigBee网络所必须的
#endif
  SampleApp_Init( taskID++ );
#if defined ( LOCATION_REFNODE )
  RefNode_Init( taskID );
#endif
#if defined ( LOCATION_BLINDNODE )
  BlindNode_Init( taskID );
#endif
#if defined ( LOCATION_DONGLE )
  LocDongle_Init( taskID );//蓝色标出的这三个分别对应三种设备,根据Preprocessor里的定义来选择
#endif
}
     时间也不早了,这几天一直熬夜,今晚想早点睡了,后面的内容明天再开帖分享吧!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

1

查看全部评分

kennan 发表于 2011-10-28 08:49:35 | 显示全部楼层
小伙子做的不错,鼓励一下。不过提醒你啊,要是拿去申请国家大学生创新计划,做PPT演示的时候你要是显示温度18.87,你就挂了。呵呵。
rgmlfofiw 发表于 2011-10-28 10:06:01 | 显示全部楼层
好文章,期待下文!  顺便想问下wwh199169是如何区分不同节点(包括病床号和报警信息)的呢,通过哪个变量区分的呢?是网络地址吗?

PS:早点睡都两点半了,wwh199169还真是用功!
 楼主| wwh199169 发表于 2011-10-28 11:12:07 | 显示全部楼层
回复 2# kennan


    呵呵,前辈见笑了,那个不是体温哦,就是当时实验室里的温度,那个冷啊~~~
 楼主| wwh199169 发表于 2011-10-28 11:13:14 | 显示全部楼层
回复 3# rgmlfofiw


    呵呵,这个就是我这几天编程的重点和难点,后面我会贴出代码详细分析的!
rgmlfofiw 发表于 2011-10-28 11:27:33 | 显示全部楼层
回复 5# wwh199169


我刚测试了下我的定位网络中的几个参考节点网络地址。第一个加入网络的RefNode是0x0001,后面依次是0x143E,0x287B,0x3CB8。如果设备的网络地址不变的话,可以用网络地址区分终端节点。还有一点就是在接收到的IncomingMSG里没有64位长地址,所以暂时只能考虑用网络地址区分。我的定位程序现在也是只能定位一个移动节点,所以想请教下如何区分两个不同的节点。
 楼主| wwh199169 发表于 2011-10-29 00:16:50 | 显示全部楼层
回复 6# rgmlfofiw


        网络地址在同一个网络中也是唯一的,可以用来标定终端节点。你的为什么只能识别出一个呢?能麻烦把信息的数据格式和区分节点网络地址的那段代码贴出来吗,否则在下很难猜测问题出在哪儿呀,呵呵
pnm_0881 发表于 2011-10-29 20:15:31 | 显示全部楼层
我也在做无线医疗通信,能加QQ吗?519870184
rgmlfofiw 发表于 2011-10-29 22:57:34 | 显示全部楼层
回复 7# wwh199169

哈哈,我上面说的可能有歧义。我的意思是我现在只做了一个节点的定位,正在考虑做两个,BOSS给的最终任务是显示两个。所以想参考下你是如何区分出第二个节点的。
fengxu0217 发表于 2011-10-30 21:20:38 | 显示全部楼层
回复 9# rgmlfofiw



    根据设备的ID号来区分呗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表