|
本帖最后由 wwh199169 于 2011-10-28 11:14 编辑
今天下午终于结束了本项目的一个重要阶段——中期检查答辩。从答辩的过程来看,评委老师们对本项目完成的进度和质量还是很满意的,特别是得知我所学并非电气专业,而是机械专业之后,更是夸奖有加,呵呵···。与参加答辩的其它项目组比起来,我的项目还是很有希望通过国创(国家大学生创新实践计划)项目的审核,成功申请到那个一万元资金的项目! 当然,来这里发帖不是为了炫耀而来的,只是表达一下如释重负,付出有得之后的喜悦心情。为了这次答辩,更为了能成功申请到国创项目,我这些天可以说是茶饭不思、废寝忘食的在学习、编程、调试,之前还因为遇到阻碍在论坛里发了两篇求助贴。其实后来更是不断的遇到问题,但经过数日夜以继昼的鏖战,都一一克服了,以至于今天能自信的走上讲台进行我的项目展示,想来实在感慨良多···
感慨完了,想到自己开发经历的艰辛也许也是许多和我一样的ZigBee初学者们的感受,就发出此帖,以自己的项目为例,尽量详细的写出开发的过程、遇到的问题以及解决的方法。希望能给初学者们一点借鉴,也希望高手们能给我更高层次的指导,在下不胜感激!
好了,前奏就啰嗦到这里,下面进入正题...
首先,向大家简单介绍一下我的项目结构。本项目是一个基于ZigBee技术的无线医疗监视网络(呵呵,网上好像有不少类似的文章),硬件部分组成如下图所示:
图中上面外挂了传感器和蜂鸣器电路的是两个是温度采集节点(属于终端节点设备),下面带LCD模块的是数据收集显示节点(属于协调器设备)。模块中主要的元器件见图中注释说明。
系统的工作过程如下图所示:
过程并不复杂,就是测温节点将传感器采集到的数据无线发送给显示节点处理、显示。这只是原来的预期功能,未能够申请国创项目,我经过这几天的努力,加入了如下功能:
1,温度数值超出上下限时,显示节点能自动报警;
2,病人能够通过采集节点上的按键发出求助信息,显示节点能够显示提示并报警;
3,显示节点在报警过程中可通过按键取消报警,表示正在处理报警事件;
4,加入与计算机的串口通信功能,即通过串口调试助手软件在计算机上显示测温节点传送来的64位地址和温度数值;
以上各功能弱是指针对一个节点都很容易实现,但是,如果不止一个,那么对不同测温节点发出的报警信息要区分对待,不能一概取消,否则当两个测温节点同时出现报警时,可能会有一个被误取消而得不到处理,那样的话病人就有麻烦了。而这部分正是我这几天的工作重点和难点,为此我在程序中尝试了许多方法,最终才找到一个勉强可行的方法。这种方法原则上可行,但实际运行中也有问题,后面会详细说明,希望高手们看到后能给与在下指点!
下面从头开始说起,很久很久以前,有一个······呵呵,开玩笑的。 本项目是基于TI给出的一个无线测温例程改编的,程序结构如下图:
可以看出,该工程是由LocDongle(显示节点程序)和RefNode(测温节点程序)两个子工程组成的,分别下载到对应的节点模块中即可各自运行。这里需要指出,其实测温节点和显示节点模块除了分别外挂了传感器和液晶模块外,其他硬件是完全一样的,所谓的“分别下载”是指在两个子工程的Project--Options--C/C++ Compiler--Preprocessor的difine symbols命令行里分别添加LOCATION_DONGLE和LOCATION_RefNode定义,另外,显示模块由于需要液晶功能,还要加入LCD_SUPPORTED,后面加入串口功能还要添加HAL_UART_BIG_TX_BUF=1定义。如下图所示:
众所周知,添加自己的应用应该在APP子层进行。从上面的协议栈结构图中可以看到,APP层下面包含了3个.c文件,分别是LocationProfile.c、SampleApp.c和Sensor_18B20.c。
LocationProfile.c文件下面包含了许多.h文件,仔细看其中还有两个.c文件:LocDongle.c和RefNode.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
查看全部评分
-
|