最近接触到一个项目,是运行在组态王软件中的仪表设备,使用modbus协议通讯。
原以为modbus是一套完整的协议,从网上下载了粗略看了一下。后来拿到竞品的样品,安装了组态王,连接运行了一下,才发现与之前理解有些不同。modbus可以说是一个协议的规范,具体数字代表的意义,是由设备厂商自定的。厂商将这些自定的协议做成驱动(dll),放在组态王的驱动包里,并选择相应的设备名,这样串口的modbus协议经过翻译,成为组态王的标准接口。
modbus协议的框架为:
PC->设备 <Head><Cmd><Address><Data><CRC>
设备->PC <Head><Cmd><Len><Data...><CRC>
<Head> 命令头,默认是0x3b, 也可以自定义,本协议中是0x60.
<Cmd> 0x03-读寄存器;0x06-写单个寄存器;其余的也可自定义;
<Address> 寄存器地址,双字节,如[00 03]=3
<Data> 双字节。当Cmd为读寄存器时,表示连续读取的个数;当Cmd为写时,表示写入的数据;
<CRC> 双字节校验;
<Len> 数据区字节个数,单字节;
举例说明
PC->主设备,读取从01开始,连续2个寄存器的值:60 03 [00 01] [00 02] [9D BA]
主设备->PC,回复4个字节数据00: 60 03 [04] [00 00] [00 00] [8A F5]
顺便贴一段crc校验的代码
ushort crcTlb[] = {0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400};
ushort CalcCRC16(byte[] pBuf, int len)
{
byte i = 0, ch = 0;
ushort crc = 0xFFFF;
for (i = 0; i < len; i++)
{
ch = pBuf[i];
crc = (ushort)(crcTlb[(ch ^ crc) & 0x0F] ^ (crc >> 4));
crc = (ushort)(crcTlb[((ch >> 4) ^ crc) & 0x0F] ^ (crc >> 4));
}
crc = (ushort)((crc & 0xFF) << 8 | (crc >> 8));
return crc;
}
另外还遇到一个组态王的讨厌问题。把原来项目文件换了一个电脑,USB转串口的端口从COM7变成了COM5,但从工程里始终无法修改,提示“不支持预定义的接口”。后来终于在工程文件device.dat的最后一段找到了,把其中的二进制COM7直接改成了COM5,打开软件后跑起来了:)