認識Modbus協議

1.什麼是Modbus?數組

  Modbus協議是應用於電子控制器上的一種通用語言。經過此協議,控制器相互之間,控制器經由網絡(例如以太網)和其它設備之間能夠通訊。Modbus協議定義了一個控制器能認識使用的消息結構,而無論他們是通過何種網絡進行通訊的。它描述了一個控制器請求訪問其餘設備的過程,若是迴應來自其餘設備的請求,以及怎樣偵測錯誤並記錄。它制定了消息域格局和內容的公共格式。網絡

Modbus是一個請求/應答協議。工具

如下是要分解的Modbus熱圖spa

Modbus消息幀計算機網絡

瞭解了它,會使你對串口有一個清晰的認識!3d

通用消息幀調試

ASCII消息幀(在消息中的每一個8Bit字節都做爲兩個ASCII字符發送)code

十六進制,ASCII字符0...9,A...Form

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

每一個字節的位

1個起始位

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

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

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

錯誤檢測域

LRC(縱向冗長檢測)

RTU消息幀

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

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

每一個字節的位

1個起始位

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

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

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

錯誤檢測域

CRC(循環冗長檢測)

CRC校驗(http://baike.baidu.com/view/1664507.htm)

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>
        /// 例如把以下字符串轉換成字節數組
        /// 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>
        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>
        /// 將字節數據轉換爲十六進制字符串,中間用 「 」分割 如: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>
        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);
        }
        /// <summary>
        /// AB CD 12 3B     轉換爲字節數組
        /// </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>
        /// 轉換爲符合本程序的十六進制格式
        /// </summary>
        /// <param name="var">1 2 3 等。</param>
        /// <returns>返回十六進制字符串,若是是1-9的話,前面帶零</returns>
        /// <example>例如: 5  ="05"  12 ="0C" 不管什麼時候,都是兩位數。  </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);
        }

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;//取反+1
            string lrc = Convert.ToString(sum, 16);
            return lrc;
        }

自定義Modbus數據表

自定義Modbus數據表例子:

設備相關讀取信息:

命令報文信息解析:

自定義Modbus數據表定義注意

串口調試工具

串口調試工具的使用

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

網絡調試助手:

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

 在遠程通訊計算機科學中,串行通訊英語:Serial communication)是指在計算機總線或其餘數據信道上,每次傳輸一個比特數據,並連續進行以上單次過程的通訊方式。與之對應的是並行通訊,它在串行端口上經過一次同時傳輸若干比特數據的方式進行通訊。串行通訊被用於長距離通訊以及大多數計算機網絡,在這些應用場合裏,電纜和同步化使並行通訊實際應用面臨困難。憑藉着其改善的信號完整性和傳播速度,串行通訊總線正在變得愈來愈廣泛,甚至在短程距離的應用中,其優越性已經開始超越並行總線不須要串行化組件(serializer),並解決了諸如時鐘偏移Clock skew)、互聯密度(interconnect density)等缺點。PCIPCI Express的升級就一個例子。

相關文章
相關標籤/搜索