Modbus通讯协议学习

Modbus通讯协议学习
 
什么是Modbus

 

Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。Modbus 协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式

Modbus 是一个请求/应答协议

Modbus

以下是要分解的Modbus热图

 

Modbus通讯协议学习_第1张图片

Modbus消息帧

 

了解了它,会使你对串口通信有一个清晰的认识!

Modbus通讯协议学习_第2张图片

通用消息帧

 

Modbus通讯协议学习_第3张图片

ASCII消息帧 (在消息中的每个8Bit 字节都作为两个ASCII字符发送)

十六进制,ASCII字符0...9A...F

消息中的每个ASCII字符都是一个十六进制字符组成

每个字节的位

1个起始位

n个数据位,最小的有效位先发送

1个奇偶校验位,无校验则无

1个停止位(有校验时),2Bit(无校验时)

错误检测域

LRC(纵向冗长检测)

Modbus通讯协议学习_第4张图片

RTU消息帧

8位二进制,十六进制数0...9A...F

消息中的每个8位域都是一个两个十六进制字符组成

每个字节的位

1个起始位

8个数据位,最小的有效位先发送

1个奇偶校验位,无校验则无

1个停止位(有校验时),2Bit(无校验时)

错误检测域

CRC(循环冗长检测)

Modbus通讯协议学习_第5张图片

 

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;

        }

        ///

        ///例如把如下字符串转换成字节数组

        /// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB   转换为字节数组

        ///

        ///十六进制字符串

        ///

        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;

        }

        ///

        ///将字节数据转换为十六进制字符串,中间用 “ ”分割如:AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB

        ///

        ///要转换的字节数组

        ///

        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);

        }

        ///

        /// AB CD 12 3B     转换为字节数组

        ///

        ///十六进制字符串

        ///

        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;

        }

        ///

        ///转换为符合本程序的十六进制格式

        ///

        ///1 2 3 等。

        ///返回十六进制字符串,如果是1-9的话,前面带零

        ///例如: 5  ="05"  12 ="0C" 无论何时,都是两位数。 

        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模式)

///

        ///取模FF(255)

        ///取反+1

        ///

        ///

        ///

        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通讯协议学习_第6张图片

命令报文信息解析:

Modbus通讯协议学习_第7张图片

自定义Modbus数据表定义注意

 

串口调试工具

 

串口调试工具的使用.

 Modbus通讯协议学习_第8张图片

串口调试工具 + RS485  就可以读取硬件上的数据,和向硬件请求了,如何使用请看调试篇会有详细的说明。

 

Modbus通讯协议学习_第9张图片Modbus通讯协议学习_第10张图片

网络调试助手:

       调试助手主要还是TCP协议通讯的一个调试工具

 

 Modbus通讯协议学习_第11张图片

你可能感兴趣的:(C#,c#,串口通信,modbus,二进制,crc)