Modbus通信(一)

1.协议特点

1.标准开放、公开发表、无版税要求、无许可证费(没有费用)

2.支持多种电气接口(RS232、RS422、RS485、RJ45);各种介质传输(双绞线、网线)

3. 格式简单、紧凑、通俗易懂,容易上手

2.Modbus总线通信环境

3.Modbus通讯方式与分类

串口:ModbusAscii,ModbusRTU

以太网:ModbusTCP、ModbusUDP

4.Modbus协议下的数据存储

位bit (bool)、字节byte(8个位)、字Word(2个字节,16位)、双字(2个字,4个字节,32位)

4.1 由byte确定Bit
//确定第n位是否为1
bool state=(value&(1<<n))!=0
//按位与
1<<n
//关系型判断
&&
4.2大小端处理及转换 

大端:数据的高位放在低地址空间,数据的低位放在高地址空间

小端:低位对应低地址,高位对应高地址

例如:整数 0x12345678 (十六进制) 在内存中的存储 :

举例(整数 0x12345678 (十六进制) 在内存中的存储 (地址递增方向 ->))PLC 厂商的常见默认字节序
大端

地址0: 0x12 (最高有效字节 )

地址1: 0x34 

地址2: 0x56 

地址3: 0x78 (最低有效字节)

西门子 (Siemens)
小端

地址0: 0x78 (最低有效字节 )

地址1: 0x56 

地址2: 0x34 

地址3: 0x12 (最高有效字节)

三菱 (Mitsubishi) **System.BitConverter

运行环境(如 x86, x64, ARM 架构的 Windows)

使用 BinaryPrimitives 是最佳实践,能避免环境依赖

双字:uint ,int ,float

float类型 IEEE754标准 浮点型数据二进制表示

double 64位 long 128位 decimal 高精度 数据存储的精度丢失问题

取高位:

//第一种 右移 8 位 仅限 16 位整数
byte[i]=(byte)(add/256);
//第二种 用掩码 0xFF00 保留高字节,清除低字节 
//16/32/64 位整数均适用(需调整掩码)
byte b=(byte)((src&0xFF00)>>8)

取低位

//第一种
byte[i]=(byte)(add%256);
//第二种
byte b=(byte)(src&0x00FF)
 4.3 内存分区与功能 

对应功能码

功能码名称
01读线圈状态
05写单个线圈
15写多个线圈
02读取输入状态(输入线圈)
04读取输入寄存器
03读取保持寄存器
06写单个保持寄存器
16写多个保持寄存器
4.4 格式
名称类型结构
Modbus RTU串口站号+功能码+地址+长度+校验码ModbusRtu
Modbus TCP网口消息号+0x0000+字节长度+站号+功能码+地址+长度ModbusTcpNet
Modbus Ascii0x3A+ADDR+PDU+LCR+0x0D+0x0AModbusAscii
4.4.1、 Modbus RTU

字节序优化  

short 2个字节

serialPort.Read(data, 0, data.Length);
// 解析   2字节的数据  
for (int i = 3; i < data.Length - 2; i += 2)
{
  // Modbus Slave大端处理
  // 100
  // 0000 0000     0110 0100
  byte[] vb = new byte[2] { data[i + 1], data[i] };[Modbus Slave大端处理-》换顺序成小端]
  ushort v = BitConverter.ToUInt16(vb);// 解析出无符号短整型数据
  Console.WriteLine(v);
}

float 4个字节 ABCD

 取决于从设备方接收的顺序:CDAB |BADC

 for (int i = 3; i < data.Length - 2; i += 4)
                {
                    // 封装库的需要注意字节序  
                    byte[] vb = new byte[4]
                    {
                        data[i + 2],//D
                        data[i+3 ],//C
                        data[i ],//B
                        data[i+1]//A
                    };
                    float v = BitConverter.ToSingle(vb);
                    Console.WriteLine(v);
                }

 注:设备方当遇到简单小数,如4.5可以存储成int类型45,取出后再*0.1,可节约字节空间

寄存器和线圈的区别

1.读写保持寄存器时

每一个代表一个字节

2.读取线圈时

每一位代表一个bit(0或者1),8位一个字节

读取线圈状态并解析 每个字节对应8位

 //2.读取每个字节对应8个位状态
                            int count = 0;
                            for (int i = 0; i < res.Count; i++)
                            {
                                for (int j = 0; j < 8; j++)
                                {
                                    // 遍历每个字节中的每个位
                                    byte temp = (byte)(1<<j);
                                    //判断是TRUE还是false
                                    bool state = (res[i] & temp) != 0;
                                    count++;
                                    if (count == len)
                                        break;
                                }
                            }

 写入多线圈报文处理

//写入内容 2字节 1011101011

 List<bool> values1 = new List<bool>()
                            {
                                true, false, true, true, true, false, true, false, true, true
                            };

                            //写入数量
                            readBytes.Add((byte)(values1.Count / 256));
                            readBytes.Add((byte)(values1.Count % 256));
                            //写入字节数
                            List<byte> vbs = new List<byte>();
                            int index = 0;
                            //把true,false转换成字节表示 1011101011-》具体数值
                            for (int i = 0; i < values1.Count; i++)
                            {
                                if (i%8==0)
                                {
                                    vbs.Add(0x00);// 初始值
                                }
                                index = vbs.Count - 1;

                                if (values1[i])
                                {
                                    byte temp = (byte)(1 << (i % 8));
                                    //  | 是为了保留上一次计算结果
                                    vbs[index] |= temp;                           1
                                }
                            }
                            //写入字节数
                            readBytes.Add((byte)vbs.Count);
                            readBytes.AddRange(vbs);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值