设备必须要有RTU协议!这是Modbus协议上规定的,且默认模式必须是RTU,ASCII作为选项。(也就是说,一般的设备只有RTU这个协议,ASCII一般很少)所以说,一般学习Modbus协议,只需要了解RTU的协议,ASCII作为学习的了解就足够了。
modbus- TCP 和 modbus-RTU的区别?
1 modbus- TCP 不需要校验码, modbus-RTU需要crc16算法校验码
2 modbus- TCP 请求帧有事务处理标识符 协议号 长度等字节,但是modbus-RTU没有事务处理标识符 协议号 长度等字节
modbus- TCP 请求帧:00 03 | 00 00 | 00 06 | 01 | 03 | 00 01 | 00 01
modbus-RTU 请求帧: 01| 03 | 00 01 |00 01 |D5 CA
modbus- ASCII 和 modbus-RTU的区别?
1 modbus- ASCII校验码的算法采用的是LRC校验算法, modbus-RTU采用的crc16校验算法
2 modbus- ASCII发送的字节转成字符串格式, modbus-RTU发送的是字节格式
modbus - ASCII 请求帧 :010300000001FB
1设备地址 01
2功能码 读取03
3寄存器地址 00 00
4 寄存器个数 00 01
5 lrc校验码 F B
string s2 = Tools.GetRequestFrame(new byte[] { 01,03,00,00,00,10});
封装 modbus-ascii使用的方法
internal static class Tools
{
/// <summary>
/// 把传递过来字节数组 通过lrc算法生成校验码
/// </summary>
/// <param name="data"> 字节数组</param>
/// <returns>校验码</returns>
/// Tools.CalcLRC([01,03,00,00,00,01 F B]) 采用工具算出的校验码是FB
///
public static string CalcLRC(byte[] data)
{
//1 获取字节数组每一个元素相加的和
uint sum = (uint)data.Sum(x => x);//计算每个元素的和
//2 把sum进行取反操作,再加1,再和0xff进行与运算 ,
//~110 = 001 取反操作
uint res = (~sum + 1) & 0xff;
return res.ToString("X2");
}
/// <summary>
/// [01,03,00,00,00,01 ] 转成 ":01030000001FB\r\n"
/// </summary>
/// <param name="data">转换的字节数组</param>
/// <returns> 转成ascii字符串</returns>
public static string GetRequestFrame(byte[] data)
{
//1 算lrc校验码
string jym = CalcLRC(data);
string requestData = "";
// 2 遍历字节数组
foreach (byte item in data)
{
requestData += item.ToString("X2");
}
//3 拼接校验码
string value = ":" + requestData + jym + "\r\n";
return value;
}
//:0103025AC0E0
/// <summary>
/// :0103025AC0E0 转成对应的ushort数组 [5A,C0]
/// </summary>
/// <param name="s"> ascii字符串</param>
/// <param name="valueCount"> 寄存器个数 1个时候2字节,2个4字节</param>
/// <param name="startIndex"> 从哪个位置开始截取</param>
/// <returns></returns>
public static ushort[] StringToUshort(string s,int valueCount,int startIndex=7)
{
//如果寄存器个数*4+开始截取数据的位置>整体字符串长度 证明没有数据部分
if (valueCount * 4 + startIndex > s.Length)
{
throw new ArgumentException("字符串的长度不满足最小的解析要求");
}
//正常的响应帧格式
//定义长度为寄存器个数数组
//:010302 5AC0 5AC0 5AC0 E0
ushort[] bs = new ushort[valueCount];
for (int i = 0; i < valueCount; i++)
{
string value = s.Substring(startIndex, 4);
startIndex += 4;
bs[i] = Convert.ToUInt16(value,16);
}
return bs;
}
}