Modbus通信协议 【 初识 Modbus】

时间:2023-03-09 16:11:13
Modbus通信协议 【 初识 Modbus】

Modbus协议

     Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。

此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

    Modbus 是一个请求/应答协议,当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。

Modbus热图
 Modbus通信协议 【 初识 Modbus】

 

Modbus消息帧

了解了它,会使你对串口通信有一个清晰的认识!

Modbus通信协议 【 初识 Modbus】

通用消息帧

Modbus通信协议 【 初识 Modbus】

ASCII消息帧 (在消息中的每个8Bit 字节都作为两个ASCII字符发送)

十六进制,ASCII字符0...9,A...F

消息中的每个ASCII字符都是一个十六进制字符组成

每个字节的位

1个起始位

n个数据位,最小的有效位先发送

1个奇偶校验位,无校验则无

1个停止位(有校验时),2个Bit(无校验时)

错误检测域

LRC(纵向冗长检测)

Modbus通信协议 【 初识 Modbus】

Modbus通信协议 【 初识 Modbus】

RTU消息帧

8位二进制,十六进制数0...9,A...F

消息中的每个8位域都是一个两个十六进制字符组成

每个字节的位

1个起始位

8个数据位,最小的有效位先发送

1个奇偶校验位,无校验则无

1个停止位(有校验时),2个Bit(无校验时)

错误检测域

CRC(循环冗长检测)

Modbus通信协议 【 初识 Modbus】

Modbus通信协议 【 初识 Modbus】

 CRC校验
public static string CRCCheck(string val)
{
val = val.TrimEnd(' ');
string[] spva = val.Split(' ');
byte[] bufData = new byte[spva.Length + ];
bufData = ToBytesCRC(val);
ushort CRC = 0xffff;
ushort POLYNOMIAL = 0xa001;
for (int i = ; i < bufData.Length - ; i++)
{
CRC ^= bufData[i];
for (int j = ; j < ; j++)
{
if ((CRC & 0x0001) != )
{
CRC >>= ;
CRC ^= POLYNOMIAL;
}
else
{
CRC >>= ;
}
}
}
return Maticsoft.DBUtility.HLConvert.ToHex(System.BitConverter.GetBytes(CRC));
}
/// <summary>
/// 例如把如下字符串转换成字节数组
/// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB 转换为字节数组
/// </summary>
/// <param name="hex">十六进制字符串</param>
/// <returns></returns>
public static byte[] ToBytesCRC(string hex)
{
string[] temp = hex.Split(' ');
byte[] b = new byte[temp.Length + ]; for (int i = ; i < temp.Length; i++)
{
b[i] = Convert.ToByte(temp[i], );
} return b;
}
/// <summary>
/// 将字节数据转换为十六进制字符串,中间用 “ ”分割 如:AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB
/// </summary>
/// <param name="vars">要转换的字节数组</param>
/// <returns></returns>
public static String ToHex(byte[] vars)
{
return BitConverter.ToString(vars).Replace('-', ' ').Trim();
}

CRC校验

CS校验(累加和)

public static string CSCheck(string str)
{
if (str.Length == ) return "";
else str = str.Trim();
byte[] sss = ToBytes(str);
int n = ;
for (int i = ; i < sss.Length; i++)
{
n += sss[i];
}
return ToHex(n);
}
/// <summary>
/// AB CD 12 3B 转换为字节数组
/// </summary>
/// <param name="hex">十六进制字符串</param>
/// <returns></returns>
public static byte[] ToBytes(string hex)
{
string[] temp = hex.Split(' ');
byte[] b = new byte[temp.Length]; for (int i = ; i < temp.Length; i++)
{
if (temp[i].Length > )
b[i] = Convert.ToByte(temp[i], );
} return b;
}
/// <summary>
/// 转换为符合本程序的十六进制格式
/// </summary>
/// <param name="var">1 2 3 等。</param>
/// <returns>返回十六进制字符串,如果是1-9的话,前面带零</returns>
/// <example>例如: 5 ="05" 12 ="0C" 无论何时,都是两位数。 </example>
public static string ToHex(int var)
{
int cs = var;
string tmp = "";
if (cs == ) { tmp = ""; }
while (cs > )
{
int ys;
cs = Math.DivRem(cs, , out ys);
tmp = tmp.Insert(, string.Format(" {0}", Right("" + Convert.ToString(ys, ), ).ToUpper()));
}
return tmp.Trim();
}
public static string Right(string str, int Length)
{
if ((Length <= ) || (str == null))
{
return "";
}
int length = str.Length;
if (Length >= length)
{
return str;
}
return str.Substring(length - Length, Length);
}

CS校验(累加和)

LRC校验(LRC错误校验用于ASCII模式)

/// <summary>
/// 取模FF(255)
/// 取反+1
/// </summary>
/// <param name="writeUncheck"></param>
/// <returns></returns>
public static string LRCheck(string writeUncheck)
{
char[] hexArray = new char[writeUncheck.Length];
hexArray = writeUncheck.ToCharArray();
int decNum = , decNumMSB = , decNumLSB = ;
int decByte, decByteTotal = ; bool msb = true; for (int t = ; t <= hexArray.GetUpperBound(); t++)
{
if ((hexArray[t] >= ) && (hexArray[t] <= )) decNum = (hexArray[t] - ); else if ((hexArray[t] >= ) & (hexArray[t] <= ))
decNum = + (hexArray[t] - ); if (msb)
{
decNumMSB = decNum * ;
msb = false;
}
else
{
decNumLSB = decNum;
msb = true;
}
if (msb)
{
decByte = decNumMSB + decNumLSB;
decByteTotal += decByte;
}
} decByteTotal = ( - decByteTotal) + ;
decByteTotal = decByteTotal & ; int a, b = ; string hexByte = "", hexTotal = "";
double i; for (i = ; decByteTotal > ; i++)
{
b = Convert.ToInt32(System.Math.Pow(16.0, i));
a = decByteTotal % ;
decByteTotal /= ;
if (a <= )
hexByte = a.ToString();
else
{
switch (a)
{
case :
hexByte = "A";
break;
case :
hexByte = "B";
break;
case :
hexByte = "C";
break;
case :
hexByte = "D";
break;
case :
hexByte = "E";
break;
case :
hexByte = "F";
break;
}
}
hexTotal = String.Concat(hexByte, hexTotal);
}
return hexTotal;
} public void LRCheck(byte[] code)
{
int sum = ;
foreach (byte b in code)
{
sum += b;
}
sum = sum % ;//取模FF(255)
sum = ~sum + ;//取反+1
string lrc = Convert.ToString(sum, );
return lrc;
}

LRC校验(LRC错误校验用于ASCII模式)

自定义Modbus数据表

自定义Modbus数据表例子:

设备相关读取信息:

Modbus通信协议 【 初识 Modbus】

命令报文信息解析:

Modbus通信协议 【 初识 Modbus】

自定义Modbus数据表定义注意

串口调试工具

串口调试工具的使用.

Modbus通信协议 【 初识 Modbus】

串口调试工具 + RS485  就可以读取硬件上的数据,和向硬件请求了,如何使用请看“调试篇”会有详细的说明。

Modbus通信协议 【 初识 Modbus】 Modbus通信协议 【 初识 Modbus】

网络调试助手:

调试助手主要还是TCP协议通讯的一个调试工具

Modbus通信协议 【 初识 Modbus】

https://www.cnblogs.com/luomingui/archive/2013/06/14/Modbus.html#top