需要测试代码的可以留下邮箱,或者关注微信公众号 小白技术栈 后台回复【cc2530串口回调函数】获取。
CC2530使用MT层实现串口读操作,在MT_UART.c文件定义回调函数:
#if defined (ZTOOL_P1) || defined (ZTOOL_P2) uartConfig.callBackFunc = MT_UartProcessZToolData;在串口接收回调函数MT_UartProcessZToolData()中,Zstack采用状态机接收的方式对串口接收数据进行处理,看似比较复杂,但其实这样接收数据还能校验数据的准确性,而且还有osal_msg_send( App_TaskID, (byte *)pMsg )发送机制,处理数据比较方便。
其接收数据格式为 0xFE + 数据长度(仅是data的长度)+ 命令字段 + data[] + 校验和
代码注释如下:
/*************************************************************************************************** * @fn MT_UartProcessZToolData * * @brief | SOP | Data Length | CMD | Data | FCS | * | 1 | 1 | 2 | 0-Len | 1 | * * Parses the data and determine either is SPI or just simply serial data * then send the data to correct place (MT or APP) * * @param port - UART port * event - Event that causes the callback * * * @return None ***************************************************************************************************/ void MT_UartProcessZToolData ( uint8 port, uint8 event ) { uint8 ch; uint8 bytesInRxBuffer; (void)event; // Intentionally unreferenced parameter while (Hal_UART_RxBufLen(port)) //判断是否有数据 { HalUARTRead (port, &ch, 1); //每次接收一个数据 switch (state) { case SOP_STATE: //初始状态state = 0,判断帧头是否为SOP_STATE(0xFE) if (ch == MT_UART_SOF) state = LEN_STATE; //若帧头正确,状态机状态改为LEN_STATE break; case LEN_STATE: //接收第二字节时,进入LEN_STATE LEN_Token = ch; //将第二字节(传输数据data[]的长度)赋值给LEN_Token tempDataLen = 0; //初始化临时数据计数器tempDataLen为零 /* Allocate memory for the data */ pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) + MT_RPC_FRAME_HDR_SZ + LEN_Token ); //分配存放消息的空间,由3字节(1字节数据长度位+2字节CMD字段)+ data[]长度 if (pMsg) //若有消息接收 { /* Fill up what we can */ pMsg->hdr.event = CMD_SERIAL_MSG; //事件ID,供应用层查询使用 pMsg->msg = (uint8*)(pMsg+1); //加1的目的是为了分配存放数据末尾的1字节校验和 pMsg->msg[MT_RPC_POS_LEN] = LEN_Token; //将数据长度存放到msg[0] state = CMD_STATE1; //修改状态机状态为CMD_STATE1 } else //无消息则回到状态机起始状态 { state = SOP_STATE; return; } break; case CMD_STATE1: pMsg->msg[MT_RPC_POS_CMD0] = ch; //第三字节为命令字段一 state = CMD_STATE2; break; case CMD_STATE2: pMsg->msg[MT_RPC_POS_CMD1] = ch; //第四字节为命令字段二 /* If there is no data, skip to FCS state */ if (LEN_Token) //如果有数据接收,则状态机改为DATA_STATE { state = DATA_STATE; } else //如果无数据接收,则状态机改为FCS_STATE校验模式 { state = FCS_STATE; } break; case DATA_STATE: /* Fill in the buffer the first byte of the data */ pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch; //开始存放data[] /* Check number of bytes left in the Rx buffer */ bytesInRxBuffer = Hal_UART_RxBufLen(port); /* If the remain of the data is there, read them all, otherwise, just read enough */ if (bytesInRxBuffer <= LEN_Token - tempDataLen) //如果缓冲区剩余字节数不大于分配 的空间,则将剩余字节全部存放到msg { HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], bytesInRxBuffer); tempDataLen += bytesInRxBuffer; } else //根据剩余空间大小存放数据 { HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], LEN_Token - tempDataLen); tempDataLen += (LEN_Token - tempDataLen); } /* If number of bytes read is equal to data length, time to move on to FCS */ if ( tempDataLen == LEN_Token ) state = FCS_STATE; //修改状态为校验状态 break; case FCS_STATE: FSC_Token = ch; //将最后一个字节(校验和)赋值给FSC_Token /* Make sure it's correct */ if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token)) //校验成功,则将消息发送出去 { osal_msg_send( App_TaskID, (byte *)pMsg ); //将消息发送到应用层 } else { /* deallocate the msg */ osal_msg_deallocate ( (uint8 *)pMsg ); //此函数用于释放消息缓冲区。此函数由任务(或处理元素)在处理完接收到的消息后调用 } /* Reset the state, send or discard the buffers at this point */ state = SOP_STATE; //恢复到初始化状态,等待下次接收 break; default: break; } } }然后在SampleApp.c文件uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )函数状态机中添加如下:
mtOSALSerialData_t *UartMsg; . . . case CMD_SERIAL_MSG: UartMsg = (mtOSALSerialData_t *)MSGpkt; memcpy(uartRecvBuf, UartMsg->msg, UartMsg->msg[0] + 3); SampleApp_Send_P2P_Message(); memset(uartRecvBuf, 0, UartMsg->msg[0] + 3);将串口接收到的消息发送到协调器,通过协调器打印出来。
cc2530串口接收数据由stm32发送测试,其测试代码为:
uint8_t MT_UartCalcFCS( uint8_t *msg_ptr, uint8_t len ) { uint8_t x; uint8_t xorResult; xorResult = 0; for ( x = 0; x < len; x++, msg_ptr++ ) xorResult = xorResult ^ *msg_ptr; return ( xorResult ); } /********************************************************************* * @fn led_entry * * @brief Led run. * * @param parameter - none * * @return none */ void led_entry(void *parameter) { uint8_t led_state = LED_ON; uint8_t test_buf[13] = {0xFE, 0x08, 0x03, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00}; test_buf[11] = 0xff; while(1) { LED(led_state); led_state = ~led_state; test_buf[12] = MT_UartCalcFCS((uint8_t*)&test_buf[1], 11); HAL_UART_Transmit(&huart1, test_buf, 13, 0xFF); test_buf[4]++; rt_thread_mdelay(1000); } }
