freemodbus源码笔记
Posted super尚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了freemodbus源码笔记相关的知识,希望对你有一定的参考价值。
首先会一直在eMBPoll中轮询,查看是否有事件发生,如果有的话就用switch语句来跳转到相应的事件。
EV_READY是在协议栈初始化后xMBRTUTimerT35Expired函数发出来的,表示startup完成
如果是接收数据帧事件那么会跳转到下图的代码:
该段代码通过peMBFrameReceiveCur函数,调用eMBRTUReceive,在eMBRTUReceive函数中首先查看帧大小是否符合要求,然后进行CRC校验。此函数的原型是:
eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
USHORT * pusLength )
第一个参数是为了返回帧中的地址,也就是帧中第一个字节;第二个传入的参数以后要当做数组来使用,所以用了指针的指针类型;第三个参数表示PDU的长度,也就是帧中除去功能码字节和CRC校验字节后的长度。
其中最大数据长度为256字节,最短为4字节。从机地址范围为1~247
然后判断是否是发往本机的数据,看地址是否一样,或者是否是广播地址。通过判断则通过xMBPortEventPost()事件通知函数post一个执行事件。
然后跳转到EV_EXECUTE事件,进行应用层的处理,如下图:
关于定时器:
eMBRTUInit函数中的变量usTimerT35_50us代表如果50us进行一次Tick的话,T35超时的Tick次数。这个公式很重要:
usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
函数xMBPortTimersInit要以变量usTimerT35_50us为传入参数,对T35超时定时器进行设置。
如果T35定时器超时并产生中断,则要调用xMBRTUTimerT35Expired函数,其内部是一个状态机转换的switch,根据当前接收状态来通过xMBPortEventPost发送事件通知,然后关闭T35定时器,并将当前接收状态设置为STATE_RX_IDLE
若使用波特率为9600,则 t3.5= ( 11 * 3.5 ) / 9600 = 4.01 ms。 不能使用8位模式的Timer,因为11.0590MHz主频在最大48分频后,最长的超时时间为1.11ms,不能满足T35的超时要求
每次进入中断服务程序间隔时间为
((1+TIM_Prescaler )/72M)(1+TIM_Period )=((1+7199)/72M)(1+9999)=1秒
协议栈以及定时器初始化T35第一次超时—>eMBPoll STATE_RX_IDLE—>收到数据中断
—>prvvUARTRxISR—>pxMBFrameCBByteReceived—>xMBRTUReceiveFSM接收数据
—> STATE_RX_RCV—>T35超时—> eMBPollEV_FRAME_RECEIVED(peMBFrameReceiveCur->eMBRTUReceive)提取完整数据帧—> eMBPoll case EV_EXECUTE:xFuncHandlers[i].pxHandler(eMBRegInputCB)对接收的数据进行处理—> peMBFrameSendCur—>eMBRTUSend(&STATE_RX_IDLE)—>STATE_TX_XMIT
串口发送完成中断—> prvvUARTTxReadyISR—> FSMpxMBFrameCBTransmitterEmpty—>xMBRTUTransmitFSM(& STATE_TX_XMIT)—>xMBPortSerialPutByte—>发送数据。
20210805 在更一下注意的地方:
在串口调试器收到的数据最后一个字节的CRC校验会丢失,通过在发送的时候进行延时算是临时解决了,但是还是没搞清楚真正的原因,通过查阅资料发现应该是中断处理的地方的问题。
因为freemodbus通过串口中断的方式接收和发送数据。采用这种做法可以节省程序等待的时间,并且也充分使用CPU的资源。串口中断接收毋庸置疑,在中断服务函数中把数据保存在数组中,以便稍后处理。但是串口发送中断使用哪种形式?串口发送中断至少有两种方式,第一种,数据寄存器空中断,只要数据寄存器为空并且中断屏蔽位置位,那么中断就会发生;第二种,发送完成中断,若数据寄存器的数据发送完成并且中断屏蔽位置位,那么中断也会发送。我非常建议各位使用串口发送完成中断。freemodbus多使用RS485通信中,从机要么接收要么发送,多数情况下从机处于接收状态,要有数据发送时才进入发送状态。进入发送状态时,数据被一个一个字节发送出去,当最后一个字节被发送出去之后,从机再次进入接收状态。如果使用发送寄存器为空中断,还需要使用其他的方法才可以判断最后一个字节的数据是否发送完成。如果使用数据寄存器为空中断,那么将很有可能丢失最后一个字节。
以上是关于freemodbus源码笔记的主要内容,如果未能解决你的问题,请参考以下文章
STM32F103移植FreeModbus主机协议实现modbus主机