Other Parts Discussed in Thread: Z-STACK
As a novice user of the CC2530, I recently encountered a problem that I couldn't solve; Firstly, I carried out the work based on three terminals and one coordinator(ZStack-2.5.1). The aim was to achieve voltage acquisition at a rate of 30Hz or higher (at the terminals), and then send the data to the coordinator in a point-to-point manner. The coordinator would then print out the data via the serial port.
Currently, the solution I am adopting is that the coordinator sends AD acquisition commands to the three terminals in a cyclic manner through point-to-point polling; after receiving the data returned by the current terminal, it then sends an AD acquisition command to the next terminal to have it upload the data; if I want to achieve a sampling rate of 30Hz, then the time for one polling cycle (polling the three terminals) by the coordinator needs to be 30ms; however, at present, the time for the coordinator to poll all three terminals is approximately 100ms (as shown in the figure1).
I have tried many methods, including modifying the parameters in files such as f8wCoord.cfg, f8wConfig.cfg and f8wEndev.cfg(as shown in the figure2,3,4). Eventually, I could only increase the sampling rate to around 10Hz.Below, I have provided the core code for implementing this function.
I really need everyone's help to solve this problem. If you could offer me some suggestions, I would be extremely grateful.
/********************************************************************* * INCLUDES */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "AF.h" #include "OnBoard.h" #include "OSAL_Tasks.h" #include "SampleApp.h" #include "ZDApp.h" #include "ZDObject.h" #include "ZDProfile.h" #include "hal_drivers.h" #include "hal_key.h" #if defined ( LCD_SUPPORTED ) #include "hal_lcd.h" #endif #include "hal_led.h" #include "hal_uart.h" #include "hal_adc.h" #include "OSAL_PwrMgr.h" /********************************************************************* * MACROS */ /********************************************************************* * CONSTANTS */ #if !defined( SAMPLE_APP_PORT ) #define SAMPLE_APP_PORT 0 #endif #if !defined( SAMPLE_APP_BAUD ) #define SAMPLE_APP_BAUD HAL_UART_BR_115200 #endif // When the Rx buf space is less than this threshold, invoke the Rx callback. #if !defined( SAMPLE_APP_THRESH ) #define SAMPLE_APP_THRESH 64 #endif #if !defined( SAMPLE_APP_RX_SZ ) #define SAMPLE_APP_RX_SZ 128 #endif #if !defined( SAMPLE_APP_TX_SZ ) #define SAMPLE_APP_TX_SZ 128 #endif // Millisecs of idle time after a byte is received before invoking Rx callback. #if !defined( SAMPLE_APP_IDLE ) #define SAMPLE_APP_IDLE 6 #endif // Loopback Rx bytes to Tx for throughput testing. #if !defined( SAMPLE_APP_LOOPBACK ) #define SAMPLE_APP_LOOPBACK FALSE #endif // This is the max byte count per OTA message. #if !defined( SAMPLE_APP_TX_MAX ) #define SAMPLE_APP_TX_MAX 80 #endif #define SAMPLE_APP_RSP_CNT 4 #define ADC_CHANNEL_COUNT 5 // 采集5路AD const uint8 adcChannels[ADC_CHANNEL_COUNT] = { HAL_ADC_CHANNEL_0, // P0_0 HAL_ADC_CHANNEL_4, // P0_4 HAL_ADC_CHANNEL_5, // P0_5 HAL_ADC_CHANNEL_6, // P0_6 HAL_ADC_CHANNEL_7 // P0_7 }; // This list should be filled with Application specific Cluster IDs. const cId_t SampleApp_ClusterList[SAMPLE_MAX_CLUSTERS] = { SAMPLEAPP_P2P_CLUSTERID, SAMPLEAPP_FLASH_CLUSTERID, SAMPLEAPP_ADDR_CLUSTERID }; const SimpleDescriptionFormat_t SampleApp_SimpleDesc = { SAMPLEAPP_ENDPOINT, // int Endpoint; SAMPLEAPP_PROFID, // uint16 AppProfId[2]; SAMPLEAPP_DEVICEID, // uint16 AppDeviceId[2]; SAMPLEAPP_DEVICE_VERSION, // int AppDevVer:4; SAMPLEAPP_FLAGS, // int AppFlags:4; SAMPLE_MAX_CLUSTERS, // byte AppNumInClusters; (cId_t *)SampleApp_ClusterList, // byte *pAppInClusterList; SAMPLE_MAX_CLUSTERS, // byte AppNumOutClusters; (cId_t *)SampleApp_ClusterList // byte *pAppOutClusterList; }; endPointDesc_t SampleApp_epDesc = { SAMPLEAPP_ENDPOINT, &SampleApp_TaskID, (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc, noLatencyReqs }; /********************************************************************* * TYPEDEFS */ /********************************************************************* * GLOBAL VARIABLES */ devStates_t SampleApp_NwkState; uint8 SampleApp_TaskID; // Task ID for internal task/event processing. uint8 SampleApp_TransID; // This is the unique message ID (counter) /********************************************************************* * EXTERNAL VARIABLES */ /********************************************************************* * EXTERNAL FUNCTIONS */ /********************************************************************* * LOCAL VARIABLES */ static uint8 SampleApp_MsgID; afAddrType_t SampleApp_Periodic_DstAddr; //广播 afAddrType_t SampleApp_Flash_DstAddr; //组播 afAddrType_t SampleApp_P2P_DstAddr; //点播 static afAddrType_t SampleApp_TxAddr; static uint8 SampleApp_TxSeq; static uint8 SampleApp_TxBuf[SAMPLE_APP_TX_MAX+1]; static uint8 SampleApp_TxLen; static afAddrType_t SampleApp_RxAddr; static uint8 SampleApp_RxSeq; static uint8 SampleApp_RspBuf[SAMPLE_APP_RSP_CNT]; //重要,定时终端ID //范围:1~MAX_DEVICE,不同的终端或者协调器,要修改此值 uint8 deviceId = 1; DEVICES mDevice[MAX_DEVICE]; /********************************************************************* * LOCAL FUNCTIONS */ static void SampleApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt ); void SampleApp_CallBack(uint8 port, uint8 event); static void SampleApp_Send_ADC_Message( void ); static void floatToStr(float vol, char *result, int maxLen); static void reverse(char *str, int len); static void intToStr(int num, char *str, int *index); void SendMsgToShortAddr(uint8* buff, uint8 len, uint16 addr); void SendShortAddrToCoor(); void SendAckToCoordinator(void); #define SAMPLEAPP_CMD_TRIGGER_ADC 0x01 // 触发ADC采集的指令 #define SAMPLEAPP_COORDINATOR 0x0000 // 协调器短地址 #define MAX_CONNECTED_DEVICES 10 // 最大连接设备数 #define CMD_SEND_INTERVAL 5 // 指令发送间隔(ms) #define RESPONSE_TIMEOUT_MS 1000 // 响应超时时间(ms) static uint8 connectedDevices[MAX_CONNECTED_DEVICES]; // 存储已连接设备ID static uint8 deviceCount = 0; // 已连接设备数量 static uint8 currentDeviceIndex = 0; // 当前轮询的设备索引 static uint8 isCoordinator = FALSE; // 是否为协调器 //static uint8 ADsuccess = 0; // 是否为协调器 static uint8 isWaitingForResponse = FALSE; // 新增:是否在等待终端响应 static uint16 currentTargetAddr = 0; // 当前发送目标地址 /********************************************************************* * @fn SampleApp_Init * * @brief This is called during OSAL tasks' initialization. * * @param task_id - the Task ID assigned by OSAL. * * @return none */ void SampleApp_Init( uint8 task_id ) { halUARTCfg_t uartConfig; SampleApp_TaskID = task_id; SampleApp_RxSeq = 0xC3; SampleApp_NwkState = DEV_INIT; SampleApp_TransID = 0; MT_UartInit(); //串口初始化 MT_UartRegisterTaskID(task_id); //注册串口任务 afRegister( (endPointDesc_t *)&SampleApp_epDesc ); RegisterForKeys( task_id ); osal_pwrmgr_device(PWRMGR_ALWAYS_ON); for(uint8 i=0; i<MAX_DEVICE; i++) { mDevice[i].id=i+1;//1~MAX_DEVICE mDevice[i].shortAddr=0;//短地址清0 } // 初始化已连接设备列表 memset(connectedDevices, 0, sizeof(connectedDevices)); deviceCount = 0; currentDeviceIndex = 0; SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//广播 SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF; // Setup for the flash command's destination address - Group 1 SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;//组播 SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP; SampleApp_P2P_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; //点播 SampleApp_P2P_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_P2P_DstAddr.addr.shortAddr = 0x0000; //发给协调器 } /********************************************************************* * @fn SampleApp_ProcessEvent * * @brief Generic Application Task event processor. * * @param task_id - The OSAL assigned task ID. * @param events - Bit map of events to process. * * @return Event flags of all unprocessed events. */ UINT16 SampleApp_ProcessEvent( uint8 task_id, UINT16 events ) { (void)task_id; // Intentionally unreferenced parameter if ( events & SYS_EVENT_MSG ) { afIncomingMSGPacket_t *MSGpkt; while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID )) ) { switch ( MSGpkt->hdr.event ) { case AF_INCOMING_MSG_CMD: SampleApp_ProcessMSGCmd( MSGpkt ); break; case ZDO_STATE_CHANGE: SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); if (SampleApp_NwkState == DEV_ZB_COORD) { // 标识当前设备为协调器 isCoordinator = TRUE; HalUARTWrite(0, "Coordinator started\r\n", 20); // 启动设备轮询定时器 osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_POLL_DEVICES_EVT, CMD_SEND_INTERVAL ); } else if ((SampleApp_NwkState == DEV_ROUTER) || (SampleApp_NwkState == DEV_END_DEVICE)) { // 终端设备入网后发送自身ID给协调器 SendShortAddrToCoor(); osal_pwrmgr_device(PWRMGR_ALWAYS_ON); } else { } break; default: break; } osal_msg_deallocate( (uint8 *)MSGpkt ); } return ( events ^ SYS_EVENT_MSG ); } // 协调器轮询设备事件 if ( events & SAMPLEAPP_POLL_DEVICES_EVT && isCoordinator ) { if (deviceCount > 0 && !isWaitingForResponse) //if (deviceCount > 0 ) { // 发送ADC采集指令给当前设备 uint8 cmd = SAMPLEAPP_CMD_TRIGGER_ADC; uint16 targetAddr = 0; //ADsuccess = 0; // 查找当前设备的短地址 for(uint8 i=0; i<MAX_DEVICE; i++) { if(mDevice[i].id == connectedDevices[currentDeviceIndex]) { targetAddr = mDevice[i].shortAddr; break; } } // 发送指令 if(targetAddr != 0) { char log[32]; char send[] = "sended\r\n"; sprintf(log, "Sending ADC cmd to device %d\r\n", connectedDevices[currentDeviceIndex]); HalUARTWrite(0, log, strlen(log)); SendMsgToShortAddr(&cmd, 1, targetAddr); //HalUARTWrite(0, send, strlen(send)); isWaitingForResponse = TRUE; // 标记为等待响应状态 currentTargetAddr = targetAddr; // 保存当前目标地址 // 启动响应超时定时器 osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_RESPONSE_TIMEOUT_EVT, RESPONSE_TIMEOUT_MS); } // 更新索引,循环轮询 currentDeviceIndex = (currentDeviceIndex + 1) % deviceCount; } // 重新启动定时器 osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_POLL_DEVICES_EVT, CMD_SEND_INTERVAL ); return (events ^ SAMPLEAPP_POLL_DEVICES_EVT); } // 触发下一个设备轮询 //if (events & SAMPLEAPP_NEXT_DEVICE_EVT && isCoordinator) //{ // 切换到下一个设备 //currentDeviceIndex = (currentDeviceIndex + 1) % deviceCount; // 触发下一次轮询 //osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_POLL_DEVICES_EVT, 5); // 短延迟后轮询下一个 //return (events ^ SAMPLEAPP_NEXT_DEVICE_EVT); //} // 响应超时事件处理 if (events & SAMPLEAPP_RESPONSE_TIMEOUT_EVT && isCoordinator) { if (isWaitingForResponse) { // 超时处理 char log[64]; sprintf(log, "Response timeout from device at address 0x%X\r\n", currentTargetAddr); HalUARTWrite(0, log, strlen(log)); // 重置等待状态,继续轮询 isWaitingForResponse = FALSE; currentTargetAddr = 0; // 继续轮询下一个设备 currentDeviceIndex = (currentDeviceIndex + 1) % deviceCount; } return (events ^ SAMPLEAPP_RESPONSE_TIMEOUT_EVT); } return ( 0 ); // Discard unknown events. } /********************************************************************* * @fn SerialApp_ProcessMSGCmd * * @brief Data message processor callback. This function processes * any incoming data - probably from other devices. Based * on the cluster ID, perform the intended action. * * @param pkt - pointer to the incoming message packet * * @return TRUE if the 'pkt' parameter is being used and will be freed later, * FALSE otherwise. */ void SampleApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt ) { uint8 buff[64]={0}; char addrBuf[6] = {0}; switch ( pkt->clusterId ) { case SAMPLEAPP_P2P_CLUSTERID: { // 协调器接收终端发送的ADC数据 if(isCoordinator) { uint16 srcShortAddr = pkt->srcAddr.addr.shortAddr; sprintf(addrBuf, "0x%X", srcShortAddr); HalUARTWrite(0, "Received data from ", 18); HalUARTWrite(0, addrBuf, osal_strlen(addrBuf)); HalUARTWrite(0, ": ", 2); HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); HalUARTWrite(0, "\r\n", 2); // 取消超时定时器 osal_stop_timerEx(SampleApp_TaskID, SAMPLEAPP_RESPONSE_TIMEOUT_EVT); isWaitingForResponse = FALSE; currentTargetAddr = 0; //osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_NEXT_DEVICE_EVT, 5); // 短延迟后处理下一个 } } break; case SAMPLEAPP_FLASH_CLUSTERID: // 终端接收协调器的ADC采集指令 if(pkt->cmd.Data[0] == SAMPLEAPP_CMD_TRIGGER_ADC) { SendAckToCoordinator(); // 执行ADC采集并发送给协调器 SampleApp_Send_ADC_Message(); } break; case SAMPLEAPP_ADDR_CLUSTERID: // 协调器处理终端发送的ID和地址信息 if(isCoordinator) { uint8 deviceId = pkt->cmd.Data[0]; uint16 shortAddr = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2]); // 存储设备信息 for(uint8 i=0; i<MAX_DEVICE; i++) { if(mDevice[i].id == deviceId) { mDevice[i].shortAddr = shortAddr; // 如果是新设备,添加到已连接设备列表 bool isNewDevice = TRUE; for(uint8 j=0; j<deviceCount; j++) { if(connectedDevices[j] == deviceId) { isNewDevice = FALSE; break; } } if(isNewDevice && deviceCount < MAX_CONNECTED_DEVICES) { connectedDevices[deviceCount++] = deviceId; char log[32]; sprintf(log, "New device connected: %d\r\n", deviceId); HalUARTWrite(0, log, strlen(log)); } break; } } } break; // 新增:处理终端发送的确认消息 case SAMPLEAPP_ACK_CLUSTERID: if(isCoordinator) { uint16 srcShortAddr = pkt->srcAddr.addr.shortAddr; sprintf(addrBuf, "0x%X", srcShortAddr); HalUARTWrite(0, "Received ACK from ", 17); HalUARTWrite(0, addrBuf, osal_strlen(addrBuf)); HalUARTWrite(0, "\r\n", 2); } break; default: break; } } /********************************************************************* * @fn SampleApp_CallBack * * @brief Send data OTA. * * @param port - UART port. * @param event - the UART port event flag. * * @return none */ void SampleApp_CallBack(uint8 port, uint8 event) { (void)port; if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) && #if SAMPLE_APP_LOOPBACK (SampleApp_TxLen < SAMPLE_APP_TX_MAX)) #else !SampleApp_TxLen) #endif { SampleApp_TxLen += HalUARTRead(SAMPLE_APP_PORT, SampleApp_TxBuf+SampleApp_TxLen+1, SAMPLE_APP_TX_MAX-SampleApp_TxLen); } } /********************************************************************* *********************************************************************/ /********************************************************************* * @fn SampleApp_Send_ADC_Message * * @brief point to point. * * @param none * * @return none */ void SampleApp_Send_ADC_Message( void ) { byte str_adc[64]={0}; //char *str_adc = "V:"; float voltages[ADC_CHANNEL_COUNT] = {0.0}; // 存储各通道电压 uint16 adcValues[ADC_CHANNEL_COUNT] = {0}; // 存储各通道原始值 byte len=19; //osal_memset(str_adc, ' ', 63); for (uint8 i = 0; i < ADC_CHANNEL_COUNT; i++) { // 读取ADC值(参考电压使用AVDD,即3.3V) char str_vol[20] = {0}; adcValues[i] = HalAdcRead(adcChannels[i], HAL_ADC_RESOLUTION_14); if(adcValues[i]>=8192) { sprintf(str_adc,"error\r\n"); } else {// 计算电压(14位ADC,最大值8192) voltages[i] = (float)(adcValues[i] * 3.3)/ 8192.0; floatToStr(voltages[i], str_vol, sizeof(str_vol)); strcat(str_vol,"\r\n"); strcat(str_adc, str_vol); //str_adc = concatDynamic(str_adc, str_vol); } } //for (uint8_t i = 0; i < ADC_CHANNEL_COUNT; i++) //{ // 格式化当前通道数据并追加到字符串 // 格式:"Vx:1.234 "(x为通道号,保留3位小数) //strLen += sprintf(&str_adc[strLen], "V%d:%.3f ", // (adcChannels[i] + 1), // 通道号从1开始显示 // voltages[i]); //} // len=osal_strlen(str_adc);//计算长度 // 确保数据发送给协调器 SampleApp_P2P_DstAddr.addr.shortAddr = SAMPLEAPP_COORDINATOR; if ( AF_DataRequest( &SampleApp_P2P_DstAddr, &SampleApp_epDesc, SAMPLEAPP_P2P_CLUSTERID, len, str_adc, &SampleApp_MsgID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { // free(str_adc); } else { //free(str_adc); // Error occurred in request to send. } } void SendShortAddrToCoor() { char buff[5]={0}; afAddrType_t DstAddr; uint16 addr=NLME_GetShortAddr(); //点播,协调器的短地址为0 DstAddr.addrMode = (afAddrMode_t)Addr16Bit; DstAddr.endPoint = SAMPLEAPP_ENDPOINT; DstAddr.addr.shortAddr = 0x0; //填发送的数据 buff[0]=deviceId;//第一个字节,终端编号 buff[1]=LO_UINT16(addr);//第二个字节,终端短地址低字节 buff[2]=HI_UINT16(addr);//第三个字节,终端短地址高字节 // //发送 if ( AF_DataRequest( &DstAddr, &SampleApp_epDesc, SAMPLEAPP_ADDR_CLUSTERID, 3, buff, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { // Error occurred in request to send. } } void SendAckToCoordinator(void) { uint8 ackMsg[] = "Received"; // 确认消息内容 afAddrType_t dstAddr; dstAddr.addrMode = Addr16Bit; dstAddr.endPoint = SAMPLEAPP_ENDPOINT; dstAddr.addr.shortAddr = SAMPLEAPP_COORDINATOR; // 目标为协调器 if ( AF_DataRequest(&dstAddr, &SampleApp_epDesc, SAMPLEAPP_ACK_CLUSTERID, sizeof(ackMsg) - 1, // 不包含字符串结束符 ackMsg, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS) == afStatus_SUCCESS ) { } else { // Error occurred in request to send. } } const char* afStatusStr[] = { "afStatus_SUCCESS", // 0: 成功 "afStatus_FAILED", // 1: 失败 "afStatus_INVALID_PARAMETER",// 2: 参数无效 "afStatus_NO_ROUTE", // 3: 无路由 "afStatus_NO_RESOURCES", // 4: 资源不足 "afStatus_NOT_SUPPORTED", // 5: 不支持 "afStatus_TIMEOUT" // 6: 超时(根据实际枚举扩展) // ... 其他状态码 }; void SendMsgToShortAddr(uint8* buff, uint8 len, uint16 addr) { afAddrType_t DstAddr; SampleApp_TransID++; //点播 DstAddr.addrMode = (afAddrMode_t)Addr16Bit; DstAddr.endPoint = SAMPLEAPP_ENDPOINT; DstAddr.addr.shortAddr = addr; afStatus_t status = AF_DataRequest( &DstAddr, &SampleApp_epDesc, SAMPLEAPP_FLASH_CLUSTERID, len, buff, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ); // 准备打印缓冲区(存储状态码和描述) char uartBuf[64]; uint16 bufLen; //发送 if ( status == afStatus_SUCCESS ) { char send[] = "sended\r\n"; HalUARTWrite(0, send, strlen(send)); } else { if (status < sizeof(afStatusStr)/sizeof(afStatusStr[0])) { sprintf(uartBuf, "AF_DataRequest status: %d (%s)\r\n", status, afStatusStr[status]); } else { sprintf(uartBuf, "AF_DataRequest status: %d (Unknown)\r\n", status); } HalUARTWrite(0, (uint8*)uartBuf, strlen(uartBuf)); } } // 共用体 union FloatUnion { float f; unsigned char bytes[4]; // float占4字节 }; // 反转字符串 void reverse(char *str, int len) { int i = 0, j = len - 1; char temp; while (i < j) { temp = str[i]; str[i] = str[j]; str[j] = temp; i++; j--; } } // 整数转换 void intToStr(int num, char *str, int *index) { int i = 0; // 处理0的特殊情况 if (num == 0) { str[(*index)++] = '0'; return; } // 提取每一位数字 while (num != 0) { int rem = num % 10; str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; num = num / 10; } // 反转得到正确顺序 reverse(str + *index, i); *index += i; } // 浮点数转为字符串 void floatToStr(float vol, char *result, int maxLen) { union FloatUnion u; u.f = vol; int index = 0; // 检查缓冲区是否足够 if (maxLen < 10) { result[0] = '\0'; return; } // 处理符号位 if (vol < 0) { result[index++] = '-'; vol = -vol; // 转为正数处理 } // 分离整数部分和小数部分 int intPart = (int)vol; float fracPart = vol - intPart; // 转换整数部分 intToStr(intPart, result, &index); // 添加小数点 result[index++] = '.'; // 转换小数部分(保留3位) for (int i = 0; i < 3; i++) { fracPart *= 10; int fracDigit = (int)fracPart; result[index++] = fracDigit + '0'; fracPart -= fracDigit; } // 添加字符串结束符 result[index] = '\0'; }