Modbus 協議是應用于電子控制器上的一種通用語言。通過此協議,控制器相互之間、控制器經由網絡(例如以太網)和其它設備之間可以通信。Modbus 協議定義了一個控制器能認識使用的消息結構,而不管它們是經過何種網絡進行通信的。它描述了一控制器請求訪問其它設備的過程,如果回應來自其它設備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內容的公共格式。
Modbus 是一個請求/應答協議
Modbus
以下是要分解的Modbus熱圖
Modbus消息幀
了解了它,會使你對串口通信有一個清晰的認識!
通用消息幀
ASCII消息幀 (在消息中的每個8Bit 字節都作為兩個ASCII字符發送)
十六進制,ASCII字符0...9,A...F
消息中的每個ASCII字符都是一個十六進制字符組成
每個字節的位
1個起始位
n個數據位,最小的有效位先發送
1個奇偶校驗位,無校驗則無
1個停止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
LRC(縱向冗長檢測)
RTU消息幀
8位二進制,十六進制數0...9,A...F
消息中的每個8位域都是一個兩個十六進制字符組成
每個字節的位
1個起始位
8個數據位,最小的有效位先發送
1個奇偶校驗位,無校驗則無
1個停止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
CRC(循環冗長檢測)
CRC校驗
public static string CRCCheck(string val) { val = val.TrimEnd(' '); string[] spva = val.Split(' '); byte[] bufData = new byte[spva.Length + 2]; bufData = ToBytesCRC(val); ushort CRC = 0xffff; ushort POLYNOMIAL = 0xa001; for (int i = 0; i < bufData.Length - 2; i++) { CRC ^= bufData[i]; for (int j = 0; j < 8; j++) { if ((CRC & 0x0001) != 0) { CRC >>= 1; CRC ^= POLYNOMIAL; } else { CRC >>= 1; } } } return Maticsoft.DBUtility.HLConvert.ToHex(System.BitConverter.GetBytes(CRC)); } /// /// 例如把如下字符串轉換成字節數組 /// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB 轉換為字節數組 /// /// 十六進制字符串 /// public static byte[] ToBytesCRC(string hex) { string[] temp = hex.Split(' '); byte[] b = new byte[temp.Length + 2]; for (int i = 0; i < temp.Length; i++) { b[i] = Convert.ToByte(temp[i], 16); } return b; } /// /// 將字節數據轉換為十六進制字符串,中間用 “ ”分割 如:AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB /// /// 要轉換的字節數組 /// public static String ToHex(byte[] vars) { return BitConverter.ToString(vars).Replace('-', ' ').Trim(); }
CS校驗(累加和)
public static string CSCheck(string str) { if (str.Length == 0) return ""; else str = str.Trim(); byte[] sss = ToBytes(str); int n = 0; for (int i = 0; i < sss.Length; i++) { n += sss[i]; } return ToHex(n); } /// /// AB CD 12 3B 轉換為字節數組 /// /// 十六進制字符串 /// public static byte[] ToBytes(string hex) { string[] temp = hex.Split(' '); byte[] b = new byte[temp.Length]; for (int i = 0; i < temp.Length; i++) { if (temp[i].Length > 0) b[i] = Convert.ToByte(temp[i], 16); } return b; } /// /// 轉換為符合本程序的十六進制格式 /// /// 1 2 3 等。 /// 返回十六進制字符串,如果是1-9的話,前面帶零 /// 例如: 5 ="05" 12 ="0C" 無論何時,都是兩位數。 public static string ToHex(int var) { int cs = var; string tmp = ""; if (cs == 0) { tmp = "00"; } while (cs > 0) { int ys; cs = Math.DivRem(cs, 256, out ys); tmp = tmp.Insert(0, string.Format(" {0}", Right("00" + Convert.ToString(ys, 16), 2).ToUpper())); } return tmp.Trim(); } public static string Right(string str, int Length) { if ((Length <= 0) || (str == null)) { return ""; } int length = str.Length; if (Length >= length) { return str; } return str.Substring(length - Length, Length); }
)
LRC校驗(LRC錯誤校驗用于ASCII模式)
/// /// 取模FF(255) /// 取反+1 /// /// /// public static string LRCheck(string writeUncheck) { char[] hexArray = new char[writeUncheck.Length]; hexArray = writeUncheck.ToCharArray(); int decNum = 0, decNumMSB = 0, decNumLSB = 0; int decByte, decByteTotal = 0; bool msb = true; for (int t = 0; t <= hexArray.GetUpperBound(0); t++) { if ((hexArray[t] >= 48) && (hexArray[t] <= 57)) decNum = (hexArray[t] - 48); else if ((hexArray[t] >= 65) & (hexArray[t] <= 70)) decNum = 10 + (hexArray[t] - 65); if (msb) { decNumMSB = decNum * 16; msb = false; } else { decNumLSB = decNum; msb = true; } if (msb) { decByte = decNumMSB + decNumLSB; decByteTotal += decByte; } } decByteTotal = (255 - decByteTotal) + 1; decByteTotal = decByteTotal & 255; int a, b = 0; string hexByte = "", hexTotal = ""; double i; for (i = 0; decByteTotal > 0; i++) { b = Convert.ToInt32(System.Math.Pow(16.0, i)); a = decByteTotal % 16; decByteTotal /= 16; if (a <= 9) hexByte = a.ToString(); else { switch (a) { case 10: hexByte = "A"; break; case 11: hexByte = "B"; break; case 12: hexByte = "C"; break; case 13: hexByte = "D"; break; case 14: hexByte = "E"; break; case 15: hexByte = "F"; break; } } hexTotal = String.Concat(hexByte, hexTotal); } return hexTotal; } public void LRCheck(byte[] code) { int sum = 0; foreach (byte b in code) { sum += b; } sum = sum % 255;//取模FF(255) sum = ~sum + 1;//取反+1 string lrc = Convert.ToString(sum, 16); return lrc; }
自定義Modbus數據表
自定義Modbus數據表例子:
設備相關讀取信息:
命令報文信息解析:
自定義Modbus數據表定義注意
串口調試工具
串口調試工具的使用.
串口調試工具 + RS485 就可以讀取硬件上的數據,和向硬件請求了,如何使用請看“調試篇”會有詳細的說明。
網絡調試助手:
調試助手主要還是TCP協議通訊的一個調試工具
-
以太網
+關注
關注
40文章
5427瀏覽量
171776 -
MODBUS
+關注
關注
28文章
1808瀏覽量
77028 -
設備
+關注
關注
2文章
4515瀏覽量
70660 -
電子控制器
+關注
關注
0文章
40瀏覽量
7354
發布評論請先 登錄
相關推薦
評論