Modbus通信协议 【 初识 Modbus】
?
Modbus協(xié)議
? ? Modbus 協(xié)議是應(yīng)用于電子控制器上的一種通用語言。通過此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)(例如以太網(wǎng))和其它設(shè)備之間可以通信。它已經(jīng)成為一通用工業(yè)標(biāo)準(zhǔn)。有了它,不同廠商生產(chǎn)的控制設(shè)備可以連成工業(yè)網(wǎng)絡(luò),進行集中監(jiān)控。?
? ? ? ? 此協(xié)議定義了一個控制器能認(rèn)識使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡(luò)進行通信的。它描述了一控制器請求訪問其它設(shè)備的過程,如果回應(yīng)來自其它設(shè)備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內(nèi)容的公共格式。?
? ?Modbus 是一個請求/應(yīng)答協(xié)議,當(dāng)在一Modbus網(wǎng)絡(luò)上通信時,此協(xié)議決定了每個控制器須要知道它們的設(shè)備地址,識別按地址發(fā)來的消息,決定要產(chǎn)生何種行動。如果需要回應(yīng),控制器將生成反饋信息并用Modbus協(xié)議發(fā)出。在其它網(wǎng)絡(luò)上,包含了Modbus協(xié)議的消息轉(zhuǎn)換為在此網(wǎng)絡(luò)上使用的幀或包結(jié)構(gòu)。這種轉(zhuǎn)換也擴展了根據(jù)具體的網(wǎng)絡(luò)解決節(jié)地址、路由路徑及錯誤檢測的方法。
?Modbus熱圖
?
?
?Modbus消息幀
?
了解了它,會使你對串口通信有一個清晰的認(rèn)識!
通用消息幀
?
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));}/// <summary>/// 例如把如下字符串轉(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ù)組/// </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>/// 將字節(jié)數(shù)據(jù)轉(zhuǎn)換為十六進制字符串,中間用 “ ”分割 如: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">要轉(zhuǎn)換的字節(jié)數(shù)組</param>/// <returns></returns>public static String ToHex(byte[] vars){return BitConverter.ToString(vars).Replace('-', ' ').Trim();} CRC校驗?
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 轉(zhuǎn)換為字節(jié)數(shù)組/// </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>/// 轉(zhuǎn)換為符合本程序的十六進制格式/// </summary>/// <param name="var">1 2 3 等。</param>/// <returns>返回十六進制字符串,如果是1-9的話,前面帶零</returns>/// <example>例如: 5 ="05" 12 ="0C" 無論何時,都是兩位數(shù)。 </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);} CS校驗(累加和)?
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;//取反+1string lrc = Convert.ToString(sum, 16);return lrc;} LRC校驗(LRC錯誤校驗用于ASCII模式)?
?
?
自定義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)試工具
?
?
https://www.cnblogs.com/luomingui/archive/2013/06/14/Modbus.html#top
?
轉(zhuǎn)載于:https://www.cnblogs.com/Tanghongchang/p/9370004.html
總結(jié)
以上是生活随笔為你收集整理的Modbus通信协议 【 初识 Modbus】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rinetd 进行转发
- 下一篇: JDK源码分析(三)——HashMap