下面我们要继续第一部分的工作,由于之前我们只是完成了一个设备(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中选择不同的设备时,到底有哪些具体的不同。 言归正传,“说话”首先要明确要跟谁说?是对某个人,一组人,所有人,还是自言自语?在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代表全部控制,等等。。。 [子问题]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?是谁在按什么标准分的? 呃。。。我还不清楚,估计得专门有个专题能讲得清楚了~~~ |
|