1.什麼是Modbus?數組
Modbus協議是應用於電子控制器上的一種通用語言。經過此協議,控制器相互之間,控制器經由網絡(例如以太網)和其它設備之間能夠通訊。Modbus協議定義了一個控制器能認識使用的消息結構,而無論他們是通過何種網絡進行通訊的。它描述了一個控制器請求訪問其餘設備的過程,若是迴應來自其餘設備的請求,以及怎樣偵測錯誤並記錄。它制定了消息域格局和內容的公共格式。網絡
Modbus是一個請求/應答協議。工具
如下是要分解的Modbus熱圖spa
Modbus消息幀計算機網絡
瞭解了它,會使你對串口有一個清晰的認識!3d
通用消息幀調試
ASCII消息幀(在消息中的每一個8Bit字節都做爲兩個ASCII字符發送)code
十六進制,ASCII字符0...9,A...Form
消息中的每一個ASCII字符都是一個十六進制字符組成htm
每一個字節的位
1個起始位
n個數據位,最小的有效位先發送
1個奇偶校驗位,無校驗則無
1箇中止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
LRC(縱向冗長檢測)
RTU消息幀
8位二進制,十六進制數0...9,A...F
消息中的每一個8位域都是一個兩個十六進制字符組成
每一個字節的位
1個起始位
8個數據位,最小的有效位先發送
1個奇偶校驗位,無校驗則無
1箇中止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
CRC(循環冗長檢測)
CRC校驗(http://baike.baidu.com/view/1664507.htm)
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)); } /// <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 + 2]; for (int i = 0; i < temp.Length; i++) { b[i] = Convert.ToByte(temp[i], 16); } 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(); }
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); } /// <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 = 0; i < temp.Length; i++) { if (temp[i].Length > 0) b[i] = Convert.ToByte(temp[i], 16); } 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 == 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模式)
/// <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 = 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協議通信的一個調試工具
在遠程通訊和計算機科學中,串行通訊(英語:Serial communication)是指在計算機總線或其餘數據信道上,每次傳輸一個比特數據,並連續進行以上單次過程的通訊方式。與之對應的是並行通訊,它在串行端口上經過一次同時傳輸若干比特數據的方式進行通訊。串行通訊被用於長距離通訊以及大多數計算機網絡,在這些應用場合裏,電纜和同步化使並行通訊實際應用面臨困難。憑藉着其改善的信號完整性和傳播速度,串行通訊總線正在變得愈來愈廣泛,甚至在短程距離的應用中,其優越性已經開始超越並行總線不須要串行化組件(serializer),並解決了諸如時鐘偏移(Clock skew)、互聯密度(interconnect density)等缺點。PCI到PCI Express的升級就一個例子。