z-stack 数据传输AF层application frame

本文深入探讨Zigbee协议中AF层的工作原理,包括数据收发、终端管理等核心功能。详细介绍了endpoint的概念及其管理方式,并解析了关键函数如afRegister()和AF_DataRequest()的作用及参数细节。

前面已经把z-stack里面的操作系统的基本原理搞懂了,紧接着的任务就是深入了解,不同设备之间是如何进行数据传输的。(个人习惯喜欢自顶而下的学习方式)

AF层是application通过空中向APS层传输数据的接口,它包括从通过aps层和NEW层空中传输数据的功能函数。它也能接收数据。AF层的功能:终端管理和数据收发。

在zigbee中每个设备看做一个节点(node),每个node有长地址和短地址,短地址被其他node用来传输数据,每个node可以有240个应用终点(endpoint,每个endpoint又要用地址来分开,device发送任务的时候。一个应用必须注册一个或多个endpoint来接收和发送数据。(来自ti的API的数据手册的资料)这说明z-stack数据传输的最小单位是endpoint。

下面看看AF层是如何对ENDPOINT进行管理的呢?

每个zigbee的endpoint有simple description,SimpleDescriptionFormat_t的结构体定义如下:

typedef struct
{
byte EndPoint;                               //endpoint的编号,也可以理解成地址1-240
uint16 AppProfId;                          //应用规范号,从zigbee联盟里面获得
uint16 AppDeviceId;                     //设备ID,这个endpoint的设备ID,也是从zigbee联盟里面获得。这里的device指的是CC2430节点后面接的设备,不是指CC2430本身。
byte AppDevVer:4;                  //设备描述的版本号,
byte Reserved:4; // AF_V1_SUPPORT uses for AppFlags:4.
byte AppNumInClusters;           //输入簇的数目
cId_t *pAppInClusterList;          //输入簇表的首地址,指针
byte AppNumOutClusters;        //输出簇的数目
cId_t *pAppOutClusterList;       //输出簇的首地址,指针
} SimpleDescriptionFormat_t;

endpoint描述结构:endPointDesc_t

typedef struct
{
byte endPoint;                                      //endpoint的编号,也可以理解成地址1-240(难以理解为什么要出现两个endpoint)byte *task_id;                                       // Pointer to location of the Application task ID.Task  ID pointer. When               a message is received, this task ID will be used to
SimpleDescriptionFormat_t  *simpleDesc;   //上面的结构体,这里是结构体嵌套结构体
afNetworkLatencyReq_t  latencyReq;           //充满没有潜伏时间的回复
} endPointDesc_t;

看了结构体,我们再看看功能函数

afRegister()用来注册一个新的endpoint到一个设备(device)上也就是(node)。

函数的原型(prototype)

afStatus_t afRegister( endPointDesc_t *epDesc );

epDesc是指向设备描述结构体的指针。

返回值是状态也就是Zsuccess 或者是Zfaules

接着还有一些endpoint管理的函数这里就不一一讲了。

终于到发送数据了。

发送数据的函数是 AF_DataRequest()
                           Call this function to send data.
              Prototype原型
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
                                             uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
                                             uint8 options, uint8 radius );参数超多
Parameter Details(参数详解:)
dstAddr – Destination address pointer. 目标地址指针
The address mode in this structure must be either: 它有四种形式

1。afAddrNotPresent tolet the reflector (source binding) figure out the destination address;

2。afAddrGroup to send to a group;

3。afAddrBroadcast to send a broadcast message;

4。afAddr16Bit to send directly (unicast) to a node.

srcEP – Endpoint Descriptor pointer of the sending endpoint.//发送设备的描述结构体的地址
cID – Cluster ID – the message’s cluster ID is like a message ID and is unique with in the profile.//簇ID
len – number of bytes in the buf field. The number of bytes to send.//发送数据buff的长度
buf – buffer pointer of data to send.//buff指针
transID – transaction sequence number pointer. This number will be incremented by this function if the message
is buffered to be sent.//序列数的指针
options – the options to send this message are to be OR’d into this field are:

AF_FRAGMENTED       0x01       Not to be used.
AF_ACK_REQUEST      0x10       APS Ack requested. This is an application level
                                                     acknowledgement – meaning that the destination
                                                     device will acknowledge the message. Only used on
                                                      messages send direct (unicast).//目标设备收到将会回复
AF_DISCV_ROUTE       0x20        Should always be included.//发现路由
AF_EN_SECURITY        0x40         Not needed.
AF_SKIP_ROUTING       0x80         Setting this option will cause the device to skip routing and try to send the message                                          directly End devices will not send the message to its parent first. Good for only                                                   direct (unicast) andbroadcast messages.//直接发送到目的设备,不发送到他的父节点

