当前位置:   article > 正文

工控 modbusTCP 报文

工控 modbusTCP 报文

在这里插入图片描述

在这里插入图片描述

Tx 发送报文:00 C9 00 00 00 06 01 03 00 00 00 02
Rx 接收报文:00 C9 00 00 00 07 01 03 04 01 4D 00 01

Tx 发送报文:00 C9 00 00 00 06 01 03 00 00 00 02
00 C9 事务处理标识符 2字节
00 00 协议标识符 2字节 固定 00 00
00 06 长度 2字节 表示之后的字节总数 (01 03 00 00 00 02 6个字节)
01 单元标识符 Unit ID 1字节
00 C9 00 00 00 06 01 合起来就是 MPAP报文头

03 功能码 1字节
00 00 00 02 数据部分

00 00 开始地址 2个字节
00 02 数据的长度 2个字节, 此处是读取2个寄存器

Rx 接收报文:00 C9 00 00 00 07 01 03 04 01 4D 00 01

00 C9 事务处理标识符 2字节
00 00 协议标识符 2字节 固定 00 00
00 07 长度 2字节 表示之后的字节总数 ( 01 03 04 01 4D 00 01 7个字节)
01 单元标识符 Unit ID 1字节
00 C9 00 00 00 07 01 合起来就是 MPAP报文头

03 功能码 1字节
04 01 4D 00 01 数据部分

04 字节数 1个字节 2个寄存器 占4个字节
01 4D 数据1
00 01 数据2
在这里插入图片描述

