中国国家标准委员会2004年正式把Modbus作为了国家标准,所以仪器的通讯基本都是用Modbus协议, Modbus RTU(远程 终端设备,16进制字符)和Modbus ASCII(文本命令)主要用于串行通信领域,而ModbusTCP则常用于以太网通信。
Modbus RTU 的格式是 : 地址位 功能代码 8位数据 CRC校验码
由于电磁干扰(Electromagnetic Interference )会导致仪表通讯受到干扰,而出现通信错误,所以需要一个机制来确认这个数据包是否完整的数据还是被干扰改变的数据. 最常用的是CRC校验, 还有和校验.
CRC即循环冗余校验码(Cyclic Redundancy Check),仪表通讯用的是CRC16 ModBus, 多项式值0x8005
我们举个例子
01-03-40-02-00-01 这个数据加上CRC码就是01-03-40-02-00-01-30-0A
public static byte[] CRC16(byte[] data) { int len = data.Length; //通讯信息帧的字节长度 if (len > 0) { ushort crc = 0xFFFF; //预置1个16位的寄存器为十六进制FFFF(即全为1) for (int i = 0; i < len; i++) //通讯信息帧的第N个字节,从0开始 { crc = (ushort)(crc ^ (data[i])); //相异或,把结果放于CRC寄存器 //(如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0) for (int j = 0; j < 8; j++) //只操作低8位 { //CRC寄存器检查最右边1位,假如是1,与多项式0xA001异或;假如是0,右移一位 crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); }//下一位 }//下一个字节 byte hi = (byte)((crc & 0xFF00) >> 8); //高位置 byte lo = (byte)(crc & 0x00FF); //低位置 return new byte[] { lo, hi }; //Modbus CRC 低位在前 } return new byte[] { 0, 0 }; }
前2天我提到的串口工具,就自带有CRC校验 C#工控上位机系列(2)- 串口通信/监控工具
代码里的0xA0001和0x8005多项式的关系,看一下2个二进制
0x8005=1000 0000 0000 0101
0xA001=1010 0000 0000 0001
对比两个二进制高低位正好是完全相反的,CRC校验分为正向校验与反向校验。
正向校验高位在左,反向校验低位在左
正向校验使用左移位,反向校验使用右移位
和校验,通常用于对通讯要求不高的情况, 因为和校验只有1位,根据仪器不同,有的和校验只包括数据位;有的则包括功能位,地址位。
byte byteSum=0;for (int i = 0; i < bytes.Length; i++){ bytesWithSum[i] = bytes[i]; //有的仪表的和校验,不是从0位开始的 if (i>=SumStartIndex) byteSum += bytes[i];}