radius –Maximum number of hops 最大跳数

奇怪,怎么AF层里面只有发送的函数没有接收的函数。经过,鄙人不懈的努力,终于找到数据接收的函数。原来在ZDO层里面。

一个应用通过用ZDO_RegisterForZDOMsg()注册能从空中接收任何信息。
ZDO_RegisterForZDOMsg()
Call this function to request an over-the-air message. A copy of the message will be sent to a task in an OSAL
message. The task receiving the message can either parse the message themselves or call a ZDO Parser function to
parse the message. Only response messages have a ZDO Parser function.
After registering for a message, and the message is received (OTA), the message is sent to the application/task as a
ZDO_CB_MSG (OSAL Msg). The body of the message (zdoIncomingMsg_t – defined in ZDProfile.h) contains the
OTA message.

程序原型(prototype)

ZStatus_t ZDO_RegisterForZDOMsg( uint8 taskID, uint16 clusterID );
参数详解(Parameter Details)
taskID – the application’s task ID. This will be used to send the OSAL message.
clusterID – the over the air message’s clusterID that you would like to receive (example: NWK_addr_rsp).
These are defined in ZDProfile.h.
Return
ZStatus_t –status values defined in ZStatus_t in ZComDef.h,可惜在z-stack里面没有找到,而且,NEW层和MAC层没有给出源文件


