Modbus 協(xié)議是應用于電子控制器上的一種通用語言。通過此協(xié)議,控制器相互之間、控制器經由網絡(例如以太網)和其它設備之間可以通信。Modbus 協(xié)議定義了一個控制器能認識使用的消息結構,而不管它們是經過何種網絡進行通信的。它描述了一控制器請求訪問其它設備的過程,如果回應來自其它設備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內容的公共格式。
Modbus 是一個請求/應答協(xié)議
Modbus
以下是要分解的Modbus熱圖
Modbus消息幀
了解了它,會使你對串口通信有一個清晰的認識!
通用消息幀
ASCII消息幀 (在消息中的每個8Bit 字節(jié)都作為兩個ASCII字符發(fā)送)
十六進制,ASCII字符0...9,A...F
消息中的每個ASCII字符都是一個十六進制字符組成
每個字節(jié)的位
1個起始位
n個數(shù)據(jù)位,最小的有效位先發(fā)送
1個奇偶校驗位,無校驗則無
1個停止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
LRC(縱向冗長檢測)
RTU消息幀
8位二進制,十六進制數(shù)0...9,A...F
消息中的每個8位域都是一個兩個十六進制字符組成
每個字節(jié)的位
1個起始位
8個數(shù)據(jù)位,最小的有效位先發(fā)送
1個奇偶校驗位,無校驗則無
1個停止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
CRC(循環(huán)冗長檢測)
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)); } /// /// 例如把如下字符串轉換成字節(jié)數(shù)組 /// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB 轉換為字節(jié)數(shù)組 /// /// 十六進制字符串 /// 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; } /// /// 將字節(jié)數(shù)據(jù)轉換為十六進制字符串,中間用 “ ”分割 如:AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB /// /// 要轉換的字節(jié)數(shù)組 /// 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 轉換為字節(jié)數(shù)組 /// /// 十六進制字符串 /// 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" 無論何時,都是兩位數(shù)。 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數(shù)據(jù)表
自定義Modbus數(shù)據(jù)表例子:
設備相關讀取信息:
命令報文信息解析:
自定義Modbus數(shù)據(jù)表定義注意
串口調試工具
串口調試工具的使用.
串口調試工具 + RS485 就可以讀取硬件上的數(shù)據(jù),和向硬件請求了,如何使用請看“調試篇”會有詳細的說明。
網絡調試助手:
調試助手主要還是TCP協(xié)議通訊的一個調試工具
-
以太網
+關注
關注
40文章
5465瀏覽量
172837 -
MODBUS
+關注
關注
28文章
1825瀏覽量
77358 -
設備
+關注
關注
2文章
4552瀏覽量
70905 -
電子控制器
+關注
關注
0文章
40瀏覽量
7392
發(fā)布評論請先 登錄
相關推薦
什么是Modbus通訊協(xié)議?Modbus通訊協(xié)議有什么特點?
基于LabVIEW的Modbus串口通訊協(xié)議的實現(xiàn)
ModBus通訊協(xié)議簡介
Modbus通訊協(xié)議的幾種實現(xiàn)方式
MODBUS通訊協(xié)議及編程
基于C++的modbus通訊協(xié)議模型實現(xiàn)
Modbus通訊協(xié)議的原理和標準
解讀Modbus通訊協(xié)議
Modbus通訊協(xié)議的詳細資料講解
![<b class='flag-5'>Modbus</b><b class='flag-5'>通訊</b><b class='flag-5'>協(xié)議</b>的詳細資料講解](https://file.elecfans.com/web1/M00/D1/28/o4YBAF_AxdCACbNUAACEJlZwcdI115.png)
評論