在这里插入图片描述
保持寄存器的值可以读取也可以修改,而输入寄存器的值对于master来说就只能读取。所谓保持寄存器,指的是可以通过通信命令读或者写的寄存器;通常是一些功能控制寄存器或者输出寄存器等。

 public class ModBusTCP
 {
     public  int ushorts2int(ushort[] res)
     {
         int high = res[0];
         int low = res[1];
         int value = (high << 16) + low;
         return value;
     }

     public  ushort[] int2ushorts(int res)
     {
         ushort ust1 = (ushort)(res >> 16);
         ushort ust2 = (ushort)res;          
         return new ushort[] { ust1, ust2 };
     }
     //声明一个Socket对象
     private Socket tcpClient;
     //单元标识符
     public byte SlaveId { get; set; } = 0x01;
     /// <summary>
     /// 建立连接
     /// </summary>
     /// <param name="ip">IP地址  </param>
     /// <param name="port">端口号</param>
     /// <returns></returns>
     public bool Connect(string ip, int port)
     { 
         //实例化Socket对象
         tcpClient =new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
         try
         {
             //建立连接   三次握手
             tcpClient.Connect(IPAddress.Parse(ip), port);
             return true;
         }
         catch (Exception)
         {

            return false;
         }
       
     }
     /// <summary>
     /// 断开连接
     /// </summary>
     public void DisConnect() 
     { 
         //  4次握手
         tcpClient?.Close();
     }
     /// <summary>
     /// 读取多个数据
     /// </summary>
     /// <param name="startAdr"></param>
     /// <param name="length"></param>
     /// <returns></returns>
     public byte[] ReadOutputRegisters(ushort startAdr, ushort length) 
     {
         #region 1 拼接报文
         
         List<byte> SendCommand = new List<byte>();
         //ModBusTCP 报文 格式     MBAP  + 功能码+  数据部分
         // MBAP  事务标识符(2字节) 协议标识符(2字节) 长度(2字节) 单元标识符(1字节)
         // 功能码 (1字节)
         // 数据部分  起始寄存器地址(2字节)   寄存器长度(2字节) 
         //=======================报文拼接===============================
         //事务标识符  设置固定  0x00 0x00
         // 等价 SendCommand.Add(0x00); SendCommand.Add(0x00);
         SendCommand.AddRange(new byte[] { 0x00, 0x00 });

         // 协议标识符  设置固定  0x00 0x00
         SendCommand.AddRange(new byte[] { 0x00, 0x00 });

         // 长度  
         SendCommand.AddRange(new byte[] {0x00,0x06});

         // 单元标识符 1字节
         SendCommand.Add(SlaveId);

         //功能码  固定 0x03
         SendCommand.Add(0x03);
         //数据部分 起始寄存器地址(2字节)
         #region ushort 转换字节数组
         //  %  /
         //byte Hbyte = (byte)(startAdr / 255);
         //byte Lbyte = (byte)(startAdr % 255);
         //SendCommand.AddRange(new byte[] { Hbyte,Lbyte});
         #endregion
         //BitConverter 大小端是颠倒
         byte[] temp = BitConverter.GetBytes(startAdr);
         SendCommand.AddRange(new byte[] { temp[1], temp[0] });
         //数据部分 寄存器长度(2字节)
         temp = BitConverter.GetBytes(length);
         SendCommand.AddRange(new byte[] { temp[1], temp[0] });
         #endregion
         #region 2 发送报文
         tcpClient.Send(SendCommand.ToArray());
         #endregion
         #region 3 接收报文
         Thread.Sleep(50);
         int count = tcpClient.Available;
         byte[] buffer= new byte[count];
         tcpClient.Receive(buffer,buffer.Length,SocketFlags.None);
         #endregion
         #region 4 验证报文
         //Tx  发送报文: 00 C9 00 00 00 06 01 03 00 00 00 02
         //Rx  接收报文: 00 C9 00 00 00 07 01 03 04 01 4D 00 01
         // 校验 00 07 01 03 04  这几位
         // 00 C9 00 00 00 07 01 03 04   这9位是长度固定的,  +   获取寄存器长度length*2   每个寄存器占2字节
         if (buffer.Length == 9+length*2) 
         {
             //两位字节转换整数  result_h   高位字节 result_1  地位字节
             //result = result_h * 256 + result_1
             //   00 07     
             //   3+length*2   3来源于01 03 04  固定的  
             if (buffer[4] * 256 + buffer[5]==3+length*2) 
             {
                 //   单元标识符  和   功能码
                 if (buffer[6] == SlaveId && buffer[7] == 0x03)
                 {
                     #region 5 解析报文
                     //  返回的数据字节数,就是 要读取寄存器*2
                     byte[] result = new byte[length*2];
                     Array.Copy(buffer,9,result,0,length*2);
                     return result;
                     #endregion
                 }
             }

         }
         return null;
         #endregion
        
       
     }

     /// <summary>
     /// 写入多数据
     /// </summary>
     /// <param name="startAdr">开始寄存器地址</param>
     /// <param name="length">寄存器长度</param>
     /// <param name="dates">具体数据</param>
     /// <returns></returns>
     public void WriteResisters(ushort startAdr, ushort length,ushort datecount, ushort[] dates)
     {
         #region 1 拼接报文
         List<byte> SendCommand = new List<byte>();
         // 事务标识符 2字节  固定  0x00 0x00
         SendCommand.AddRange(new byte[] { 0x00, 0x00 });
         // 协议标识符 2字节  固定  0x00 0x00
         SendCommand.AddRange(new byte[] { 0x00, 0x00 });
         // 长度  2字节       7:  单元标识符1字节+功能码1字节+ 开始寄存器地址2字节 寄存器长度2字节 + 字节长度1字节
         ushort[] lens=int2ushorts(2*length+7);
         //byte[] start1 = BitConverter.GetBytes(lens[0]);
         byte[] len = BitConverter.GetBytes(lens[1]);
         if (BitConverter.IsLittleEndian)
         {
             Array.Reverse(len);
         }
         SendCommand.AddRange(len);
         // 单元标识符  1字节  固定 SlaveId
         SendCommand.Add(SlaveId);
         // 功能码  写入 多个保持寄存器
         SendCommand.Add(0x10);
         // 数据部分     开始寄存器地址 寄存器长度  字节长度   具体数据
         // 开始寄存器地址
         byte[] start = BitConverter.GetBytes(startAdr);
         //数据值
         List<byte> valueBytes = new List<byte>();
         byte[] value;
         foreach (ushort b in dates)
         {
             value= BitConverter.GetBytes(b);
             if (BitConverter.IsLittleEndian)
             {
                 Array.Reverse(value);
             }
             valueBytes.AddRange(value);
         }            
         //根据计算机大小端存储方式进行高低字节转换
         if (BitConverter.IsLittleEndian)
         {
             Array.Reverse(start);              
         }
         SendCommand.AddRange(start);
         //寄存器长度  2字节
         byte[] registLen = BitConverter.GetBytes(length);         
         if (BitConverter.IsLittleEndian)
         {
             Array.Reverse(registLen);
           
         }
         SendCommand.AddRange(registLen);
         //字节长度 1字节
         SendCommand.Add((byte)(datecount%255));
         
         //SendCommand.AddRange(new byte[] { 0,1});
        
         SendCommand.AddRange(valueBytes);
       
         #endregion
         #region 2 发送报文
         Thread.Sleep(50);
         //tcpClient.Send(SendCommand.ToArray(),0,SendCommand.Count(),SocketFlags.Partial);
         //tcpClient.Send(SendCommand.ToArray());
         //tcpClient.Send(new byte[] { 00, 01, 00, 00, 00, 08, 0xFF, 0x05, 00, 05 , 00 ,01, 01, 01 });
         //Rx: 000002 - 00 01 00 00 00 09 01 0A 00 05 00 01 01 00 0F
         //事务标识符2字节           1F 97
         //协议标识符2字节           00 00
         //长度 2字节                00 11
         //单元标识符                01
         //功能码                    10
         //起始地址 2字节            00 04
         //寄存器长度 2字节          00 02            读2个寄存器
         //字节数    寄存器长度*2    04
         //字节数组N*2字节           00 06 00 09
         //1F 97 00 00 00 11 01 10 00 04 00 02 04 00 06 00 09
         // 00 01 00 00 00 11 01 10 00 03 00 02 04 00 02 01 09
         //tcpClient.Send(new byte[] { 00, 01, 00, 00, 00, 11, 01, 0x10, 00, 00 ,00 ,02 ,04,01,02, 30 ,39 });
         //tcpClient.Send(new byte[] { 00, 01, 00, 00, 00, 11, 01, 0x10, 00, 00 ,00 ,02 ,04,01,02, 30 ,39 });
         tcpClient.Send(SendCommand.ToArray());
         #endregion

     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226

在这里插入图片描述

位操作,写写数据需要吧数据转换 2进制

4种寄存器

线圈寄存器 按位操作 可读可写
离散输入寄存器 按位 读取寄存器
保持寄存器
输入寄存器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

》》 按位操作 所以 返回 1个字节
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/451912
推荐阅读
相关标签
  

闽ICP备14008679号