调试报告
问题描述
在 Modbus 主站回读数据时,eRcvState一直保持在STATE_M_RX_IDLE状态,导致无法正常接收数据。经过检查,发现问题出在主循环的轮询调用上。
BOOLxMBMasterRTUReceiveFSM(void){BOOL xTaskNeedSwitch=FALSE;UCHAR ucByte;assert_param((eSndState==STATE_M_TX_IDLE)||(eSndState==STATE_M_TX_XFWR));/* Always read the character. */(void)xMBMasterPortSerialGetByte((CHAR*)&ucByte);switch(eRcvState){/* If we have received a character in the init state we have to * wait until the frame is finished. */caseSTATE_M_RX_INIT:vMBMasterPortTimersT35Enable();break;/* In the error state we wait until all characters in the * damaged frame are transmitted. */caseSTATE_M_RX_ERROR:vMBMasterPortTimersT35Enable();break;/* In the idle state we wait for a new character. If a character * is received the t1.5 and t3.5 timers are started and the * receiver is in the state STATE_RX_RECEIVCE and disable early * the timer of respond timeout . */caseSTATE_M_RX_IDLE:/* In time of respond timeout,the receiver receive a frame. * Disable timer of respond timeout and change the transmiter state to idle. */vMBMasterPortTimersDisable();eSndState=STATE_M_TX_IDLE;usMasterRcvBufferPos=0;ucMasterRTURcvBuf[usMasterRcvBufferPos++]=ucByte;eRcvState=STATE_M_RX_RCV;/* Enable t3.5 timers. */vMBMasterPortTimersT35Enable();break;/* We are currently receiving a frame. Reset the timer after * every character received. If more than the maximum possible * number of bytes in a modbus frame is received the frame is * ignored. */caseSTATE_M_RX_RCV:if(usMasterRcvBufferPos<MB_SER_PDU_SIZE_MAX){ucMasterRTURcvBuf[usMasterRcvBufferPos++]=ucByte;}else{eRcvState=STATE_M_RX_ERROR;}vMBMasterPortTimersT35Enable();break;}returnxTaskNeedSwitch;}在这个函数中,eRcvState 一直等于0x01 STATE_M_RX_IDLE,一次 case STATE_M_RX_RCV的分支都没执行
原因分析
原始代码中,Modbus 主站的轮询函数 eMBMasterPoll() 在主循环中调用频率过高,导致状态机无法正常切换。具体代码如下:
while(1){// 主机轮询eMBMasterPoll();// 非阻塞方式轮询,避免 HAL_Delay 占用 CPU。if(HAL_GetTick()-lastPollTime>=1000){test(MB_USER_READ_CALLBACK);lastPollTime=HAL_GetTick();// 延时1秒}HAL_Delay(MB_POLL_CYCLE_MS);// 延时1秒}解决方案
将主循环中的轮询调用调整为合理的频率,确保状态机能够正常切换。调整后的代码如下:
while(1){MX_LWIP_Process();// Modbus 从机轮询eMBPoll();// 主站轮询,调整频率以避免回读问题if(HAL_GetTick()-lastPollTime1>=200){eMBMasterPoll();lastPollTime1=HAL_GetTick();// 延时200ms}// 非阻塞方式轮询,避免 HAL_Delay 占用 CPU。if(HAL_GetTick()-lastPollTime>=1000){test(MB_USER_READ_CALLBACK);lastPollTime=HAL_GetTick();// 延时1秒}}总结
通过调整主循环中 Modbus 主站轮询的调用频率,解决了eRcvState一直保持在STATE_M_RX_IDLE的问题,确保了主站能够正常接收数据。此调试过程强调了合理设置轮询频率的重要性,避免因调用过于频繁导致状态机无法正常运作。