Modbus 协议报文间隔需要大于3.5个字符。
Freemodbus需要配合一个定时器使用,这是因为它是通过定时器超时来判断Modbus传输过程结束的,在Modbus协议中,以RTU模式为例,报文帧由时长至少为3.5个字符的空闲间隔区分,这个区间被称为t3.5,注意,这里是“至少”不是至多,也就是通信之间也不希望对方发的过快,所以在Freemodbus中对定时器就采用了类似于四舍五入的办法,比3.5个字符略微多一点的溢出时间。
Modbus 协议报文间隔需要大于3.5个字符计算:
1.1、有检验位
1个字符=1(起始位)+8(数据位)+1(奇偶校验位)+1(停止位)=11位
3.5个字符=3.5*11=38.5位
如果波特率=9600bps,则3.5个字符间隔时间为38.5/9.6=4.0104167毫秒
1.2、无校验位
1个字符=1(起始位)+8(数据位)+0(无校验位)+1(停止位)=10位
3.5个字符=3.5*10=35位
如果波特率=9600bps,则3.5个字符间隔时间为35/9.6=3.6458毫秒
2、通常可以将传输45位的时间四舍五入后做为报文时间间隔。
如果波特率=9600bps,则45位传输时间为45/9.6=4.6875≈5毫秒
所以Freemodus的作者做了一个 特别巧妙的公式变量:
usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate )
这里,usTimerT35_50us表示 3.5个字符,对应 50us的倍数,以波特率9600计算,刚刚理论计算为4ms左右,4000us/50us = 80
那么这个公式的计算结果是:usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate ) = 7*220000/(2*9600) = 80.2,这个值是无符号整型,所以就是80。
那么算出 80 以后怎么用呢,80代表的是80个 50us,这是作者为了移植方便,所以都用 50us作为基准,在具体使用的时候,刚说到要比t3.5稍微大点,大太多,反应慢,容易出错,作者给了一种方法:
usTimeoutMS = ( usTim1Timerout50us + 10 ) / 20;
其中 usTimeoutMS 就是要延时的ms数,还是以9600为例,那么定时器溢出时间为 (80+10)/20 = 4ms,然后移植者再根据自己的处理器,设置4ms的定时器溢出即可。
针对F460的设置:
stcTimerCfg.Tim0_CounterMode = Tim0_Sync;//同步计数模式stcTimerCfg.Tim0_SyncClockSource = Tim0_Pclk1;//选择时钟(时钟配置的是100M)stcTimerCfg.Tim0_ClockDivision = Tim0_ClkDiv1024;//分频 (97656.25Hz)
//波特率大于19200,统一设置1750us
//波特率大于19200,统一设置1750us
stcTimerCfg.Tim0_CmpValue = (uint16_t) 171;//19200以上,统一配置1750us:171=97656.25/1000000*1750
//波特率小于19200, 设置t35
stcTimerCfg.Tim0_CmpValue = (uint16_t) 5 * (usTimerT35_50us+10);//19200以下, 97656.25/1000000 * (usTimerT35_50us+10) * 50 = 97656.25/20000 * (usTimerT35_50us+10) = 5 * (usTimerT35_50us+10)