modubs常用8命令协议基础封装
一、区别:tcp比rtu多了事务,协议,长度(前面多6个字节)
ascii和rtu的区别(参考地址:https://blog.csdn.net/b07lxh/article/details/131613977)
/// <summary> /// byte[]转换为等效的十六进制字符串,例如byte example = 32,转换字符串为"20" /// </summary> /// <param name="source">byte[]原数组</param> /// <param name="formatStr">转换的格式,默认为十六进制</param> private string BytesToHexString(byte[] source) { StringBuilder pwd = new StringBuilder(); foreach (byte btStr in source) { pwd.AppendFormat("{0:X2}", btStr); } return pwd.ToString(); } //转换为16进制字符串后,组装成ModbusASCII命令格式,首字符为":",末尾字符为回车换行 string cmdString = ":" + BytesToHexString(command) + "\r\n"; //把ModbusASCII指令格式转换为等效的byte[] byte[] AsciiCmd = Encoding.ASCII.GetBytes(cmdString);
二、ascii的结果处理:
0x3A是ASCII码的冒号(:);最后两个字符0x0D 0x0A是回车换行符;剩下的是需要处理的数据,和rtu一样
三、tcp常用modbus协议封装发送
public class ModbusHelp { #region 功能码 /// <summary> /// 读线圈寄存器 /// </summary> public const byte MB_READ_COILS = 0x01; /// <summary> /// 读离散输入寄存器 /// </summary> public const byte MB_READ_DISCRETE = 0x02; /// <summary> /// 读保持寄存器 /// </summary> public const byte MB_READ_HOLD_REG = 0x03; /// <summary> /// 读输入寄存器 /// </summary> public const byte MB_READ_INPUT_REG = 0x04; /// <summary> /// 写单个线圈 /// </summary> public const byte MB_WRITE_SINGLE_COIL = 0x05; /// <summary> /// 写单寄存器 /// </summary> public const byte MB_WRITE_SINGLE_REG = 0x06; /// <summary> /// 写多线圈 /// </summary> public const byte MB_WRITE_MULTIPLE_COILS = 0x0f; /// <summary> /// 写多寄存器 /// </summary> public const byte MB_WRITE_MULTIPLE_REGS = 0x10; #endregion #region 协议 /// <summary> /// 事物处理标识符 /// </summary> public byte[] MB_Thing = new byte[] { 0x00, 0x0B }; /// <summary> /// 协议标识符 /// </summary> public byte[] MB_Agreement = new byte[] { 0x00, 0x00 }; /// <summary> /// 单元标识符 /// </summary> public byte MB_Cell = 0x07; #endregion #region 请求参数封装 /// <summary> /// 计算数据长度 /// </summary> /// <param name="byteData"></param> /// <returns></returns> public byte[] GetDataLength(byte[] byteData) { int leng = byteData.Length; return IntToByte(leng); } /// <summary> /// int类型转字节 /// </summary> /// <param name="data"></param> /// <returns></returns> public byte[] IntToByte(int data) { var register = Convert.ToInt16(data); //return BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder(register)); return BitConverter.GetBytes(register).Reverse().ToArray(); } /// <summary> /// 读线圈寄存器 /// </summary> /// <param name="state">读取位置</param> /// <param name="places">读取多少位</param> /// <returns></returns> public List<byte> ReadModbusCoils(int state, int places) { return ReadModbusSingleData(state, places, MB_READ_COILS); } /// <summary> /// 读离散输入寄存器 /// </summary> /// <param name="state">读取位置</param> /// <param name="places">读取多少位</param> /// <returns></returns> public List<byte> ReadModbusDiscrete(int state, int places) { return ReadModbusSingleData(state, places, MB_READ_DISCRETE); } /// <summary> /// 读保持寄存器 /// </summary> /// <param name="state">读取位置</param> /// <param name="places">读取多少位</param> /// <returns></returns> public List<byte> ReadModbusHoldReg(int state, int places) { return ReadModbusSingleData(state, places, MB_READ_HOLD_REG); } /// <summary> /// 读输入寄存器 /// </summary> /// <param name="state">读取位置</param> /// <param name="places">读取多少位</param> /// <returns></returns> public List<byte> ReadModbusInputReg(int state, int places) { return ReadModbusSingleData(state, places, MB_READ_INPUT_REG); } /// <summary> /// 1,2,3,4 请求是一样的 /// </summary> /// <param name="state"></param> /// <param name="places"></param> /// <param name="fcode"></param> /// <returns></returns> public List<byte> ReadModbusSingleData(int state, int places, byte fcode) { List<byte> SendCommand = new List<byte>(); //事物处理标识符 SendCommand.AddRange(MB_Thing); //协议标识符 SendCommand.AddRange(MB_Agreement); //长度 SendCommand.AddRange(new byte[] { 0x00, 0x06 }); //单元标识符 SendCommand.Add(MB_Cell); //功能码 SendCommand.Add(fcode); //起始地址 SendCommand.AddRange(IntToByte(state)); //结束地址-长度 SendCommand.AddRange(IntToByte(places)); return SendCommand; } /// <summary> /// 写单个线圈 /// </summary> /// <param name="state">读取位置</param> /// <param name="places">读取多少位</param> /// <returns></returns> public List<byte> WriteModbusCoil(int index, int value) { List<byte> SendCommand = new List<byte>(); //事物处理标识符 SendCommand.AddRange(MB_Thing); //协议标识符 SendCommand.AddRange(MB_Agreement); //长度 SendCommand.AddRange(new byte[] { 0x00, 0x06 }); //单元标识符 SendCommand.Add(MB_Cell); //功能码 SendCommand.Add(MB_WRITE_SINGLE_COIL); //起始地址 SendCommand.AddRange(IntToByte(index)); //写入数据 SendCommand.AddRange(value == 1 ? new byte[] { 0xff, 0x00 } : new byte[] { 0x00, 0x00 }); return SendCommand; } /// <summary> /// 写单寄存器 /// </summary> /// <param name="state">读取位置</param> /// <param name="places">读取多少位</param> /// <returns></returns> public List<byte> WriteModbusSingleReg(int index, int value) { List<byte> SendCommand = new List<byte>(); //事物处理标识符 SendCommand.AddRange(MB_Thing); //协议标识符 SendCommand.AddRange(MB_Agreement); //长度 SendCommand.AddRange(new byte[] { 0x00, 0x06 }); //单元标识符 SendCommand.Add(MB_Cell); //功能码 SendCommand.Add(MB_WRITE_SINGLE_REG); //起始地址 SendCommand.AddRange(IntToByte(index)); //写入数据 SendCommand.AddRange(IntToByte(value)); return SendCommand; } /// <summary> /// 写入多个线圈器 /// </summary> /// <param name="index">位置</param> /// <param name="values">值</param> /// <returns></returns> public List<byte> WriteModbusMultipleCoils(int index, List<int> values) { //写入的值 List<byte> SendCommand = new List<byte>(); //事物处理标识符 SendCommand.AddRange(MB_Thing); //协议标识符 SendCommand.AddRange(MB_Agreement); //长度 SendCommand.AddRange(new byte[] { 0x00, 0x08 }); //单元标识符 SendCommand.Add(MB_Cell); //功能码 SendCommand.Add(MB_WRITE_MULTIPLE_COILS); //起始地址 SendCommand.AddRange(IntToByte(index)); //写入的数量 SendCommand.AddRange(IntToByte(values.Count())); //写入数据字节 SendCommand.Add(0x01); string str = "";//数据要反转 for (int i = values.Count - 1; i >= 0; i--) { if (values[i] == 1) str += "1"; else str += "0"; } SendCommand.Add(Convert.ToByte(str, 2)); return SendCommand; } /// <summary> /// 写入多个寄存器 /// </summary> /// <param name = "index" > 位置 </ param > /// < param name="values">值</param> /// <returns></returns> public List<byte> WriteModbusMultipleRegs(int index, List<int> values) { //写入的值 List<byte> valueByte = new List<byte>(); foreach (var it in values) { valueByte.AddRange(IntToByte(it)); } byte[] valueLeng = BitConverter.GetBytes(Convert.ToInt16(valueByte.Count())); valueByte.Insert(0, valueLeng.FirstOrDefault()); List<byte> SendCommand = new List<byte>(); //事物处理标识符 SendCommand.AddRange(MB_Thing); //协议标识符 SendCommand.AddRange(MB_Agreement); //长度 SendCommand.AddRange(IntToByte(valueByte.Count() + 6)); //单元标识符 1 SendCommand.Add(MB_Cell); //功能码 1 SendCommand.Add(MB_WRITE_MULTIPLE_REGS); //写入位置 2 SendCommand.AddRange(IntToByte(index)); //写入寄存器数量 SendCommand.AddRange(IntToByte(values.Count())); //写入的值 SendCommand.AddRange(valueByte); return SendCommand; } #endregion /// <summary> /// 处理返回的值 /// </summary> /// <param name="buffer"></param> public void HandelByte(byte[] buffer, int length = 0) { int count = buffer.Count(); if (buffer[7] == 0x01 || buffer[7] == 0x02)//读取多个 读取的个数 { string binaryString = Convert.ToString(buffer[9], 2); var values = binaryString.ToCharArray().ToList();//这个判断有问题 int vl = values.Count; if (vl != length) { for (int i = 0; i < length - vl; i++) values.Insert(0, '0'); } values.Reverse(); string str = string.Join(",", values); Console.WriteLine(str);//线圈的状态 } else if ( buffer[7] == 0x03 || buffer[7] == 0x04)//读取多个 { var data = BitConverter.ToUInt16(buffer, 0); int l = buffer[8] / 2; ShowData(buffer, l); } else if (buffer[7] == 0x05 || buffer[7] == 0x06)//写入单个寄存器 { //解析 ushort[] data = new ushort[1]; data[0] = BitConverter.ToUInt16(new byte[] { buffer[11], buffer[10] }, 0); Console.WriteLine(data);//写入的值 } else if (buffer[7] == 0x0f || buffer[7] == 0x10)//写入多个寄存器 { //解析 ushort[] data = new ushort[1]; data[0] = BitConverter.ToUInt16(new byte[] { buffer[11], buffer[10] }, 0); Console.WriteLine(data);//写入的个数 } } /// <summary> /// /// </summary> /// <param name="buffer"></param> /// <param name="length"></param> /// <param name="j"></param> private void ShowData(byte[] buffer, int length) { //解析 ushort[] data = new ushort[length]; for (int i = 0; i < data.Length; i++) { data[i] = BitConverter.ToUInt16(new byte[] { buffer[9 + 2 * i + 1], buffer[9 + 2 * i] }, 0); } Console.WriteLine(data); } }