🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[success] 导师视频讲解:[去听课](https://www.bilibili.com/video/BV1k34y1D7Vz/) >[success] **技术支持说明:** >**1**.一般以自主学习为主 > **2**.可到官方问答社区中提问:[**去提问**](https://bbs.csdn.net/forums/zigbee) > **3**.工程师**会尽快**解答社区问题,但他们是一线开发,【**难以保证**】解答时效,解答辛苦,感谢理解! <br/> 本节课将以实验的方式讲解如何使用ZCL读写命令API,实验设备包含一个协调器和一个终端,内容是协调器向终端发送写命令,然后在再发送读命令,最后比较一下写入的信息和读取到的信息是否一致。 <br/> ## **定义读写事件** 在zcl\_samplesw.h文件中分别定义一个读命令事件和写命令事件,代码如下: ![](https://img.kancloud.cn/ce/a1/cea12db058c27a1edc2566b25ca88fa4_444x266.png =300x) ### 协调器接收到终端设备广播(Annce)的信息后,启动一个读命令事件,代码如下: ![](https://img.kancloud.cn/fb/a0/fba09952b2d08500d45569eaf85fcb9f_832x660.png =600x) ### 在zcl\_samplews.c文件的zclSample\_event\_loop事件处理函数中,可以找到读命令事件的处理代码,如下: ~~~ // if ( events & SAMPLEAPP_READ_EVT )//如是读命令事件 { zclSampleSw_ReadTest();//读命令事件处理函数 //启动一个写命令事件 osal_start_timerEx(zclSampleSw_TaskID, SAMPLEAPP_WRITE_EVT, SAMPLEAPP_WRITE_PERIOD); return ( events ^ SAMPLEAPP_READ_EVT ); } ~~~ ### 读命令事件处理函数zclSampleSw\_ReadTest的代码定义如下: ### ``` 1.static void zclSampleSw_ReadTest(void)   2.{   3.    afAddrType_t destAddr;   4.    zclReadCmd_t *readCmd;   5.    static uint8 txID = 0;   6.       7.    destAddr.endPoint = SAMPLESW_ENDPOINT;   8.    destAddr.addrMode = afAddr16Bit;   9.    destAddr.addr.shortAddr = zclSampleSw_TestAddr;   10.  //申请一个动态内存 11.  readCmd = (zclReadCmd_t *)osal_mem_alloc(sizeof(zclReadCmd_t) +    sizeof(uint16)); 12. 13.   if(readCmd == NULL)//判断是否成功申请到内存 14.      return;   15.    readCmd->numAttr = 1;//待读取的属性数量为1 16.    readCmd->attrID[0] = ATTRID_ON_OFF_SWITCH_ACTIONS;//待读取的属性ID 17.       18.    zcl_SendRead(SAMPLESW_ENDPOINT,   19.                 &destAddr,   20.                 ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG,//Cluster ID   21.                 readCmd,   22.                 ZCL_FRAME_CLIENT_SERVER_DIR,//通信方向是由客户端到服务器端 23.                 TRUE, 24.                 txID++);   25. osal_mem_free(readCmd);//释放内存 26.} ``` ### 在读命令处理中代码中还启动一个写命令事件,在读命令事件处理代码的下方可以找到写命令事件的处理代码,如下: ~~~ if ( events & SAMPLEAPP_WRITE_EVT )//如果是写命令事件 { zclSampleSw_WriteTest();//写命令处理函数 osal_start_timerEx(zclSampleSw_TaskID,//启动一个读命令事件 SAMPLEAPP_READ_EVT, SAMPLEAPP_READ_PERIOD); return ( events ^ SAMPLEAPP_WRITE_EVT ); } ~~~ ### 写命令事件处理函数zclSampleSw\_WriteTest的代码定义如下: ### ``` static void zclSampleSw_WriteTest(void)   {       afAddrType_t destAddr;       zclWriteCmd_t *writeCmd;       static uint8 txID = 0;              destAddr.endPoint = SAMPLESW_ENDPOINT;       destAddr.addrMode = afAddr16Bit;       destAddr.addr.shortAddr = zclSampleSw_TestAddr;            writeCmd=(zclWriteCmd_t *)osal_mem_alloc(sizeof(zclWriteCmd_t) +    sizeof(zclWriteRec_t));//申请一个动态内存     if(writeCmd == NULL)//判断动态内存是否申请成功      return;          writeCmd->attrList[0].attrData=(uint8*)osal_mem_alloc(sizeof(uint8));//申请一个动态内存     if(writeCmd->attrList[0].attrData == NULL)//判断动态内存是否申请成功        return;              writeCmd->numAttr = 1;//待写入的属性数量     writeCmd->attrList[0].attrID =ATTRID_ON_OFF_SWITCH_ACTIONS;待写入的属性的ID     writeCmd->attrList[0].dataType = ZCL_DATATYPE_ENUM8;//属性值的类型     *(writeCmd->attrList[0].attrData) = txID;//属性值     HalLcdWriteStringValue("Write:", txID, 10, 4);            zcl_SendWrite(SAMPLESW_ENDPOINT,   &destAddr,   ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG,//Cluster ID  writeCmd,   ZCL_FRAME_CLIENT_SERVER_DIR,//通信方向是由客户端到服务器端 TRUE, txID++);   osal_mem_free(writeCmd->attrList[0].attrData); // 释放内存 osal_mem_free(writeCmd); // 释放内存 } ``` <br/> ## **读响应处理** 在客户端中处理从服务器端中读取到的信息,即编写读命令响应信息处理函数,代码如下: ~~~ #ifdef ZCL_READ /********************************************************************* * @fn zclSampleSw_ProcessInReadRspCmd * * @brief 读响应处理函数 * * @param pInMsg - 待处理的消息 * * @return */ static uint8 zclSampleSw_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg ) { zclReadRspCmd_t *readRspCmd; uint8 i; readRspCmd = (zclReadRspCmd_t *)pInMsg->attrCmd; for (i = 0; i < readRspCmd->numAttr; i++)//readRspCmd->numAttr为属性的数量 { if( pInMsg->clusterId == ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG &&//如果该消息是关于指定的Cluster readRspCmd->attrList[i].attrID == ATTRID_ON_OFF_SWITCH_ACTIONS )//如果该属性的ID是指定的属性ID { uint8 val; val = *(readRspCmd->attrList[i].data);//读取属性值 HalLcdWriteStringValue("Read:", val, 10, 4);//显示信息到屏幕中 } } return TRUE; } #endif // ZCL_READ ~~~ <br/> ## **仿真调试** * 分别编译协调器和终端(路由器)工程,然后分别下载到两个开发板中。 * 终端(路由器)设备加入到ZigBee网络中后,可以看到协调器屏幕显示如下提示信息。 ![](https://img.kancloud.cn/ce/b3/ceb377d8d26438ac846ff8c4f8142007_246x216.png =200x) ![](https://img.kancloud.cn/3e/78/3e7827774bb3d26a3395aef27994d785_264x242.png =200x) 可以观察到读和写的数据是一样的。 <br/> <br/> ## **项目定制** * 如需项目定制开发,可扫码添加项目经理好友(注明“**项目定制**”) * 定制范围:**NB-IoT**、**CATn(4G)**、**WiFi**、**ZigBee**、**BLE Mesh**以及**STM32**、**嵌入式Linux**等IoT技术方案 * 善学坊官网:[www.sxf-iot.com](https://www.sxf-iot.com/) ![](https://img.kancloud.cn/ca/73/ca739f92cab220a3059378642e3bd502_430x430.png =200x) * 非项目定制**勿扰**,此处**非**技术支持