1、FreeModbus笔记docFreeModbus 笔记Modbus -RTU 是基于 485 总线基础上一个主从协议,主站主动发起通信,从站接收主站的消息并响应主站的指令。这里主要探讨FreeModbus中的RTU从站协议的实现。从站的串口每次接收一个字节数据,并产生串口中断(中断打开)个个字节如何组成一个 Modbus 的数据帧呢?,那么串口中传过来的一这是通过一个重要的参数T3.5 来进行判断的。T3.5 就是串口传递3.5 个字符的时间,这个时间和波特率相关,不同波特率下,T3.5 时间不等。3.5 个字符时间区分不同的帧, 即接收到的两个字符之间时间间隔小于 3.5 个字符时间时认为
2、是同一个帧的, 如果间隔大于 3.5 个字符时间则认为是不同帧的,在一般的串口通信中,发送 1 个字符需要: 1 位起始位, 8 位数据位, 1 位校验位(可无 ),1 位停止位 ,总共 1+8+1+1 = 11 位,3.5个字符时间就是 3.5 * 11 = 38.5位,假如波特率是 9600,那么传输 1 位的时间是 1000/9600 = 0.10416667(ms) ,这样, 3.5 个字符时间就大约是 4 ms ,即定时器需要的中断时间串行口数据帧D0 D1 D2 D3 D4 D5 D6 D7 Par 停止位起始位1个字节 1个字节 1个字节 1个字节 1个字节tT3.5TT3.5T
3、T3.5Modbus数据帧也就是串口在静默了T3.5 秒以后收到的第一个字节作为一个Modbus数据帧的首字节,然后收到的字符间隔只要不超出T3.5 的时间间隔, 都作为这一帧数据来处理。当串口在T3.5没有收到数据时,则认为当前主站Modbus发送完了一个数据帧。可以进行后面的Modbus数据帧处理了。再收到的数据回作为下一个Modbus数据帧的首字节。接收一个字节, 是由串口中断来进行完成的, 判断是否超时是由定时器中断来完成的。 因此以上看是很清楚的一个协议流程需要串口和定时器配合共同完成。所以在看 RTU 实现协议时一定要记住这点。从站主要是接收,被动响应,所以先分析接收机的状态:接收
4、状态机接收状态包含以下几种:STATE_RX_INIT, /*! 接收机在初始态 */STATE_RX_IDLE, /*! 接收机在空闲态 */STATE_RX_RCV, /*! 接收到一帧数据 */STATE_RX_ERROR /*!19200是usTimerT35_50us=35xMBPortTimersInit()否初始化是否成功是状态码=MB_EPORTERR返回状态码至此, Modbus 的初始化工作完成。串口中断被打开,超时定时器配置好。eMBEnable()该函数指针指向eMBRTUStarteMBRTUStarteMBEnable()eStatus 状态码 =无错误初始化时的状
5、态 否eMBState =STATE_DISABLED是pvMBFrameStartCur()eMBState =STATE_ENABLED返回 eStatus状态码eMBRTUStart ()eStatus =MB_EILLSTATE置接收状态位初始化状态置端口为接收状态开端口定时功能eRcvState =STATE_RX_INIT;vMBPortSerialEnable( TRUE, FALSE );在端口使能函数中vMBPortTimersEnable( );设置 485的收发状态返回当串口接收到数据时发生中断,由串口中断程序处理 USART1_IRQHandler()USART1_IR
6、QHandler()是接收事件?否调用 prvvUARTRxISR()处理是发送准备好事件?否调用调用 prvvUARTTxReadyISR()处理pxMBFrameCBByteReceived();处理在 RTU 模式,该函数指针指向xMBRTUReceiveFSM ()调用实际调用的是返回pxMBFrameCBTransmitterEmpty();xMBRTUTransmitFSM()处理在 RTU 模式,该函数指针指向xMBRTUTransmitFSM()实际调用的是 xMBRTUTransmitFSM()实际是调用函数:USART_ReceiveData(USART1);STATE_R
7、X_INITvMBPortTimersEnable( );xMBRTUReceiveFSM()确认当前发送为空闲状态调用xMBPortSerialGetByte()接收一个字节数据判断当前接收状态eRcvStateSTATE_RX_ERROR STATE_RX_IDLE STATE_RX_RCVvMBPortTimersEnable( );接收第一个字节,并将状将当前接收字节加入到接收缓冲态置为 STATE_RX_RCV区,当接收字节数大于最大帧同时,启动 T3.5定时器长,将放弃该帧( eRcvState =STATE_RX_ERROR )每收到一个字节复位 T3.5 定时器返回xMBRTU
8、TransmitFSM()确认当前接收为空闲状态判断当前接收状态eSndStateSTATE_TX_IDLEvMBPortSerialEnable( TRUE, FALSE );由发变收产生一个发送完毕事件xNeedPoll = xMBPortEventPost(EV_FRAME_SENT );vMBPortSerialEnable( TRUE, FALSE );由发变收STATE_TX_XMIT否发送缓冲区不为零是发送当前字节xMBPortSerialPutByte( ( CHAR)*pucSndBufferCur )实际是调用函数:USART_SendData(USART1, ucByte
9、);更新缓冲器指针和大小返回TIM2_IRQHandler中断函数调用调用TIMERExpiredISR( void )调用pxMBPortCBTimerExpired()RTU 模式下,该函数指针指向xMBRTUTimerT35Expired()判断当前接收状态eRcvStateSTATE_RX_INITSTATE_RX_ERRORSTATE_RX_RCVDefault置返回值为错误态产生一个准备好事件xMBPortEventPost(产生一个接收一帧事件确认各参数正常?EV_READY); xMBPortEventPost(EV_FRAME_RECEIVED )vMBPortTimersD
10、isable( );eRcvState = STATE_RX_IDLE;返回Modbus 的主查询函数 eMBPoll()eMBPoll()状态码 =无错误否ModBus是否使能 协议栈出错,并返回错误码是否EV_READY获取当前 MB_EVENT 成功是判断当前 EVENTEV_FRAME_SENTEV_FRAME_RECEIVED EV_EXECUTEpeMBFrameReceiveCur(/ 从接收缓冲取出功能码&ucRcvAddress,&ucMBFrame, &usLengthBreak;);/查询接收结果,并将结依次查询各个功能码Break;果保存到 ucMBFrame否否查询接收结果无错误本机支持该功能码是是判断当前数据帧是本机否调用该功能码处理函数数据或是广播数据是派送一个执行事件否xMBPortEventPost(地址不等于广播地址EV_EXECUTE );是按照 MB 协议,发送应答帧返回
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1