奥特曼Zigbee读书日记(四)-- 设备“对话”专题(2)

shir   2010-6-21 16:30 楼主
原贴地址:http://www.feibit.com/bbs/viewthread.php?tid=86&;extra=page%3D1


  心理学专家告诉我们,一个贴子不能写得太长,否则会让读者有疲劳感。。。(背景音:哪个专家说的?--自己百度去,肯定不是奥特曼~~~)按照专家的指点,我们把设备“对话”专题,又分了个part 2,就这样,还不知道能不能把这部分说得清楚呢,汗自己一个。。。

  在第一部分中,我们只是做了下基础的工作,从“壹”开始,搭建了一个属于自己的工作平台,虽然和主题有点相去甚远,但我认为这对我们后面的理解很有必要,这能帮助我们排除一些非重要因素的干扰,把复杂的事情变得简单--这也是我们网站的宗旨所在!

[注:本文源自www.feibit.com--“飞比”无线单片机论坛,为尊重劳动者成果,如需转载请保留此行]

  下面我们要继续第一部分的工作,由于之前我们只是完成了一个设备(Coordinator)的项目搭建,对一个最小化的Zigbee网络,在笔记一中已经做过介绍,至少要一个Coordinator和一个End Device,不过为了方便以后的应用,在这里我们把Coordinator、Router和End Device这三种设备一起添加到项目中。具体的做法如下:

在“project ==> edit configurations”中,分别建立“Coordinator”“Router”及“EndDevice”三种设备的项目设置,注意在"based on configuration"下拉框中要选择之前做过配置的“debug”,然后删除“debug”与“release”。

同时,有几个地方是“Router”及“EndDevice”与“Coordinator”设置有所差异,我们必须要按照“GenericApp”的设置手动修改的
(1)C/C++ compiler ==> preprocessor ==> defined symbols
(2)C/C++ compiler ==>Extra Options
(3)linker ==>Extra Options

这三点对我们理解到整个项目的结构也是非常有帮助的。因为这样我们就知道了,在workspace中选择不同的设备时,到底有哪些具体的不同。

至此,我们就有了具有三种设备的一个基础项目,终于可以开始让机器“说话”啦。。。是不是“铺垫”铺得太长了,不知道还有没有人有耐心看到这里,对我的写作思路有异议的同学,欢迎批评啊~~~
-- 2010.5.9 by outman from Feibit

言归正传,“说话”首先要明确要跟谁说?是对某个人,一组人,所有人,还是自言自语?在Zigbee协议中,有五种类型的地址:
  AddrNotPresent = 0,
  AddrGroup = 1,
  Addr16Bit = 2,
  Addr64Bit = 3,
  AddrBroadcast = 15
其中,64位的地址是一个“全地址”,就像你的手机在国外打要拨008613XXXXXXXXX,此地址全球唯一,64位的地址理论上可以支持2^64=1.8*10^19个设备,8个0是一个亿,那就是1800亿亿,天哪,这是多少啊~~~~~

16位地址相当于我们的集团短号了(一个Coordinator下的唯一地址),而当地址类型为Group与Broadcast时,分别对应一组设备和所有设备。

作为第一个“对话”的例子,我们从最简单的广播式开始--老张和老王都在大声讲话,所有人都听得到。然后,在此基础上,再探讨一下如何进行“私聊”。

明确了“跟谁说”和“说什么”的问题之后,从大脑到神经系统再到肌肉组织等等一系列的复杂的协调动作,已经由Zigbee组织给我们规定好,并且由TI公司给我们完成了,虽然很多同学可能对这个更感兴趣,但介于目前的水平,我们还是先来看看“嘴”在哪里,和怎么用吧?

afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                           uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
                           uint8 options, uint8 radius )

这个就是我们要用的“嘴”--把它研究清楚了,我们就有了学习说话的基础了。

这里面的数据结构有点复杂,不过还是让我们来一条条地逐一研究吧。

在这之前,先说几个在这个复杂的数据表中几个比较重要的概念。

[子问题]10.3 Short address, Profile ID, Endpoint, Cluster ID都代表什么意思?区别在哪里?

要说明这个问题,举个“智能家居”里的“无线开关”的例子,可能会更直观点



在这个例子里,左边是两个开关(可能装在走廊里),两个开关共用一个Zigbee节点“Z1”(相当于开发板上的两个按键,这点应该不难理解吧),他们一起控制右边的三个灯泡(也是接在同一个节点上的--“Z2”)。Z1的key1控制Z2的lamp1,而key2则控制Z2的lamp2与lamp3。
OK,回到这个问题
1. short address,16位的短地址,由Coordinator/Router来分配(注:这里留个伏笔,地址分配的问题后面会专门做个专题来讲)
2. Profile ID, 这个是由Zigbee组织来分配的应用ID号,比如无线开关用0x0001,智能电表用ox0002,万用遥控器用0x0003等等。在这个例子里,这个ID号是专门用来做电灯开关的。为什么要这么做呢?这里就体现了“标准”的意义,不同厂家功能的设备,由于有了这个ID就能互相间使用了,正泰的开关一样可以控制Philips的灯。。。
3. Endpoint,这个名字看起来容易误解,以为是设备的序号了,其实不然。在这个例子中,Z1有key1/key2两个Endpoint,分别做不同的事情。其对应了同一个"application"中的0-240个不同的“子应用”,其中0号endpoint是用"ZDO"预留的,不能占用。
4. Cluster ID,这个怎么叫呢?叫信息簇ID吧。。。我的理解是,“这是个哪类的信息”,发送端和接收端一定要对应,但是具体这个“类”怎么分,是我们可以自己决定的。比如说这个例子,我可以这样定:Cluster ID=1代表开关一次,Cluster ID=2代表连续闪烁。。。或者定义Cluster ID=1代表点对点控制,而Cluster ID=2代表全部控制,等等。。。
-- 2010.5.12 00:24 by outman from Feibit

