C# ModbusRTU、ModbusASCII及ModbusTCP返回数据解析为数值,功能码0x01

您所在的位置:网站首页 字符串解码顺序 C# ModbusRTU、ModbusASCII及ModbusTCP返回数据解析为数值,功能码0x01

C# ModbusRTU、ModbusASCII及ModbusTCP返回数据解析为数值,功能码0x01

2024-07-12 16:57| 来源: 网络整理| 查看: 265

1.概述

既然谈到ModbusRTU、Modbus ASCII、ModbusTCP数据返回,那我们多少会对Modbus数据发送会有了解,所以本文不再对Modbus的基础知识进行阐述,如果想了解Modbus常用的发送指令,可以参看我的文章"C# ModbusRTU命令功能码"、“C# Modbus ASCII命令功能码"和"C# ModbusTCP命令功能码”。 Modbus常用的通信指令有8条,其中功能码0x01、0x02、0x03、0x04是查询指令,0x05、0x06、0x0F、0x10是写入指令,对应的返回数据也就有8种。写入指令0x05和0x06的返回数据跟发送指令完全相同(返回异常码除外),0x0F和0x10返回数据跟发送指令的前6个字节完全相同,LRC、CRC校验码不同(ModbusTCP无此校验),写入指令的返回数据相当于确认功能,它们解析为数值是没有意义的。所以我们着重谈的是功能码0x01至0x04的返回数据的值解析。

2.解析代码

Modbus功能码0x01和0x02是查询线圈和离散量状态的,所以返回值类型为bool类型,功能码0x03和0x04是查询保持寄存器和输入寄存器的值,返回类型是数值型的。由于不同的通信硬件设备的解码字节顺序不同,也会带来返回数据的值不同,例如Modicon PLC的整形与浮点型均按3412顺序,而PLC返回的原始数据为1234,解析出来的值自然不会正确。 首先声明四个个枚举,其中有几条枚举项现在用不上,但是我写上它是为了能列出来更多的Modbus指令和生成Modbus发送指令时使用的,无用的大家可自己过滤掉。

/// /// Modbus的类型 /// public enum ModbusType { /// /// Modbus serial RTU /// SERIAL_RTU = 0, /// /// Modbus serial ASCII /// SERIAL_ASCII = 1, /// /// Modbus TCP/IP /// TCP_IP = 2, } /// /// Modbus指令代码 /// public enum ModbusCodes { READ_COILS = 0x01, //读取线圈 READ_DISCRETE_INPUTS = 0x02, //读取离散量输入 READ_HOLDING_REGISTERS = 0x03, //读取保持寄存器 READ_INPUT_REGISTERS = 0x04, //读取输入寄存器 WRITE_SINGLE_COIL = 0x05, //写单个线圈 WRITE_SINGLE_REGISTER = 0x06, //写单个保持寄存器 READ_EXCEPTION_STATUS = 0x07, //读取异常状态 DIAGNOSTIC = 0x08, //回送诊断校验 GET_COM_EVENT_COUNTER = 0x0B, //读取事件计数 GET_COM_EVENT_LOG = 0x0C, //读取通信事件记录 WRITE_MULTIPLE_COILS = 0x0F, //写多个线圈 WRITE_MULTIPLE_REGISTERS = 0x10, //写多个保持寄存器 REPORT_SLAVE_ID = 0x11, //报告从机标识(ID) READ_FILE_RECORD = 0x14, //读文件记录 WRITE_FILE_RECORD = 0x15, //写文件记录 MASK_WRITE_REGISTER = 0x16, //屏蔽写寄存器 READ_WRITE_MULTIPLE_REGISTERS = 0x17, //读写多个寄存器 READ_FIFO_QUEUE = 0x18, //读取队列 READ_DEVICE_IDENTIFICATION = 0x2B //读取设备标识 } /// /// 错误代码 /// public enum Errors { NO_ERROR = 0,//无错误 EXCEPTION_UNKNOWN = 1,//未知异常 EXCEEDING_MODBUSCODE_RANGE = 2,//超出ModbusCode范围 UNPROCESSED_MODBUSCODE = 3,//没有处理的ModbusCode WRONG_RESPONSE_ADDRESS = 4,//响应地址错误 WRONG_RESPONSE_REGISTERS = 5,//响应寄存器错误 WRONG_RESPONSE_VALUE = 6,//响应值错误 WRONG_CRC = 7,//CRC16校验错误 TOO_MANY_REGISTERS_REQUESTED = 8,//请求的寄存器数量太多 ZERO_REGISTERS_REQUESTED = 9,//零寄存器请求 EXCEPTION_ILLEGAL_FUNCTION = 20,//非法的功能码 EXCEPTION_ILLEGAL_DATA_ADDRESS = 21,//非法的数据地址 EXCEPTION_ILLEGAL_DATA_VALUE = 22,//非法的数据值 EXCEPTION_SLAVE_DEVICE_FAILURE = 23,//从站(服务器)故障 } /// /// Modbus返回字节大小/类型/顺序 /// public enum ByteOrder { NONE = 0, TWO_WORD_12 = 1, TWO_WORD_21 = 2, FOUR_INT_1234 = 3, FOUR_INT_1243 = 4, FOUR_INT_2134 = 5, FOUR_INT_2143 = 6, FOUR_INT_3412 = 7, FOUR_INT_3421 = 8, FOUR_INT_4312 = 9, FOUR_INT_4321 = 10, FOUR_FLOAT_1234 = 11, FOUR_FLOAT_1243 = 12, FOUR_FLOAT_2134 = 13, FOUR_FLOAT_2143 = 14, FOUR_FLOAT_3412 = 15, FOUR_FLOAT_3421 = 16, FOUR_FLOAT_4312 = 17, FOUR_FLOAT_4321 = 18 }

下面就是解析从站返回数据的方法了,返回类型是object,是因为我们上面说过,返回类型可能是bool型和数值型,所以最后根据需要自己去强制转换。考虑到功能码0x01和0x02可能查询是多个线圈或离散量,所以解析方法返回的数据就会是一个bool数组序列,功能码0x03和0x04查询的可能是多个保持寄存器或输入寄存器,其解析回来的数值根据设备字节顺序要求,会是byte、ushort、int和float数组。

#region Modbus public class Modbus { #region 内部方法 /// /// 16进制的字符串转换成等效的byte[]数组 /// private byte[] HexStringToBytes(string source) { source = source.Replace(" ", ""); if (source.Length % 2 == 1) return null;//字符串为奇数就无法转换,返回null byte[] buffer = new byte[source.Length / 2]; for (int i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3