天天看點

Modbus通訊協定學習

Modbus通訊協定學習

什麼是Modbus?

Modbus 協定是應用于電子控制器上的一種通用語言。通過此協定,控制器互相之間、控制器經由網絡(例如以太網)和其它裝置之間可以通信。Modbus 協定定義了一個控制器能認識使用的消息結構,而不管它們是經過何種網絡進行通信的。它描述了一控制器請求通路其它裝置的過程,如果回應來自其它裝置的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和内容的公共格式。

Modbus 是一個請求/應答協定

Modbus

以下是要分解的Modbus熱圖

Modbus通訊協定學習

Modbus消息幀

了解了它,會使你對序列槽通信有一個清晰的認識!

Modbus通訊協定學習

通用消息幀

Modbus通訊協定學習

ASCII消息幀 (在消息中的每個8Bit 位元組都作為兩個ASCII字元發送)

十六進制,ASCII字元0...9,A...F

消息中的每個ASCII字元都是一個十六進制字元組成

每個位元組的位

1個起始位

n個資料位,最小的有效位先發送

1個奇偶校驗位,無校驗則無

1個停止位(有校驗時),2個Bit(無校驗時)

錯誤檢測域

LRC(縱向冗長檢測)

Modbus通訊協定學習
Modbus通訊協定學習

RTU消息幀

8位二進制,十六進制數0...9,A...F

消息中的每個8位域都是一個兩個十六進制字元組成

每個位元組的位

1個起始位

8個資料位,最小的有效位先發送

1個奇偶校驗位,無校驗則無

1個停止位(有校驗時),2個Bit(無校驗時)

錯誤檢測域

CRC(循環冗長檢測)

Modbus通訊協定學習
Modbus通訊協定學習
public  static string CRCCheck(string val)
        
            string hexString = string.Empty;
             val = val.TrimEnd('');
            string[] spva = val.Split('');
            byte[] bufData = newbyte[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;
                    }
                }
            }
            byte[] bytes = System.BitConverter.GetBytes(CRC));
            
            if (bytes != null)
             {
                 StringBuilder strB = new StringBuilder();                for (int i = 0; i < bytes.Length; i++)
                 {
                     strB.Append(bytes[i].ToString("X2"));
                 }
                 hexString = strB.ToString();
             }
             return hexString;        
         ///<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>
         publicstaticbyte[] ToBytesCRC(string hex)
        
            string[] temp = hex.Split('');
            byte[] b =  newbyte[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>
         publicstatic String ToHex(byte[] vars)
        
            return BitConverter.ToString(vars).Replace('-', '').Trim();
        

CS校驗(累加和)

publicstaticstring 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>
         publicstaticbyte[] ToBytes(string hex)
       
            string[] temp = hex.Split('');
            byte[] b =  newbyte[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>
         publicstaticstring ToHex(intvar)
        
            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();
        
         publicstaticstring 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>
         publicstaticstring LRCheck(string writeUncheck)
        
            char[] hexArray = newchar[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);
 
                elseif ((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)
                    {
                        case10:
                            hexByte = "A";
                            break;
                        case11:
                            hexByte = "B";
                            break;
                        case12:
                            hexByte = "C";
                            break;
                        case13:
                            hexByte = "D";
                            break;
                        case14:
                            hexByte = "E";
                            break;
                        case15:
                            hexByte = "F";
                            break;
                  
                }
                hexTotal = String.Concat(hexByte, hexTotal);
            }
            return hexTotal;
        
 
         publicvoid 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通訊協定學習

指令封包資訊解析:

Modbus通訊協定學習

自定義Modbus資料表定義注意

序列槽調試工具

序列槽調試工具的使用.

Modbus通訊協定學習

序列槽調試工具 + RS485  就可以讀取硬體上的資料,和向硬體請求了,如何使用請看“調試篇”會有詳細的說明。

​​

Modbus通訊協定學習
Modbus通訊協定學習

​​

網絡調試助手:

       調試助手主要還是TCP協定通訊的一個調試工具