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(縱向冗長檢測)

RTU消息幀

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

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

每個字節的位

1個起始位

8個數據位,最小的有效位先發送

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

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

錯誤檢測域

CRC(循環冗長檢測)

 

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 == 0return"";

            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, 256out ys);

                tmp = tmp.Insert(0string.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數據表定義注意

 

串口調試工具

 

串口調試工具的使用.

 

串口調試工具 + RS485  就可以讀取硬件上的數據,和向硬件請求了,如何使用請看“調試篇”會有詳細的說明。

 

網絡調試助手:

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章