using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace IStation.DataDockingSocket { //ModBus RTU标准: static public class ModBusRtuHelper { /// /// 得到16位的CRC检验码:低位在前[0],高位在后[1] /// /// 注意输入的消息长度要求包含CRC的2位,否则计算出来CRC不正确 /// public static void GetCRC16(byte[] message, ref byte[] CRC) { //Function expects a modbus message4PT of any length as well as a 2 byte CRC array in which to //return the CRC values: if (CRC == null) CRC = new byte[2]; ushort CRCFull = 0xFFFF; byte CRCHigh = 0xFF, CRCLow = 0xFF; char CRCLSB; for (int i = 0; i < (message.Length) - 2; i++) { CRCFull = (ushort)(CRCFull ^ message[i]); for (int j = 0; j < 8; j++) { CRCLSB = (char)(CRCFull & 0x0001); CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF); if (CRCLSB == 1) CRCFull = (ushort)(CRCFull ^ 0xA001); } } CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF); CRC[0] = CRCLow = (byte)(CRCFull & 0xFF); } // // 摘要: // 构建查询消息 // // 参数: // address设备地址,注意是byte格式,最大255 // func功能码 // startRegister 寄存器开始地址(用十进制的地址) // numRegister 寄存器数量 // // 返回结果 // 消息List类型,不成功返回NULL public static void BuildSendMessage(byte address, byte func, ushort start, ushort registers, ref byte[] message) { //构建消息 message数据长度要求包含最后2位的校验码 message = new byte[8]; message[0] = address; message[1] = func; message[2] = (byte)(start >> 8); message[3] = (byte)start; message[4] = (byte)(registers >> 8); message[5] = (byte)registers; //计算16位的CRC校验码 byte[] CRC = new byte[2]; GetCRC16(message, ref CRC); //赋值校验码 message[message.Length - 2] = CRC[0]; message[message.Length - 1] = CRC[1]; } /// /// 写入多个 /// /// /// /// /// /// public static void BuildSendMessage16(byte address, ushort start, ushort registers, float v, ref byte[] message) { byte[] bytes4Float = BitConverter.GetBytes(v); // 09-03-08-40-40-00-00-40-40-00-00-EE-57 //构建消息 message数据长度要求包含最后2位的校验码 message = new byte[12]; message[0] = address; message[1] = 0x10; message[2] = (byte)(start >> 8); message[3] = (byte)start; message[4] = (byte)(registers >> 8); message[5] = (byte)registers; message[6] = (byte)04;//2个就*2 message[7] = bytes4Float[3];//要倒过来 0x40; message[8] = bytes4Float[2];//要倒过来0x80; message[9] = bytes4Float[1];//要倒过来0x00; message[10] = bytes4Float[0];//要倒过来0x00; //计算16位的CRC校验码 byte[] CRC = new byte[2]; GetCRC16(message, ref CRC); //赋值校验码 message[message.Length - 2] = CRC[0]; message[message.Length - 1] = CRC[1]; } /// /// 写入单个 /// /// /// /// /// /// public static void BuildSendMessage06(byte address, ushort start, ushort registers, int v, ref byte[] message) { byte[] bytes4Value = BitConverter.GetBytes(v); //构建消息 message数据长度要求包含最后2位的校验码 message = new byte[8]; message[0] = address; message[1] = 0x06; message[2] = (byte)(start >> 8); message[3] = (byte)start; message[4] = bytes4Value[1];//要倒过来0x00; message[5] = bytes4Value[0];//要倒过来0x00; //计算16位的CRC校验码 byte[] CRC = new byte[2]; GetCRC16(message, ref CRC); //赋值校验码 message[message.Length - 2] = CRC[0]; message[message.Length - 1] = CRC[1]; } /** * 将int数值转换为占四个字节的byte数组,本方法适用于(低位在前,高位在后)的顺序。 和bytesToInt()配套使用 * @param value * 要转换的int值 * @return byte数组 */ public static byte[] intToBytes(int value) { byte[] src = new byte[2]; src[1] = (byte)((value >> 8) & 0xFF); src[0] = (byte)(value & 0xFF); return src; } /** * 将int数值转换为占四个字节的byte数组,本方法适用于(高位在前,低位在后)的顺序。 和bytesToInt2()配套使用 */ public static byte[] intToBytes2(int value) { byte[] src = new byte[2]; src[2] = (byte)((value >> 8) & 0xFF); src[3] = (byte)(value & 0xFF); return src; } /// /// /// /// /// /// /// /// public static byte[] BuildSendMessage(byte address, byte func, ushort start, ushort registers) { byte[] message = null; BuildSendMessage(address, func, start, registers,ref message); return message; } /// /// 得到收到的信息中的数据 /// /// /// /// public static int GetReceivedDatas(byte[] byteMessage, out double[] rValueArray) { rValueArray = null; string strMessage = BitConverter.ToString(byteMessage, 0, byteMessage.Length); // byte[] -> 16进制字符串 string[] strValueList = strMessage.Split('-'); int iReadAddress = -1; if (strValueList.Length <= 6) { //!数据没有收完,直接返回 return -1; } try { iReadAddress = int.Parse(strValueList[0]); //!获得设备ID //int iFunID = int.Parse(strValueList[1]);//!读取功能吗 int dataNum = int.Parse(strValueList[2]) / 2;//!获得数据长度(除以2就是数据个数) if (dataNum < 1) return -1; List rValueList = new List(); for (int i = 0; i < dataNum; i++) { string strHigh = strValueList[3 + 2 * i]; string strLow = strValueList[3 + 2 * i + 1]; byte byteHigh = Convert.ToByte(strHigh); byte byteLow = Convert.ToByte(strLow); double rValue = byteHigh * 256.0 + byteLow; // rValue = rValue * 10000 / Math.Pow(10, GetDecimalPlaces(1)); rValueList.Add(rValue); } rValueArray = rValueList.ToArray(); } catch { return -1; } return iReadAddress; } // // 摘要: // 检查收到的信息的校验码是否正确 // // 参数: // 得到的二进制数据 // // 返回结果: // 是否成功 public static bool CheckReceivedMessage(byte[] byteMessage) { //计算校验码 byte[] CRC = new byte[2]; GetCRC16(byteMessage, ref CRC); //比较是否和消息中的校验码一致 if (CRC[0] == byteMessage[byteMessage.Length - 2] && CRC[1] == byteMessage[byteMessage.Length - 1]) return true; else return false; } } }