/****************************************************************************** * @fn zb_ReceiveDataIndication * * @brief The zb_ReceiveDataIndication callback function is called * asynchronously by the ZigBee stack to notify the application * when data is received from a peer device. * * @param source - The short address of the peer device that sent the data * command - The commandId associated with the data * len - The number of bytes in the pData parameter * pData - The data sent by the peer device * * @return none */ /* void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData ) { //处理数据格式 gtwData.parent = BUILD_UINT16(pData[SENSOR_PARENT_OFFSET+ 1], pData[SENSOR_PARENT_OFFSET]); gtwData.source=source; gtwData.temp=*pData; gtwData.voltage=*(pData+1); // Flash LED 1 once to indicate data reception //接收到数据之后LED灯闪烁1次 HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF ); HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK ); // Send gateway report //发送网关数据 sendGtwReport(&gtwData); } */ void zb_ReceiveDataIndication(uint16 source, uint16 command, uint16 len, uint8 *pData) { gtwData.parent = BUILD_UINT16(pData[SENSOR_PARENT_OFFSET+1], pData[SENSOR_PARENT_OFFSET]); gtwData.source = source; gtwData.temp = *pData; gtwData.humidity = *(pData+1); gtwData.humandetected = *(pData+2); // Flash LED 1 once to indicate data reception HalLedSet(HAL_LED_1, HAL_LED_MODE_OFF); HalLedSet(HAL_LED_1, HAL_LED_MODE_BLINK); // 格式化显示数据 char displayBuf[50]; //sprintf(displayBuf, "22145131 22145137:%d,%d\r\n", gtwData.temp, gtwData.humidity); sprintf(displayBuf, "A0=%d A1=%d H0=%d\r\n", gtwData.temp, gtwData.humidity,gtwData.humandetected); HalUARTWrite(HAL_UART_PORT_0,(uint8 *)displayBuf, strlen(displayBuf)); sendGtwReport(&gtwData); } /****************************************************************************** * @fn uartRxCB * * @brief Callback function for UART * * @param port - UART port * event - UART event that caused callback * * @return none */ /*void uartRxCB(uint8 port, uint8 event) { uint8 pBuf[RX_BUF_LEN]; uint16 len; uint16 cmd; if (event != HAL_UART_TX_EMPTY) { len = HalUARTRead(HAL_UART_PORT_0, pBuf, RX_BUF_LEN); if (len > 0) { // 检查是否是PING请求 cmd = BUILD_UINT16(pBuf[SYS_PING_CMD_OFFSET+1], pBuf[SYS_PING_CMD_OFFSET]); if ((pBuf[FRAME_SOF_OFFSET] == CPT_SOP) && (cmd == SYS_PING_REQUEST)) { sysPingReqRcvd(); return; } // 处理字符串命令 if (strncmp((char *)pBuf, "0x131 ON", 8) == 0) { // LED ON命令 HalLedSet(HAL_LED_2, HAL_LED_MODE_BLINK); uint8 cmd[] = "305 ON"; zb_SendDataRequest(0xFFFF, SENSOR_REPORT_CMD_ID, sizeof(cmd)-1, cmd, 0, AF_ACK_REQUEST, 0); HalUARTWrite(HAL_UART_PORT_0, "22145131 22145137:LED ON ok\r\n", sizeof("22145131 22145137:LED ON ok\r\n")); } else if (strncmp((char *)pBuf, "0x131 OFF", 9) == 0) { // LED OFF命令 HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF); uint8 cmd[] = "305 OFF"; zb_SendDataRequest(0xFFFF, SENSOR_REPORT_CMD_ID, sizeof(cmd)-1, cmd, 0, AF_ACK_REQUEST, 0); HalUARTWrite(HAL_UART_PORT_0, "22145131 22145137:LED OFF命令已发送\r\n", sizeof("22145131 22145137:LED OFF命令已发送\r\n")); } else if (strncmp((char *)pBuf, "0x132", 5) == 0) { // 单次采集命令 uint8 cmd[] = "SINGLE_REPORT"; zb_SendDataRequest(0xFFFE, SENSOR_REPORT_CMD_ID, sizeof(cmd)-1, cmd, 0, AF_ACK_REQUEST, 0); HalUARTWrite(HAL_UART_PORT_0, "22145131 22145137:one collect ok\r\n", sizeof("22145131 22145137:one collect ok\r\n")); } else if (strncmp((char *)pBuf, "0x133", 5) == 0) { // 连续采集命令 continuousReporting = 1; reportCount = 0; uint8 cmd[] = "CONTINUOUS_REPORT"; zb_SendDataRequest(0xFFFE, SENSOR_REPORT_CMD_ID, sizeof(cmd)-1, cmd, 0, AF_ACK_REQUEST, 0); HalUARTWrite(HAL_UART_PORT_0, "22145131 22145137:many collect ok\r\n", sizeof("22145131 22145137:many collect ok\r\n")); } else if (strncmp((char *)pBuf, "0x134", 5) == 0) { // 停止采集命令 continuousReporting = 0; uint8 cmd[] = "STOP_REPORT"; zb_SendDataRequest(0xFFFE, SENSOR_REPORT_CMD_ID, sizeof(cmd)-1, cmd, 0, AF_ACK_REQUEST, 0); HalUARTWrite(HAL_UART_PORT_0, "22145131 22145137:stop collect ok\r\n", sizeof("22145131 22145137:stop collect ok\r\n")); } } } }*/ /*风扇传感器------------------------------------------------------------------ ------------------------------------------------------------------------*/ //转速显示函数 int count = 0; void Speed(void) { char Str[10]; sprintf(Str,"%d\r\n",count/3); Uart_Send_String(Str); //串口发送数据 count = 0; halWait(250); //延时 halWait(250); halWait(250); halWait(250); } /*T1初始化函数,配置为pwm模式 -------------------------------------------------------*/ void t1_init(void) { PERCFG = 0x03; //位置1 定时器1设置为位置1, P0SEL |= 0x20; //P0_5用作外设接口 P0DIR |= 0x20; P2DIR |= 0xC0; T1CNTL = 0x00; T1CNTH = 0x00; T1CCTL3 = 0x2C; //比较模式6 T1CC0L = 0xFF; //周期 T1CC0H = 0xEF; T1CC3L = 0xFF; //占空比 T1CC3H = 0x6F; T1CTL = 0x0E; //模模式 } /*中断服务子程序 -------------------------------------------------------*/ #pragma vector = P0INT_VECTOR __interrupt void P0_ISR(void) { EA = 0; //关中断 if((P0IFG & 0x02 ) >0 ) //按键中断 ,p0_1 { halWait(200); //去抖动 P0IFG &= ~0x02; //P0.1中断标志清0 T1CC3H = T1CC3H + 0x20; //减小占空比 T1CC3L = 0xFF; } if((P0IFG & 0x10 ) >0 ) //按键中断 ,p0_4 { halWait(200); //去抖动 P0IFG &= ~0x10; //P0.4中断标志清0 T1CC3H = T1CC3H - 0x20; //增大占空比 T1CC3L = 0xFF; } if((P0IFG & 0x40 ) >0 ) // p0_6 { P0IFG &= ~0x40; //P0.5中断标志清0 count++; } P0IF = 0; //P0中断标志清0 EA = 1; //开中断 } /*延时函数 -------------------------------------------------------*/ void halWait(unsigned char wait) { unsigned long largeWait; if(wait == 0) {return;} largeWait = ((unsigned short) (wait << 7)); largeWait += 114*wait; largeWait = (largeWait >> CLKSPD); while(largeWait--); return; } //节能模式 void SetLowPowerMode(void) { // 1. 降低传感器采样频率 osal_stop_timerEx(sapi_TaskID, SENSOR_SAMPLE_EVT); osal_start_timerEx(sapi_TaskID, SENSOR_SAMPLE_EVT, 5000); // 5秒采样 // 2. 关闭非必要外设 HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF); // 关闭D6 // 3. 发送节能通知 Uart_Send_String("SYSTEM: Entering Low Power Mode"); }
最新发布
07-03
<think>好的,我需要分析用户提供的代码,并回答相关问题。首先,用户给出的代码是关于ZigBee协调器处理接收到的数据、UART回调函数、风扇传感器控制以及低功耗模式设置的。用户可能希望了解这些代码的功能、实现方式以及优化点。 首先看zb_ReceiveDataIndication函数。这个函数处理从终端节点接收的数据,包括温度、湿度和人体检测信息。数据被解析后,通过LED闪烁提示接收,并通过UART发送网关报告。可能的问题涉及如何解析数据、如何处理多传感器信息以及如何触发发送报告。 接下来是UART回调函数uartRxCB,处理串口输入的命令,比如控制LED开关、启动或停止数据采集。这里可能需要解释命令解析逻辑、如何发送ZigBee命令以及如何处理不同指令。 然后是风扇传感器部分,包括PWM初始化、中断服务程序和转速显示函数。这部分代码负责调节风扇转速,并通过按键调整占空比。问题可能涉及PWM配置、中断处理以及如何计算转速。 最后,SetLowPowerMode函数用于进入节能模式,降低采样频率和关闭非必要外设。可能的问题包括节能模式的具体措施、如何触发以及对系统的影响。用户可能希望了解代码中的关键函数如何工作,如何优化功耗,或者如何调试特定功能。需要确保回答准确,并指出潜在的改进点,例如错误处理、代码结构优化等。</think>### 代码解析与优化建议 #### 1. **ZigBee数据接收处理函数 `zb_ReceiveDataIndication`** - **功能解析** 该函数接收来自ZigBee终端节点的传感器数据(温度、湿度、人体存在状态),并执行以下操作: 1. 解析数据结构:从`pData`中提取父节点地址、源地址、温度、湿度及人体检测标志 2. LED闪烁提示:通过HalLedSet实现单次闪烁反馈 3. 数据格式化显示:通过UART输出类似"A0=25 A1=60 H0=1"的字符串 4. 调用`sendGtwReport`上传网关数据 - **优化建议** - **健壮性增强**:增加数据校验逻辑(如CRC校验)防止错误解析 - **资源管理**:避免频繁使用`sprintf`,改用预分配缓冲区减少内存碎片 - **扩展性改进**:将传感器类型编码为枚举常量而非硬编码偏移量 #### 2. **UART命令解析函数 `uartRxCB`** - **关键逻辑** 实现串口指令解析与响应: - PING协议处理:识别0xFFFF广播地址的握手请求 - 设备控制指令: - `0x131 ON/OFF` 控制LED状态 - `0x132` 单次数据采集 - `0x133/134` 连续/停止采集模式切换 - ZigBee指令封装:通过`zb_SendDataRequest`下发控制命令 - **潜在改进点** - **协议分**:引入状态机解析协议帧头、长度、校验码 - **命令扩展**:支持JSON格式参数传递(如调节PWM占空比范围) - **错误处理**:添加超时重传机制应对无线通信丢包 #### 3. **风扇控制模块** - **PWM配置分析** ```c T1CCTL3 = 0x2C; // 比较模式6,输出PWM波形 T1CC0L/H = 0xEFFF; // 周期计算:(0xEFFF+1)*时钟周期 ≈ 4kHz T1CC3L/H = 0x6FFF; // 初始占空比:(0x6FFF/0xEFFF)*100% ≈ 46.9% ``` - **中断服务优化** - **按键防抖**:当前200ms延时可能阻塞其他中断,建议改用定时器扫描 - **转速计算**:`count/3`假设每3次中断为1转,需根据霍尔传感器特性验证 #### 4. **低功耗模式实现** - **节能策略分析** 1. 采样间隔调整:从默认值改为5秒 2. 外设关闭:关闭LED指示灯 3. 状态通知:通过UART发送提示 - **深度优化建议** - **时钟管理**:切换到32kHz晶振降低系统时钟频率 - **外设关断**:禁用未使用的ADC模块和定时器 - **唤醒机制**:配置GPIO中断实现人体检测触发唤醒 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值