Modbus通讯协议学习 - 认识篇

MODBUS协议整理——汇总
https://blog.csdn.net/xukai871105/article/details/16368615

ModBus
https://baike.sogou.com/v7562947.htm?fromTitle=ModBus

Modbus通讯协议学习 - 认识篇
https://blog.csdn.net/xiaoluoshan/article/details/73233955

Modbus协议———常用功能码详解
http://www.cnblogs.com/luomingui/archive/2013/06/14/Modbus.html

Modbus协议详解与实战分析
https://mp.weixin.qq.com/s?src=11×tamp=1538828737&ver=1166&signature=j-bas9TJSbHnOe5UFqlOKCU4NmPoFIN8Bxfrn1FmNMyG0Msjcf861LsxprN-KFMCR*OZ96p6y2IIuCKhGu4yAPTDjm94tmbqjO66RPoXjIaJEsWilULnJ5NTSXmhhhLj&new=1

其实Modbus通讯很简单手把手教你
http://www.360doc.com/content/17/1204/04/49530759_709669949.shtml

//======================================================================//

01H-读线圈状态
1)描述:读从机线圈寄存器,位操作,可读单个或者多个;
2)发送指令:
假设从机地址位0x01,寄存器开始地址0x0023,寄存器结束抵制0x0038,总共读取21个线圈。协议图如下:
Modbus通讯协议学习 - 认识篇_第1张图片

3)响应:
返回数据的每一位对应线圈状态,1-ON,0-OFF,如下图;
在这里插入图片描述
上表中data1表示0x0023-0x002a的线圈状态,data1的最低位代表最低地址的线圈状态,可以理解为小端模式;
在这里插入图片描述

data2表示地址0x002b-0x0033的线圈状态,如下表:
在这里插入图片描述

data3表示地址0x0034-0x0038的线圈状态,不够8位,字节高位填充为0,如下表:
在这里插入图片描述

02H-读离散输入状态
1):读离散输入寄存器,位操作,可读单个或多个,协议类似功能码0X01协议,此处省;

03H-读保持寄存器
1)描述:读保持寄存器,字节指令操作,可读单个或者多个;
2)发送指令:
从机地址0x01,保持寄存器起始地址0x0032,读2个保持寄存器
Modbus通讯协议学习 - 认识篇_第2张图片

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

数据存储顺序
在这里插入图片描述

04H-读输入寄存器

1)描述:读输入寄存器,字节指令操作,可读单个或者多个;
2)发送指令:同03H;
3)响应:同03H;

05H-写单个线圈

1)描述:写单个线圈,位操作,只能写一个,写0xff00表示设置线圈状态为ON,写0x0000表示设置线圈状态为OFF
2)发送指令:
设置0x0032线圈为ON;
Modbus通讯协议学习 - 认识篇_第4张图片

3)响应:
同发送指令;

06H-写单个保持寄存器

1)描述:写单个保持寄存器,字节指令操作,只能写一个;
2)发送指令:
写0x0032保持寄存器为0x1232;
Modbus通讯协议学习 - 认识篇_第5张图片
3)响应:同发送指令;

0FH-写多个线圈

1)描述:写多个线圈寄存器。若数据区的某位值为“1”表示被请求的相应线圈状态为ON,若某位值为“0”,则为状态为OFF。
2)发送指令:
线圈地址为0x04a5,写12个线圈,
Modbus通讯协议学习 - 认识篇_第6张图片
上图中DATA1为0x0c,表示:
Modbus通讯协议学习 - 认识篇_第7张图片
DATA2为0x02,不够8位,字节高位填充0:
Modbus通讯协议学习 - 认识篇_第8张图片
3)响应:
Modbus通讯协议学习 - 认识篇_第9张图片

10H-写多个保持寄存器

1)描述:写多个保持寄存器,字节指令操作,可写多个;
2)发送指令:
保持寄存器起始地址为0x0034,写2个寄存器4个字节的数据;
Modbus通讯协议学习 - 认识篇_第10张图片
3)响应:
Modbus通讯协议学习 - 认识篇_第11张图片

//================================================================================//

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

Modbus 是一个请求/应答协议

Modbus

以下是要分解的Modbus热图
Modbus通讯协议学习 - 认识篇_第12张图片

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

Modbus消息帧
了解了它,会使你对串口通信有一个清晰的认识!
Modbus通讯协议学习 - 认识篇_第15张图片

通用消息帧
Modbus通讯协议学习 - 认识篇_第16张图片

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

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

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

每个字节的位

1个起始位

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

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

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

错误检测域

LRC(纵向冗长检测)

在这里插入图片描述
Modbus通讯协议学习 - 认识篇_第17张图片

RTU消息帧

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

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

每个字节的位

1个起始位

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

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

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

错误检测域

CRC(循环冗长检测)
在这里插入图片描述
Modbus通讯协议学习 - 认识篇_第18张图片

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通讯协议学习 - 认识篇_第19张图片

命令报文信息解析:
Modbus通讯协议学习 - 认识篇_第20张图片
自定义Modbus数据表定义注意

串口调试工具
串口调试工具的使用.
Modbus通讯协议学习 - 认识篇_第21张图片

串口调试工具 + RS485 就可以读取硬件上的数据,和向硬件请求了,如何使用请看“调试篇”会有详细的说明。
Modbus通讯协议学习 - 认识篇_第22张图片
Modbus通讯协议学习 - 认识篇_第23张图片

网络调试助手:

   调试助手主要还是TCP协议通讯的一个调试工具
   ![在这里插入图片描述](https://img-blog.csdn.net/20181006152554131?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE4NTQ3ODk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

你可能感兴趣的:(c#)