[子问题]10.4 什么是Beacon?

Beacon我们可以简单地理解为一个“指挥棒”,在有beacon的传输中,发送与接收设备是按照一个固定的节奏来进行数据传输的。

好了,现在我们就把要控制这个“嘴”的所有参数列出来,把最重要的一个个来说。这次就不上图了,换个方式。

注:{}中的数据为本例的“广播”式传输的设置值
/*********************************************************************/
*dstAddr ........................目标地址
                shortAddr ................................... 16位短地址{0xFFFF--代表“广播”}
                addrMode .................................... 地址类型,上文已做过阐述{AddrBroadcast}
                endPoint  ..................................... 目标“EndPoint”序号,其意义见上文{20}

/*********************************************************************/
*srcEP ...........................源“EndPoint”描述
                endPoint  .................................... 源“EndPoint”序号{20}
                *task_id ..................................... 所要调用的任务ID{BeginApp_TaskID}
                *simpleDesc
                               EndPoint ..................... 源“EndPoint”序号(为什么又有一个?--等搞明白了再补充){20}
                               AppProfId ................... profile ID号,其意义见上文{0x0F08}
                               AppDeviceId ............... 16位的设备ID号{0x0001}
                               AppDevVer ................. 设备版本号{0}
                               Reserved .................... AppFlags(此上三项,具体用处以后再补充){0}
                               AppNumInClusters ....... 输入Cluster的总数目,Cluster的意义见上文{1}
                               *pAppInClusterList ...... 输入Cluster的列表{BeginApp_ClusterList}
                               AppNumOutClusters ..... 输出Cluster的总数目{1}
                               *pAppOutClusterList .... 输出Cluster的列表{BeginApp_ClusterList}
                latencyReq ................................. Beacon的使用情况,本例中没有用到。{noLatencyReqs}

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

cID ........................................................... 本次要发送的Cluster ID号{1}

len ............................................................ 本次要发送的数据长度{发送字符串长度}  

*buf .......................................................... 本次要发送的数据的存放地址{字符串地址}

*transID .................................................... 数据传输“排队”号{0}

options ...................................................... 发送选项,如是否要ACK,加密,是否跳过路由等等
                                                                    {AF_DISCV_ROUTE}

radius ........................................................ 最大“折射”次数/“多跳”级别{10}

/*********************************************************************/
由于本例中,每个节点都只对应一个endpoint,所以只要保证设为同一个值,可以去不理会。重点设置红色部分项目。

至此,我们基本认识了这个“嘴”的每一根控制神经,下面就要正式说话了~~~

不记得在OSAL中如何读取按键,如何响应事件的同学请复习下“日记(二)”中的内容,这里只简单地把最重要的代码贴出来。

1. 按键 Hal_key.c  HalKeyPoll函数,增加
      if (!(P0 & HAL_KEY_SW_1))
      {
         ksave0 |= HAL_KEY_SW_1;
      }
以读取按键IO口状态,判断按键,当然在成熟的产品中需要做一个“消抖”算法

2. 响应按键,发送数据
BeginApp.c 的KEY_CHANGE函数中:

#ifdef IAMZHANG
  char say_hello[] = "LAO ZHANG: lao wang, chi le mei?";
#else
  char say_hello[] = "LAO WANG: lao zhang, chi le mei?";
#endif

  BeginApp_SendP2PMessage(say_hello);

此函数将调用AF_DataRequest,其参数按上述设置即可

3. 接收数据并回复
BeginApp.c  的接受信息函数BeginApp_MessageMSGCB中添加

rec_msg = pkt->cmd.Data;

//reply after 2 seconds
       osal_start_timerEx( BeginApp_TaskID,
                                BEGINAPP_SEND_REPLY_MSG_EVT,
                                BEGINAPP_SEND_MSG_TIMEOUT );

4. 另外,添加一个LED闪烁的函数BeginApp_BlinkLED与串口发送数据函数UART_Send_String,在发送或接收时进行必要的显示。

此处只进行重点部分的讲解,需要源文件的同学请跟帖,如有必要,则会以附件形式共享出来。

好了,终于舒了一口气,剩下最后一个小问题了~
[子问题]10.5 如何知道当前设备的短地址?它是怎么分配的?

试下在程序的某个位置调用一下NLME_GetShortAddr这个函数,看看不同的设备会返回什么值?这个就是为节点分配的short address,有点像路由器给电脑分配IP的感觉。知道了这个,我们做一个小实验,把前面“老张”和“老王”的聊天变成“私聊”。

其实只需要在上面的设置参数里,改变一下这两个就可以了

                shortAddr ................................... {Coordinator:0 /EndDevice:0x796F}
                addrMode .................................... {Addr16Bit}

这两个设备地址,我们都只是通过实验的方法找到的,但究竟why?是谁在按什么标准分的?
呃。。。我还不清楚,估计得专门有个专题能讲得清楚了~~~
-- 2010.5.12 by outman from Feibit

回复评论 (1)

学习中!希望能有更多的资料分享
点赞  2011-6-22 08:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复