Modbus通讯协议学习 - 认识篇

什么是Modbus?

 

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

Modbus 是一个请求/应答协议

Modbus

以下是要分解的Modbus热图

 Modbus通讯协议学习 - 认识篇_第1张图片

 

Modbus消息帧

 

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

Modbus通讯协议学习 - 认识篇_第2张图片

通用消息帧

Modbus通讯协议学习 - 认识篇_第3张图片

 

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

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

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

每个字节的位

1个起始位

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

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

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

错误检测域

LRC(纵向冗长检测)

ASCII消息帧

位顺序(ASCII)

RTU消息帧

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

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

每个字节的位

1个起始位

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

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

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

错误检测域

CRC(循环冗长检测)

RTU消息帧

位顺序(RTU)

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));
        }
        /// 
        /// 例如把如下字符串转换成字节数组
        /// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB   转换为字节数组
        /// 
        /// 十六进制字符串
        /// 
        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;
        }
        /// 
        /// 将字节数据转换为十六进制字符串,中间用 “ ”分割 如:AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB
        /// 
        /// 要转换的字节数组
        /// 
        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);
        }
        /// 
        /// AB CD 12 3B     转换为字节数组
        /// 
        /// 十六进制字符串
        /// 
        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;
        }
        /// 
        /// 转换为符合本程序的十六进制格式
        /// 
        /// 1 2 3 等。
        /// 返回十六进制字符串,如果是1-9的话,前面带零
        /// 例如: 5  ="05"  12 ="0C" 无论何时,都是两位数。  
        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模式)

/// 
        /// 取模FF(255)
        /// 取反+1
        /// 
        /// 
        /// 
        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通讯协议学习 - 认识篇_第4张图片

命令报文信息解析:

Modbus通讯协议学习 - 认识篇_第5张图片

自定义Modbus数据表定义注意

 

串口调试工具

 

串口调试工具的使用.

Modbus通讯协议学习 - 认识篇_第6张图片

 

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

Modbus通讯协议学习 - 认识篇_第7张图片 Modbus通讯协议学习 - 认识篇_第8张图片

网络调试助手:

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

 Modbus通讯协议学习 - 认识篇_第9张图片

你可能感兴趣的:(Modbus通讯协议学习 - 认识篇)