Modbus 協(xié)議是應(yīng)用于電子控制器上的一種通用語言。通過此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)(例如以太網(wǎng))和其它設(shè)備之間可以通信。Modbus 協(xié)議定義了一個控制器能認(rèn)識使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡(luò)進(jìn)行通信的。它描述了一控制器請求訪問其它設(shè)備的過程,如果回應(yīng)來自其它設(shè)備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內(nèi)容的公共格式。
Modbus 是一個請求/應(yīng)答協(xié)議
Modbus
以下是要分解的Modbus熱圖
Modbus消息幀
了解了它,會使你對串口通信有一個清晰的認(rèn)識!
通用消息幀
ASCII消息幀 (在消息中的每個8Bit 字節(jié)都作為兩個ASCII字符發(fā)送)
十六進(jìn)制,ASCII字符0...9,A...F
消息中的每個ASCII字符都是一個十六進(jìn)制字符組成
每個字節(jié)的位
1個起始位
n個數(shù)據(jù)位,最小的有效位先發(fā)送
1個奇偶校驗位,無校驗則無
1個停止位(有校驗時),2個Bit(無校驗時)
錯誤檢測域
LRC(縱向冗長檢測)
RTU消息幀
8位二進(jìn)制,十六進(jìn)制數(shù)0...9,A...F
消息中的每個8位域都是一個兩個十六進(jìn)制字符組成
每個字節(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)); } /// /// 例如把如下字符串轉(zhuǎn)換成字節(jié)數(shù)組 /// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB 轉(zhuǎn)換為字節(jié)數(shù)組 /// /// 十六進(jìn)制字符串 /// 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ù)轉(zhuǎn)換為十六進(jìn)制字符串,中間用 “ ”分割 如:AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB /// /// 要轉(zhuǎn)換的字節(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 轉(zhuǎn)換為字節(jié)數(shù)組 /// /// 十六進(jìn)制字符串 /// 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; } /// /// 轉(zhuǎn)換為符合本程序的十六進(jìn)制格式 /// /// 1 2 3 等。 /// 返回十六進(jìn)制字符串,如果是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ù)表例子:
設(shè)備相關(guān)讀取信息:
命令報文信息解析:
自定義Modbus數(shù)據(jù)表定義注意
串口調(diào)試工具
串口調(diào)試工具的使用.
串口調(diào)試工具 + RS485 就可以讀取硬件上的數(shù)據(jù),和向硬件請求了,如何使用請看“調(diào)試篇”會有詳細(xì)的說明。
網(wǎng)絡(luò)調(diào)試助手:
調(diào)試助手主要還是TCP協(xié)議通訊的一個調(diào)試工具
-
以太網(wǎng)
+關(guān)注
關(guān)注
40文章
5288瀏覽量
169672 -
MODBUS
+關(guān)注
關(guān)注
28文章
1718瀏覽量
76423 -
設(shè)備
+關(guān)注
關(guān)注
2文章
4349瀏覽量
70275 -
電子控制器
+關(guān)注
關(guān)注
0文章
35瀏覽量
7301
發(fā)布評論請先 登錄
相關(guān)推薦
評論