关于freemodbus协议中eMBFuncReadHoldingRegister()函数的所谓错误
摘要:网上看到有好心的网友提示,freemodbus协议中的mbfuncholding.c 文件中eMBFuncReadHoldingRegister()函数,有一处错误,即:第185行的“usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”应为“usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”,我认为这不能算是一个错误,且听我的分析。
关键词:freemodbus Modbus 保持寄存器 eMBFuncReadHoldingRegister
1.关于freemodbus协议栈的一点粗浅体会
Modbus通信协议,搞过工业控制的人,多多少少应该了解一点。其结构简单,应用广泛。几乎是很多PLC的标配接口。但其通信规约也有几十页之多,要在单片机上实现,如果自己写源代码,估计还是需要一些时间的,因为不光要实现常用的功能,还要保持协议的完整性和错误处理机制。
freemodbus是一个比较完整的协议栈,有机构在维护,并且开源。有点单片机基础得朋友,1个小时应该可以移植好(前提能参考一个不错的教程)。比自己撸代码快N倍。个人感觉这个协议栈还是很好用的,但免费的只支持从站,需要做主站就要自己再想办法了。
2.为什么说这不算个错误
首先要看这句代码是干什么用的?上下文如下:
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
pucFrame[MB_PDU_FUNC_READ_ADDR_OFF]存储的是Modbus数据帧中寄存器起始地址的高字节,pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] 存储的是Modbus数据帧中寄存器起始地址的低字节,pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 存储的是Modbus数据帧中寄存器个数的高字节,pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] 存储的是Modbus数据帧中寄存器个数的低字节。
下面给一个实例,能更好理解,如图1。此帧数据是读取地址为1的从站的保持寄存器,寄存器起始地址为:18430(0x47FE),读取寄存器的个数为:101(0x0065),在这里:
pucFrame[MB_PDU_FUNC_READ_ADDR_OFF]的值为:0x47;
pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] 的值为:0xFE;
pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 的值为:0x00;
pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] 的值为:0x65。
从这里也可以看出,Modbus在发送一个word(16bit)数据的时候,是高字节在前,低字节在后。
图1
既然pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 表示的是寄存器个数的高字节,那么我们来查看一下Modbus协议,看一下这个参数的范围,如图2、图3所示。此两图是从Modbus协议文本中截出来的,0x03功能码是读保持寄存器,0x10功能码是写多个保持寄存器,这两个功能码会涉及到保持寄存器数量的问题,寄存器数量的范围一个是0x7D,一个是0x78,都在一个字节的范围内,因此,寄存器数量这个参数的高字节始终为0,也就是说pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF]是等于0的,可以不处理。
图2
图3
3.总结及讨论
综上,我认为这个不能算是个错误,不影响程序的正常结果,只是写法不够严谨。但有一个极端情况,是有影响的,Modbus主站读写寄存器的数量超过协议规定的数量的时候,本应该返回错误码,但这种写法由于只处理了低字节,就有可能认为没有错误,而对数据进行处理。为了安全起见,大家还是把这句代码改掉吧,改为“usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”,以防止极端情况的发生。
还有一个问题,Modbus协议规定的读写保持寄存器的数量都在一个字节的范围内,发送数据的时候为什么要用2个字节来表示寄存器数量,这个还没有做深入研究,可能是考虑协议的整体兼容性吧,有兴趣的朋友可以一起讨论。