Modbus 協(xié)議是應(yīng)用于電子控制器上的一種通用語(yǔ)言。通過(guò)此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)(例如以太網(wǎng))和其它設(shè)備之間可以通信。Modbus 協(xié)議定義了一個(gè)控制器能認(rèn)識(shí)使用的消息結(jié)構(gòu),而不管它們是經(jīng)過(guò)何種網(wǎng)絡(luò)進(jìn)行通信的。它描述了一控制器請(qǐng)求訪問(wèn)其它設(shè)備的過(guò)程,如果回應(yīng)來(lái)自其它設(shè)備的請(qǐng)求,以及怎樣偵測(cè)錯(cuò)誤并記錄。它制定了消息域格局和內(nèi)容的公共格式。
Modbus 是一個(gè)請(qǐng)求/應(yīng)答協(xié)議
Modbus
以下是要分解的Modbus熱圖
Modbus消息幀
了解了它,會(huì)使你對(duì)串口通信有一個(gè)清晰的認(rèn)識(shí)!
通用消息幀
ASCII消息幀 (在消息中的每個(gè)8Bit 字節(jié)都作為兩個(gè)ASCII字符發(fā)送)
十六進(jìn)制,ASCII字符0...9,A...F
消息中的每個(gè)ASCII字符都是一個(gè)十六進(jìn)制字符組成
每個(gè)字節(jié)的位
1個(gè)起始位
n個(gè)數(shù)據(jù)位,最小的有效位先發(fā)送
1個(gè)奇偶校驗(yàn)位,無(wú)校驗(yàn)則無(wú)
1個(gè)停止位(有校驗(yàn)時(shí)),2個(gè)Bit(無(wú)校驗(yàn)時(shí))
錯(cuò)誤檢測(cè)域
LRC(縱向冗長(zhǎng)檢測(cè))
RTU消息幀
8位二進(jìn)制,十六進(jìn)制數(shù)0...9,A...F
消息中的每個(gè)8位域都是一個(gè)兩個(gè)十六進(jìn)制字符組成
每個(gè)字節(jié)的位
1個(gè)起始位
8個(gè)數(shù)據(jù)位,最小的有效位先發(fā)送
1個(gè)奇偶校驗(yàn)位,無(wú)校驗(yàn)則無(wú)
1個(gè)停止位(有校驗(yàn)時(shí)),2個(gè)Bit(無(wú)校驗(yàn)時(shí))
錯(cuò)誤檢測(cè)域
CRC(循環(huán)冗長(zhǎng)檢測(cè))
CRC校驗(yàn)
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校驗(yàn)(累加和)
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" 無(wú)論何時(shí),都是兩位數(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校驗(yàn)(LRC錯(cuò)誤校驗(yàn)用于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)讀取信息:
命令報(bào)文信息解析:
自定義Modbus數(shù)據(jù)表定義注意
串口調(diào)試工具
串口調(diào)試工具的使用.
串口調(diào)試工具 + RS485 就可以讀取硬件上的數(shù)據(jù),和向硬件請(qǐng)求了,如何使用請(qǐng)看“調(diào)試篇”會(huì)有詳細(xì)的說(shuō)明。
網(wǎng)絡(luò)調(diào)試助手:
調(diào)試助手主要還是TCP協(xié)議通訊的一個(gè)調(diào)試工具
-
以太網(wǎng)
+關(guān)注
關(guān)注
40文章
5426瀏覽量
171740 -
MODBUS
+關(guān)注
關(guān)注
28文章
1805瀏覽量
77011 -
設(shè)備
+關(guān)注
關(guān)注
2文章
4509瀏覽量
70645 -
電子控制器
+關(guān)注
關(guān)注
0文章
40瀏覽量
7349
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論