欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用C#實(shí)現(xiàn)自己封裝的Modbus工具類庫

 更新時(shí)間:2024年02月29日 09:50:31   作者:baivfhpwxf2023  
Modbus通訊協(xié)議在工控行業(yè)的應(yīng)用是很多的,并且也是上位機(jī)開發(fā)的基本技能之一,所以本文主要為大家介紹了如何使用C#封裝一個(gè)Modbus工具類庫,需要的可以參考下

前言

Modbus通訊協(xié)議在工控行業(yè)的應(yīng)用是很多的,并且也是上位機(jī)開發(fā)的基本技能之一。相關(guān)的類庫也很多也很好用。以前只負(fù)責(zé)用,對其并沒有深入學(xué)習(xí)和了解。前段時(shí)間有點(diǎn)空就在這塊挖了挖。想做到知其然還要知其所以然。所以就有了自己封裝的Modbus工具類庫的想法。一來是練練手,二來是自己封裝的用的更順手。

Modbus通訊協(xié)議我在工作中目前只用到了兩種一個(gè)是串口通訊ModbusRTU,還有一個(gè)是網(wǎng)絡(luò)通訊ModbusTcp。所以本文只有這兩種通訊的實(shí)現(xiàn)。

設(shè)計(jì)思想

C#是高級語言有很多好用的東西,如面像對像,設(shè)計(jì)模式等。但我在工作中還是經(jīng)??吹矫嫦襁^程的編程。如有多個(gè)串口設(shè)備就有多個(gè)代碼類似的工具類。代碼重復(fù)非常嚴(yán)重。我認(rèn)為這種事還是要發(fā)點(diǎn)時(shí)間總結(jié)和代碼一下代碼,把它封裝工具類庫。以便后繼在其他上的使用。

本次的封裝用了一點(diǎn)面像對像的方法,設(shè)計(jì)了一個(gè)多個(gè)Modbus 基類將一些公共方法放在基類中,子類就可以繼續(xù)使用。不同的子類有不同的功能??梢园葱枵{(diào)用。使用簡單方便。

調(diào)用示例        

var _serialPort = new ModbusRTUCoil(portName, baudRate, parity, dataBits, stopBits);
var isOk = false;
var resultModel = _serialPort.ReadDataCoil(1, 1, ModbusFunctionCode.ReadInputCoil, (ushort)type.GetHashCode());
if (resultModel.ResultList != null && resultModel.ResultList.Count > 0)
{
    isOk = resultModel.ResultList.FirstOrDefault();
}

類庫項(xiàng)目結(jié)構(gòu)

代碼

Modbus結(jié)果實(shí)體

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CJH.ModbusTool
{
    /// <summary>
    /// Modbus結(jié)果實(shí)體
    /// </summary>
    /// <typeparam name="DateType"></typeparam>
    public class ModbusResultModel
    {
        public ModbusResultModel()
        {
            IsSucceed = false;
            Msg = "失敗(默認(rèn))";
        }
 
        private bool _isSucceed = false;
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool IsSucceed
        {
            get
            {
                return _isSucceed;
            }
            set
            {
                _isSucceed = value;
                if (IsSucceed)
                {
                    Msg = "成功";
                }
            }
        }
 
        /// <summary>
        /// 返回消息
        /// </summary>
        public string Msg { get; set; }
 
        /// <summary>
        /// 發(fā)送報(bào)文
        /// </summary>
        public string SendDataStr { get; set; }
 
        /// <summary>
        /// 原始數(shù)據(jù)
        /// </summary>
        public byte[] Datas { get; set; }
    }
 
    /// <summary>
    /// Modbus結(jié)果實(shí)體
    /// </summary>
    /// <typeparam name="DateType"></typeparam>
    public class ModbusResultModel<DateType> : ModbusResultModel
    {
        public ModbusResultModel() : base()
        {
            ResultList = new List<DateType>();
        }
 
        /// <summary>
        /// 解析后的數(shù)據(jù)
        /// </summary>
        public List<DateType> ResultList { get; set; }
    }
}

Modbus 基類

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CJH.ModbusTool
{
    /// <summary>
    /// Modbus 基類
    /// </summary>
    public abstract class ModbusBase
    {
        /// <summary>
        /// 生成讀取報(bào)文的 公共方法
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="length">寄存器數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始寄存器地址</param>
        /// <returns>返回報(bào)文(協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量)</returns>
        protected byte[] GenerateReadCommandBytes(byte devAddr, ushort length, ModbusFunctionCode functionCode = ModbusFunctionCode.ReadRegister, ushort startAddr = 0)
        {
            //1.拼接報(bào)文:
            var sendCommand = new List<byte>();
 
            //協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量
            //站地址
            sendCommand.Add(devAddr);
            //功能碼
            sendCommand.Add((byte)functionCode.GetHashCode());
            //起始寄存器地址
            sendCommand.Add((byte)(startAddr / 256));
            sendCommand.Add((byte)(startAddr % 256));
            //寄存器數(shù)量
            sendCommand.Add((byte)(length / 256));
            sendCommand.Add((byte)(length % 256));
            //CRC
            //byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
            //sendCommand.AddRange(crc);
 
            return sendCommand.ToArray();
        }
 
        /// <summary>
        /// 生成讀取報(bào)文的 公共方法
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="data">定入數(shù)據(jù)</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">寫入地址</param>
        /// <returns>返回報(bào)文(協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量)</returns>
        protected byte[] GenerateWriteCommandBytes(byte devAddr, ushort data, ModbusFunctionCode functionCode = ModbusFunctionCode.ReadRegister, ushort startAddr = 0)
        {
            //1.拼接報(bào)文:
            var sendCommand = new List<byte>();
 
            //協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量
            //站地址
            sendCommand.Add(devAddr);
            //功能碼
            sendCommand.Add((byte)functionCode.GetHashCode());
            //寫入地址
            sendCommand.Add((byte)(startAddr / 256));
            sendCommand.Add((byte)(startAddr % 256));
            //寫入數(shù)據(jù)
            var temp_bytes = BitConverter.GetBytes(data);
            if (BitConverter.IsLittleEndian)
            {
                //temp_bytes.Reverse();
                Array.Reverse(temp_bytes);
            }
            sendCommand.AddRange(temp_bytes);
            //CRC
            //byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
            //sendCommand.AddRange(crc);
 
            return sendCommand.ToArray();
        }
 
        /// <summary>
        /// 生成發(fā)送命令報(bào)文
        /// </summary>
        /// <param name="sendCommand"></param>
        /// <returns></returns>
        protected string generateSendCommandStr(byte[] sendCommand)
        {
            var sendCommandStr = string.Empty;
            foreach (var item in sendCommand)
            {
                sendCommandStr += Convert.ToString(item, 16) + " ";
            }
            return sendCommandStr;
        }
 
        /// <summary>
        /// 驗(yàn)證CRC
        /// </summary>
        /// <param name="value">要驗(yàn)證的數(shù)據(jù)</param>
        /// <returns></returns>
        protected bool CheckCRC(byte[] value)
        {
            var isOk = false;
            if (value != null && value.Length >= 2)
            {
                int length = value.Length;
                byte[] buf = new byte[length - 2];
                Array.Copy(value, 0, buf, 0, buf.Length);
 
                //自己驗(yàn)證的結(jié)果
                byte[] CRCbuf = Crc16(buf, buf.Length);
                //把上面驗(yàn)證的結(jié)果和串口返回的校驗(yàn)碼(最后兩個(gè))進(jìn)行比較
                if (CRCbuf[0] == value[length - 2] && CRCbuf[1] == value[length - 1])
                {
                    isOk = true;
                }
            }
            return isOk;
        }
 
        protected byte[] Crc16(byte[] pucFrame, int usLen)
        {
            int i = 0;
            byte[] res = new byte[2] { 0xFF, 0xFF };
            ushort iIndex;
            while (usLen-- > 0)
            {
                iIndex = (ushort)(res[0] ^ pucFrame[i++]);
                res[0] = (byte)(res[1] ^ aucCRCHi[iIndex]);
                res[1] = aucCRCLo[iIndex];
            }
            return res;
        }
 
        protected readonly byte[] aucCRCHi = {
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40
         };
 
        protected readonly byte[] aucCRCLo = {
             0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
             0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
             0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
             0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
             0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
             0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
             0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
             0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
             0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
             0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
             0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
             0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
             0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
             0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
             0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
             0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
             0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
             0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
             0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
             0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
             0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
             0x41, 0x81, 0x80, 0x40
         };
 
        /// <summary>
        /// CRC校驗(yàn)
        /// </summary>
        /// <param name="pucFrame">字節(jié)數(shù)組</param>
        /// <param name="usLen">驗(yàn)證長度</param>
        /// <returns>2個(gè)字節(jié)</returns>
        protected byte[] CalculateCRC(byte[] pucFrame, int usLen)
        {
            int i = 0;
            byte[] res = new byte[2] { 0xFF, 0xFF };
            ushort iIndex;
            while (usLen-- > 0)
            {
                iIndex = (ushort)(res[0] ^ pucFrame[i++]);
                res[0] = (byte)(res[1] ^ aucCRCHi[iIndex]);
                res[1] = aucCRCLo[iIndex];
            }
            return res;
        }
    }
 
    /// <summary>
    /// Modbus 功能碼
    /// </summary>
    public enum ModbusFunctionCode
    {
        /// <summary>
        /// 讀取輸出線圈
        /// </summary>
        [Description("讀取輸出線圈")]
        ReadOutCoil = 1,
 
        /// <summary>
        /// 讀取輸入線圈
        /// </summary>
        [Description("讀取輸入線圈")]
        ReadInputCoil = 2,
 
        /// <summary>
        /// 讀取保持寄存器
        /// </summary>
        [Description("讀取保持寄存器")]
        ReadRegister = 3,
 
        /// <summary>
        /// 讀取輸入寄存器
        /// </summary>
        [Description("讀取輸入寄存器")]
        ReadInputRegister = 4,
 
        /// <summary>
        /// (寫入)預(yù)置單線圈
        /// </summary>
        [Description("(寫入)預(yù)置單線圈")]
        WriteCoil = 5,
 
        /// <summary>
        /// (寫入)預(yù)置單個(gè)寄存器
        /// </summary>
        [Description("(寫入)預(yù)置單個(gè)寄存器")]
        WriteRegister = 6,
 
        /// <summary>
        /// (寫入)預(yù)置多寄存器
        /// </summary>
        [Description("(寫入)預(yù)置多寄存器")]
        WriteRegisterMultiple = 16,
    }
}

RTU

串口基類 SerialPortBase

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CJH.ModbusTool.RTU
{
    //Modbus 規(guī)定4個(gè)存儲區(qū)
    // 區(qū)號     名稱     讀寫        范圍
    // 0區(qū)     輸出線圈  可讀可寫    00001-09999
    // 1區(qū)     輸入線圈  只讀        10001-19999
    // 2區(qū)     輸入寄存器  只讀      30001-39999
    // 4區(qū)     保存寄存器  可讀可寫  40001-19999
 
    //功能碼
    //01H     讀取輸出線圈
    //02H     讀取輸入線圈
    //03H     讀取保持寄存器
    //04H     讀取輸入寄存器
    //05H     (寫入)預(yù)置單線圈
    //06H     (寫入)預(yù)置寄存器
    //0FH     (寫入)預(yù)置多線圈
    //10H     (寫入)預(yù)置多寄存器
 
    /// <summary>
    /// 串口基類
    /// </summary>
    public abstract class SerialPortBase : ModbusBase
    {
        protected SerialPort SerialPortObj;
 
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="portName">COM口名稱</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">檢驗(yàn)位</param>
        /// <param name="dataBits">數(shù)據(jù)位</param>
        /// <param name="stopBits">停止位</param>
        protected void Init(string portName, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
        {
            SerialPortObj = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
            if (SerialPortObj.IsOpen)
            {
                SerialPortObj.Close();
            }
            SerialPortObj.Open();
        }        
 
        /// <summary>
        /// 關(guān)閉
        /// </summary>
        public void Close()
        {
            if (SerialPortObj.IsOpen)
            {
                SerialPortObj.Close();
                SerialPortObj.Dispose();
                SerialPortObj = null;
            }
        }
    }
 
    //功能碼
    //01H     讀取輸出線圈
    //02H     讀取輸入線圈
    //03H     讀取保持寄存器
    //04H     讀取輸入寄存器
    //05H     (寫入)預(yù)置單線圈
    //06H     (寫入)預(yù)置寄存器
    //0FH     (寫入)預(yù)置多線圈
    //10H     (寫入)預(yù)置多寄存器
 
    
}

Modbus 串口通訊

(串口操作的所有功能這個(gè)類都能做)

using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CJH.ModbusTool.RTU
{
    /// <summary>
    /// Modbus 串口通訊
    /// </summary>
    public class ModbusRTU : SerialPortBase
    {
        private string _className = "ModbusRTU";
 
        /// <summary>
        /// Modbus 串口通訊
        /// </summary>
        /// <param name="portName">COM口名稱</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">檢驗(yàn)位</param>
        /// <param name="dataBits">數(shù)據(jù)位</param>
        /// <param name="stopBits">停止位</param>
        public ModbusRTU(string portName, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
        {
            Init(portName, baudRate, parity, dataBits, stopBits);
            //SerialPortObj.DataReceived += new SerialDataReceivedEventHandler(ComDataReceived);
        }
 
        /// <summary>
        /// 讀取線圈數(shù)據(jù) ok
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="length">寄存器數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始寄存器地址</param>
        /// <returns>線圈數(shù)據(jù)</returns>
        public ModbusResultModel ReadData(byte devAddr, ushort length, ModbusFunctionCode functionCode = ModbusFunctionCode.ReadRegister, ushort startAddr = 0)
        {
            return ReadData(devAddr, length, (byte)functionCode, startAddr);
        }
 
        /// <summary>
        /// 讀取數(shù)據(jù) ok
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="length">寄存器數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始寄存器地址</param>
        /// <returns>線圈數(shù)據(jù)</returns>
        public ModbusResultModel ReadData(byte devAddr, ushort length, byte functionCode = 2, ushort startAddr = 0)
        {
            var resultModel = new ModbusResultModel();
            //byte[] datas = null;
            if (functionCode >= 1 && functionCode <= 4)
            {
                try
                {
                    //1.拼接報(bào)文:
                    var sendCommand = new List<byte>();
 
                    //協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量+CRC
                    //站地址
                    sendCommand.Add(devAddr);
                    //功能碼
                    sendCommand.Add(functionCode);
                    //起始寄存器地址
                    sendCommand.Add((byte)(startAddr / 256));
                    sendCommand.Add((byte)(startAddr % 256));
                    //寄存器數(shù)量
                    sendCommand.Add((byte)(length / 256));
                    sendCommand.Add((byte)(length % 256));
                    //CRC
                    byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
                    sendCommand.AddRange(crc);
 
                    resultModel.SendDataStr = generateSendCommandStr(sendCommand.ToArray());
                    //2.發(fā)送報(bào)文
                    SerialPortObj.Write(sendCommand.ToArray(), 0, sendCommand.Count);
                    //3.接收報(bào)文
                    Thread.Sleep(50);//要延時(shí)一下,才能讀到數(shù)據(jù)
 
                    //讀取響應(yīng)報(bào)文
                    byte[] respBytes = new byte[SerialPortObj.BytesToRead];
                    SerialPortObj.Read(respBytes, 0, respBytes.Length);
                    // respBytes -> 01 01 02 00 00 B9 FC
                    resultModel.Datas = respBytes;
                    // 檢查一個(gè)校驗(yàn)位
                    //if (CheckCRC(respBytes) && (respBytes.Length == 5 + length * 2) 
                    //    && respBytes[0] == devAdd && respBytes[1] == functionCode && respBytes[1] == length * 2)
                    if (CheckCRC(respBytes) && respBytes[0] == devAddr && respBytes[1] == functionCode)
                    {
                        //datas = respBytes;
                        resultModel.IsSucceed = true;
                    }
                    else
                    {
                        resultModel.Msg = "響應(yīng)報(bào)文校驗(yàn)失敗";
                    }
                }
                catch (Exception ex)
                {
                    resultModel.Msg = "異常:" + ex.Message;
                }
            }
            else
            {
                //throw new Exception("功能碼不正確[1-4]");
                resultModel.Msg = "功能碼不正確[1-4]";
            }
            //SerialPortObj.Close();
            return resultModel;
        }
 
        /// <summary>
        /// 寫入單個(gè)寄存器 ok
        /// 數(shù)據(jù)示例: 200
        /// 功能碼 6
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="value">寫入的數(shù)據(jù)</param>
        /// <param name="startAddr">寫入地址</param>
        /// <returns>是否成功</returns>
        public ModbusResultModel WriteDataShort(int devAddr, short value, short startAddr = 0)
        {
            var resultModel = new ModbusResultModel();
            try
            {
                //bool isOk = false;
                //1.拼接報(bào)文:
                //var sendCommand = GetSingleDataWriteMessage(devAdd, startAddr, value); //ok
                var sendCommand = GetSingleDataWriteMessageList(devAddr, startAddr, value); //ok
                                                                                           //var sendCommandStr = string.Join(' ', sendCommand.ToArray());
                resultModel.SendDataStr = generateSendCommandStr(sendCommand);
 
                //2.發(fā)送報(bào)文
                SerialPortObj.Write(sendCommand.ToArray(), 0, sendCommand.Length);
                //3.接收報(bào)文
                Thread.Sleep(50);//要延時(shí)一下,才能讀到數(shù)據(jù)
 
                //讀取響應(yīng)報(bào)文
                byte[] respBytes = new byte[SerialPortObj.BytesToRead];
                SerialPortObj.Read(respBytes, 0, respBytes.Length);
                // respBytes -> 01 01 02 00 00 B9 FC
                // 檢查一個(gè)校驗(yàn)位
                if (CheckCRC(respBytes) && respBytes[0] == devAddr && respBytes[1] == 0x06)
                {
                    //isOk = true;
                    resultModel.IsSucceed = true;
                }
                else
                {
                    resultModel.Msg = "響應(yīng)報(bào)文校驗(yàn)失敗";
                }
            }
            catch (Exception ex)
            {
                resultModel.Msg = "異常:" + ex.Message;
            }
            //SerialPortObj.Close();
            return resultModel;
        }
 
        /// <summary>
        /// 寫入單個(gè)寄存器 ok
        /// 數(shù)據(jù)示例: 200
        /// 功能碼 6
        /// </summary>
        /// <param name="devAddr">站地址</param>
        /// <param name="dataList">寫入的數(shù)據(jù)集合</param>
        /// <param name="startAddr">寫入地址</param>
        /// <returns>是否成功</returns>
        public ModbusResultModel WriteDataShort(int devAddr, List<short> dataList, short startAddr = 0)
        {
            var resultModel = new ModbusResultModel();
            if (dataList != null && dataList.Count > 0)
            {
                foreach (var item in dataList)
                {
                    resultModel = WriteDataShort(devAddr, item, startAddr);
                    startAddr++;
                }
            }
            return resultModel;
        }
 
        /// <summary>
        /// 獲取寫入單個(gè)寄存器的報(bào)文
        /// </summary>
        /// <param name="slaveStation">從站地址</param>
        /// <param name="startAddr">寄存器地址</param>
        /// <param name="value">寫入值</param>
        /// <returns>寫入單個(gè)寄存器的報(bào)文</returns>
        private byte[] GetSingleDataWriteMessage(int slaveStation, short startAddr, short value)
        {
            //從站地址
            byte station = (byte)slaveStation;
            //功能碼
            byte type = 0x06;//06H     (寫入)預(yù)置寄存器
            //寄存器地址
            byte[] start = BitConverter.GetBytes(startAddr);
            //值
            byte[] valueBytes = BitConverter.GetBytes(value);
            //根據(jù)計(jì)算機(jī)大小端存儲方式進(jìn)行高低字節(jié)轉(zhuǎn)換
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(start);
                Array.Reverse(valueBytes);
            }
            //拼接報(bào)文
            byte[] result = new byte[] { station, type };
            result = result.Concat(start.Concat(valueBytes).ToArray()).ToArray();
 
            //計(jì)算校驗(yàn)碼并拼接,返回最后的報(bào)文結(jié)果
            return result.Concat(Crc16(result, result.Length)).ToArray();
        }
 
        /// <summary>
        /// 獲取寫入單個(gè)寄存器的報(bào)文
        /// </summary>
        /// <param name="slaveStation">從站地址</param>
        /// <param name="startAddr">寄存器地址</param>
        /// <param name="data">寫入值</param>
        /// <returns>寫入單個(gè)寄存器的報(bào)文</returns>
        private byte[] GetSingleDataWriteMessageList(int slaveStation, short startAddr, short data)
        {
            //1.拼接報(bào)文:
            var sendCommand = new List<byte>();
            //從站地址
            byte station = (byte)slaveStation;
            //功能碼
            byte type = 0x06;//06H     (寫入)預(yù)置寄存器            
            //寄存器地址
            byte[] start = BitConverter.GetBytes(startAddr);
            //值
            byte[] valueBytes = BitConverter.GetBytes(data);
            //根據(jù)計(jì)算機(jī)大小端存儲方式進(jìn)行高低字節(jié)轉(zhuǎn)換
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(start);
                Array.Reverse(valueBytes);
            }
            sendCommand.Add((byte)slaveStation);
            sendCommand.Add(type);
            sendCommand.AddRange(start);
            sendCommand.AddRange(valueBytes);
 
            byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
            sendCommand.AddRange(crc);
            return sendCommand.ToArray();
        }
 
        /// <summary>
        /// 寫入多個(gè)寄存器 ok
        /// 數(shù)據(jù)示例: 123.45f, 14.3f
        /// 功能碼 10 
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="data">寫入的數(shù)據(jù)</param>
        /// <param name="startAddr">寫入地址</param>
        /// <returns>是否成功</returns>
        public ModbusResultModel WriteDataFloat(byte devAddr, float data, ushort startAddr = 0)
        {
            return WriteDataFloat(devAddr, new List<float>() { data }, startAddr);
        }
 
        /// <summary>
        /// 寫入多個(gè)寄存器 ok
        /// 數(shù)據(jù)示例: 123.45f, 14.3f
        /// 功能碼 10 
        /// </summary>
        /// <param name="devAdd">從站地址</param>
        /// <param name="dataList">寫入的數(shù)據(jù)</param>
        /// <param name="startAddr">寫入地址</param>
        /// <returns>是否成功</returns>
        public ModbusResultModel WriteDataFloat(byte devAddr, List<float> dataList, ushort startAddr = 0)
        {
            var resultModel = new ModbusResultModel();
            if (dataList != null && dataList.Count > 0)
            {
                try
                {
                    byte functionCode = (byte)ModbusFunctionCode.WriteRegisterMultiple.GetHashCode();
                    int length = dataList.Count * 2;
                    //1.拼接報(bào)文:
                    var sendCommand = new List<byte>();
 
                    //協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量+CRC
                    //站地址
                    sendCommand.Add(devAddr);
                    //功能碼
                    sendCommand.Add(functionCode);
                    //寫入地址
                    sendCommand.Add((byte)(startAddr / 256));
                    sendCommand.Add((byte)(startAddr % 256));
                    //寄存器數(shù)量
                    sendCommand.Add((byte)(length / 256));
                    sendCommand.Add((byte)(length % 256));
                    // 獲取數(shù)值的byte[]
                    List<byte> valueBytes = new List<byte>();
                    foreach (var data in dataList)
                    {
                        List<byte> temp = new List<byte>(BitConverter.GetBytes(data));
                        temp.Reverse();// 調(diào)整字節(jié)序
                        valueBytes.AddRange(temp);
                    }
                    // 字節(jié)數(shù)
                    sendCommand.Add((byte)valueBytes.Count);
                    sendCommand.AddRange(valueBytes);
                    //CRC
                    byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
                    sendCommand.AddRange(crc);
 
                    //000004 - Rx:01 10 00 02 00 04 08 42 F6 E6 66 41 64 CC CD 83 23
                    //000005 - Tx:01 10 00 02 00 04 60 0A
                    //000006 - Rx:01 0A 00 02 00 04 08 42 F6 E6 66 41 64 CC CD 98 F9
                    //000007 - Tx:01 8A 01 86 A0 //報(bào)錯(cuò)了
 
                    //2.發(fā)送報(bào)文
                    SerialPortObj.Write(sendCommand.ToArray(), 0, sendCommand.Count);
                    //3.接收報(bào)文
                    Thread.Sleep(50);//要延時(shí)一下,才能讀到數(shù)據(jù)
 
                    //讀取響應(yīng)報(bào)文
                    byte[] respBytes = new byte[SerialPortObj.BytesToRead];
                    SerialPortObj.Read(respBytes, 0, respBytes.Length);
                    // respBytes -> 01 01 02 00 00 B9 FC
 
                    // 檢查一個(gè)校驗(yàn)位
                    if (CheckCRC(respBytes) && respBytes[0] == devAddr && respBytes[1] == functionCode)
                    {
                        resultModel.IsSucceed = true;
                    }
                    else
                    {
                        resultModel.Msg = "響應(yīng)報(bào)文校驗(yàn)失敗";
                    }
                }
                catch (Exception ex)
                {
                    resultModel.Msg = "異常:" + ex.Message;
                }
                //SerialPortObj.Close();
            }
            else
            {
                resultModel.Msg = "dataLis參數(shù)不能為NULL 且 Count 要大于0";
            }
            return resultModel;
        }
 
        /// <summary>
        /// 寫單個(gè)線圈輸出 ok
        /// </summary>
        /// <param name="on">開關(guān)</param>
        /// <param name="devAddr">從站地址</param>
        /// <param name="startAddr">寫入地址</param>
        /// <returns></returns>
        public ModbusResultModel WriteSingleOutOnOff(bool on, byte devAddr = 1, ushort startAddr = 0)
        {
            var resultModel = new ModbusResultModel();
            try
            {
                //var isOk = false;
                //1.拼接報(bào)文:
                var sendCommand = new List<byte>();
                //協(xié)議格式:站地址+功能碼+起始寄存器地址+寄存器數(shù)量+CRC
                //站地址
                sendCommand.Add(devAddr);
                //功能碼
                byte functionCode = 0x05;
                sendCommand.Add(functionCode);
                //寫入地址
                sendCommand.Add((byte)(startAddr / 256));
                sendCommand.Add((byte)(startAddr % 256));
                //寫入數(shù)據(jù)
                sendCommand.Add((byte)(on ? 0xFF : 0x00));//true : 0xFF 開,false : 0x00 關(guān)
                sendCommand.Add(0x00);
                //CRC
                byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
                sendCommand.AddRange(crc);
                //2.發(fā)送報(bào)文
                SerialPortObj.Write(sendCommand.ToArray(), 0, sendCommand.Count);
                //isOk = true;
                resultModel.IsSucceed = true;
            }
            catch (Exception ex)
            {
                resultModel.Msg = "異常:" + ex.Message;
            }
            return resultModel;
        }
    }
}

Modbus 串口通訊 讀線圈狀態(tài)

(這個(gè)類是針對線圈的 突出讀取數(shù)據(jù))

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CJH.ModbusTool.RTU
{
    /// <summary>
    /// Modbus 串口通訊 讀線圈狀態(tài)
    /// </summary>
    public class ModbusRTUCoil : ModbusRTU
    {
        //ModbusRTU rtu = new ModbusRTU(portName);
        //var resultModel = rtu.ReadData(1, readLen, ModbusFunctionCode.ReadOutCoil);
 
        /// <summary>
        /// Modbus 串口通訊
        /// </summary>
        /// <param name="portName">COM口名稱</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">檢驗(yàn)位</param>
        /// <param name="dataBits">數(shù)據(jù)位</param>
        /// <param name="stopBits">停止位</param>
        public ModbusRTUCoil(string portName, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
            : base(portName, baudRate, parity, dataBits, stopBits)
        {
            //Init(portName, baudRate, parity, dataBits, stopBits);
            //SerialPortObj.DataReceived += new SerialDataReceivedEventHandler(ComDataReceived);
        }
 
        /// <summary>
        /// 讀取線圈數(shù)據(jù) ok
        /// </summary>
        /// <param name="devAdd">從站地址</param>
        /// <param name="length">寄存器數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始寄存器地址</param>
        /// <returns>線圈數(shù)據(jù)</returns>
        public ModbusResultModel<bool> ReadDataCoil(byte devAdd, ushort length, ModbusFunctionCode functionCode = ModbusFunctionCode.ReadRegister, ushort startAddr = 0)
        {
            var resultModel = new ModbusResultModel<bool>();
            var model = ReadData(devAdd, length, (byte)functionCode, startAddr);
            if (model != null && model.Datas != null && model.Datas.Length > 5)
            {
                resultModel.IsSucceed = model.IsSucceed;
                //報(bào)文解析
                // 檢查一個(gè)校驗(yàn)位
                List<byte> respList = new List<byte>(model.Datas);
                respList.RemoveRange(0, 3);
                respList.RemoveRange(respList.Count - 2, 2);
                // 00 00
                //集合反轉(zhuǎn)
                respList.Reverse();
                //轉(zhuǎn)換成2進(jìn)制
                var respStrList = respList.Select(r => Convert.ToString(r, 2)).ToList();
                var values = string.Join("", respStrList).ToList();
                values.Reverse();
                //values.ForEach(c => Console.WriteLine(Convert.ToBoolean(int.Parse(c.ToString()))));
                foreach (var v in values)
                {
                    resultModel.ResultList.Add(v.ToString() == "1");
                }
            }
            return resultModel;
        }
    }
}

TCP

ModbusTCP 基類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
 
namespace CJH.ModbusTool.TCP
{
    /// <summary>
    /// ModbusTCP 基類
    /// </summary>
    public abstract class ModbusTCPBase : ModbusBase
    {
        private Socket _socket = null;
        ushort _tid = 0;//TransactionId 最大 65535
 
        /// <summary>
        /// 異常碼 字典
        /// </summary>
        protected Dictionary<int, string> Errors = new Dictionary<int, string>() {
            { 0x01 , "非法功能碼"},
            { 0x02 , "非法數(shù)據(jù)地址"},
            { 0x03 , "非法數(shù)據(jù)值"},
            { 0x04 , "從站設(shè)備故障"},
            { 0x05 , "確認(rèn),從站需要一個(gè)耗時(shí)操作"},
            { 0x06 , "從站忙"},
            { 0x08 , "存儲奇偶性差錯(cuò)"},
            { 0x0A , "不可用網(wǎng)關(guān)路徑"},
            { 0x0B , "網(wǎng)關(guān)目標(biāo)設(shè)備響應(yīng)失敗"},
        };
 
        /// <summary>
        /// Modbus TCP 通訊 初始化
        /// </summary>
        /// <param name="host">主機(jī)地址</param>
        /// <param name="port">端口</param>
        protected void Init(string host, int port)
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Connect(host, port);
        }
 
        /// <summary>
        /// 讀取報(bào)文的 公共方法
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="length">寄存器數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始寄存器地址</param>
        /// <returns>返回報(bào)文(協(xié)議格式:TransactionId+協(xié)議標(biāo)識+后續(xù)字節(jié)數(shù)+站地址+功能碼+起始寄存器地址+寄存器數(shù)量)</returns>
        protected byte[] GenerateTcpCommandReadBytes(byte devAddr, ushort length, ModbusFunctionCode functionCode = ModbusFunctionCode.ReadRegister, ushort startAddr = 0)
        {
            var baseCommand = GenerateReadCommandBytes(devAddr, length, functionCode, startAddr);
 
            var sendCommand = new List<byte>();
            //TransactionId
            sendCommand.Add((byte)(_tid / 256));
            sendCommand.Add((byte)(_tid % 256));
            //Modbus 協(xié)議標(biāo)識
            sendCommand.Add(0x00);
            sendCommand.Add(0x00);
            //后續(xù)字節(jié)數(shù)
            sendCommand.Add((byte)(baseCommand.Length / 256));
            sendCommand.Add((byte)(baseCommand.Length % 256));
            _tid++;
            _tid %= 65535;
            sendCommand.AddRange(baseCommand);
            return sendCommand.ToArray();
        }
 
        /// <summary>
        /// 讀取報(bào)文的 公共方法
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="data">輸入數(shù)據(jù)</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始寄存器地址</param>
        /// <returns>返回報(bào)文(協(xié)議格式:TransactionId+協(xié)議標(biāo)識+后續(xù)字節(jié)數(shù)+站地址+功能碼+起始寄存器地址+寄存器數(shù)量)</returns>
        protected byte[] GenerateTcpCommandWriteBytes(byte devAddr, ushort data, ModbusFunctionCode functionCode = ModbusFunctionCode.WriteRegister, ushort startAddr = 0)
        {
            var baseCommand = GenerateWriteCommandBytes(devAddr, data, functionCode, startAddr);
 
            var sendCommand = new List<byte>();
            //TransactionId
            sendCommand.Add((byte)(_tid / 256));
            sendCommand.Add((byte)(_tid % 256));
            //Modbus 協(xié)議標(biāo)識
            sendCommand.Add(0x00);
            sendCommand.Add(0x00);
            //后續(xù)字節(jié)數(shù)
            sendCommand.Add((byte)(baseCommand.Length / 256));
            sendCommand.Add((byte)(baseCommand.Length % 256));
            _tid++;
            _tid %= 65535;
            sendCommand.AddRange(baseCommand);
            return sendCommand.ToArray();
        }
 
        protected ModbusResultModel SendCommand(byte[] sendCommand)
        {
            var resultModel = new ModbusResultModel();
            try
            {
                //報(bào)文
                //TransactionId Modbus 協(xié)議標(biāo)識 后續(xù)字節(jié)數(shù)  從站地址  功能碼         起始寄存器地址  寄存器數(shù)量  CRC
                //0x00 0x01     0x00   0x00     0x00  0x06  devAddr   functionCode   0x00  0x0A      
 
                resultModel.SendDataStr = generateSendCommandStr(sendCommand.ToArray());
                _socket.Send(sendCommand.ToArray());
                //000002-Rx:00 00 00 00 00 06 01 03 00 01 00 05
                //000003-Tx:00 00 00 00 00 0D 01 03 0A 00 00 00 00 00 00 00 00 00 00
                // 00 00 00 00 00 0D 前6位
                // 01 03 0A (0,1,2)
                // 0A 數(shù)據(jù)長度 (0A=10)
 
                //先取前6位,固定返回
                var resp_bytes = new byte[6];// 00 00 00 00 00 0D 前6位
                _socket.Receive(resp_bytes, 0, resp_bytes.Length, SocketFlags.None);
 
                //取出下標(biāo)為 :4和5的數(shù)據(jù)[00 0D]
                var len_bytes = resp_bytes.ToList().GetRange(4, 2);
                //起始寄存器地址 的反向操作
                //將下標(biāo)為4和5 兩個(gè)字節(jié)轉(zhuǎn)成10進(jìn)制數(shù)
                int len = len_bytes[0] * 256 + len_bytes[1];
 
                //獲取數(shù)據(jù)的長度
                //01 03 0A 00 00 00 00 00 00 00 00 00 00 [正常]
                //01 83 02 [異常,83, 異常代碼 :02]
                resp_bytes = new byte[len];
                _socket.Receive(resp_bytes, 0, len, SocketFlags.None);
 
                //檢查響應(yīng)報(bào)文是否正常
                //0x83 1000 0011
                //01 83 02 [異常,83, 異常代碼 :02]
                if (resp_bytes[1] > 0x08)//判斷是否異常
                {
                    //resp_bytes[2] = 異常代碼 :02
                    //說明響應(yīng)是異常報(bào)文
                    //返回異常信息,根據(jù)resp_bytes字節(jié)進(jìn)行異常關(guān)聯(lián)
                    if (Errors.ContainsKey(resp_bytes[2]))
                    {
                        resultModel.Msg = Errors[resp_bytes[2]];//獲取異常碼對應(yīng)的異常說明
                    }
                }
                else
                {
                    //resp_bytes[2] = 0A 數(shù)據(jù)長度 (0A=10)
                    //正常
                    resultModel.Datas = resp_bytes.ToList().GetRange(3, resp_bytes[2]).ToArray();
                    resultModel.IsSucceed = true;
                }
            }
            catch (Exception ex)
            {
                resultModel.Msg = ex.Message;
            }
            return resultModel;
        }
 
        /// <summary>
        /// 解析數(shù)據(jù)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="datas"></param>
        /// <returns></returns>
        public List<T> AnalysisDatas<T>(byte[] datas)
        {
            //data_bytes 每兩個(gè)字節(jié)轉(zhuǎn)成一個(gè)數(shù)字, float 4個(gè)字節(jié)轉(zhuǎn)成一個(gè)數(shù)字,double 8個(gè)字節(jié)轉(zhuǎn)成一個(gè)數(shù)字
            //2  ushort short int16 uint32 float
            //4  int uint int32 uint32 float
            //8  double
            //16 decimal
            var resultValue = new List<T>();
            try
            {
                var type_len = Marshal.SizeOf(typeof(T));
                for (int i = 0; i < datas.Length; i += type_len)
                {
                    var temp_bytes = datas.ToList().GetRange(i, type_len);
                    if (BitConverter.IsLittleEndian)
                    {
                        temp_bytes.Reverse();
                    }
                    //反射 方法
                    Type bitConverter_type = typeof(BitConverter);
                    var typeMethodList = bitConverter_type.GetMethods().ToList();
                    //找到返回類型和傳入的類型一至,且方法的參數(shù)是2個(gè)的方法
                    var method = typeMethodList.FirstOrDefault(mi => mi.ReturnType == typeof(T)
                                        && mi.GetParameters().Length == 2);
                    if (method == null)
                    {
                        throw new Exception("數(shù)據(jù)轉(zhuǎn)換類型出錯(cuò)!");
                    }
                    else
                    {
                        //由 bitConverter_type 執(zhí)行找到的 method方法,注意參數(shù)數(shù)量,上面找是的兩個(gè)參數(shù)的方法
                        var value = method.Invoke(bitConverter_type, new object[] { temp_bytes.ToArray(), 0 });
                        resultValue.Add((T)value);
                    }
                }
            }
            catch (Exception ex)
            {
 
            }
            return resultValue;
        }
    }
}

Modbus TCP 通訊

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
 
namespace CJH.ModbusTool.TCP
{
    /// <summary>
    /// Modbus TCP 通訊
    /// </summary>
    public class ModbusTCP : ModbusTCPBase
    {
 
        /// <summary>
        /// Modbus TCP 通訊
        /// </summary>
        /// <param name="host">主機(jī)地址</param>
        /// <param name="port">端口</param>
        public ModbusTCP(string host, int port)
        {
            //_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //_socket.Connect(host, port);
            Init(host, port);
        }
 
        /// <summary>
        /// 讀取保持型寄存器 03
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="count">數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始地址</param>
        //public ModbusResultModel ReadHoldingRegister(byte devAddr, ushort length, byte functionCode = 3, ushort startAddr = 0)
        //{
        //    var resultModel = new ModbusResultModel();
        //    //報(bào)文
        //    //TransactionId Modbus 協(xié)議標(biāo)識 后續(xù)字節(jié)數(shù)  從站地址  功能碼         起始寄存器地址  寄存器數(shù)量  CRC
        //    //0x00 0x01     0x00   0x00     0x00  0x06  devAddr   functionCode   0x00  0x0A      
        //    try
        //    {
        //        ushort tid = 0;//TransactionId 最大 65535
 
        //        var sendCommand = new List<byte>();
        //        //TransactionId
        //        sendCommand.Add((byte)(tid / 256));
        //        sendCommand.Add((byte)(tid % 256));
        //        //Modbus 協(xié)議標(biāo)識
        //        sendCommand.Add(0x00);
        //        sendCommand.Add(0x00);
        //        //后續(xù)字節(jié)數(shù)
        //        sendCommand.Add(0x00);
        //        sendCommand.Add(0x06);
        //        //從站地址
        //        sendCommand.Add(devAddr);
        //        //功能碼
        //        sendCommand.Add(functionCode);
        //        //起始寄存器地址
        //        sendCommand.Add((byte)(startAddr / 256));
        //        sendCommand.Add((byte)(startAddr % 256));
        //        //寄存器數(shù)量
        //        sendCommand.Add((byte)(length / 256));
        //        sendCommand.Add((byte)(length % 256));
        //        //CRC
        //        //byte[] crc = Crc16(sendCommand.ToArray(), sendCommand.Count);
        //        //sendCommand.AddRange(crc);
        //        tid++;
        //        tid %= 65535;
        //        resultModel.SendDataStr = generateSendCommandStr(sendCommand.ToArray());
        //        _socket.Send(sendCommand.ToArray());
        //        //000002-Rx:00 00 00 00 00 06 01 03 00 01 00 05
        //        //000003-Tx:00 00 00 00 00 0D 01 03 0A 00 00 00 00 00 00 00 00 00 00
        //        // 00 00 00 00 00 0D 前6位
        //        // 01 03 0A (0,1,2)
        //        // 0A 數(shù)據(jù)長度 (0A=10)
 
        //        //先取前6位,固定返回
        //        var resp_bytes = new byte[6];// 00 00 00 00 00 0D 前6位
        //        _socket.Receive(resp_bytes, 0, resp_bytes.Length, SocketFlags.None);
 
        //        //取出下標(biāo)為 :4和5的數(shù)據(jù)[00 0D]
        //        var len_bytes = resp_bytes.ToList().GetRange(4, 2);
        //        //起始寄存器地址 的反向操作
        //        //將下標(biāo)為4和5 兩個(gè)字節(jié)轉(zhuǎn)成10進(jìn)制數(shù)
        //        int len = resp_bytes[4] * 256 + resp_bytes[5];
 
        //        //獲取數(shù)據(jù)的長度
        //        //01 03 0A 00 00 00 00 00 00 00 00 00 00 [正常]
        //        //01 83 02 [異常,83, 異常代碼 :02]
        //        resp_bytes = new byte[len];
        //        _socket.Receive(resp_bytes, 0, len, SocketFlags.None);
 
        //        //檢查響應(yīng)報(bào)文是否正常
        //        //0x83 1000 0011
        //        //01 83 02 [異常,83, 異常代碼 :02]
        //        if (resp_bytes[1] > 0x08)//判斷是否異常
        //        {
        //            //resp_bytes[2] = 異常代碼 :02
        //            //說明響應(yīng)是異常報(bào)文
        //            //返回異常信息,根據(jù)resp_bytes字節(jié)進(jìn)行異常關(guān)聯(lián)
        //            if (Errors.ContainsKey(resp_bytes[2]))
        //            {
        //                resultModel.Msg = Errors[resp_bytes[2]];//獲取異常碼對應(yīng)的異常說明
        //            }
        //        }
        //        else
        //        {
        //            //resp_bytes[2] = 0A 數(shù)據(jù)長度 (0A=10)
        //            //正常
        //            resultModel.Datas = resp_bytes.ToList().GetRange(3, resp_bytes[2]).ToArray();
        //            resultModel.IsSucceed = true;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        resultModel.Msg = ex.Message;
        //    }
        //    return resultModel;
        //}
 
        /// <summary>
        /// 讀取保持型寄存器 03
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="length">數(shù)量</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始地址</param>
        /// <returns>返回對象</returns>
        public ModbusResultModel<T> ReadHoldingRegister<T>(byte devAddr, ushort length, ModbusFunctionCode functionCode = ModbusFunctionCode.ReadRegister, ushort startAddr = 0)
        {
            var resultModel = new ModbusResultModel<T>();
            try
            {
                var command = GenerateTcpCommandReadBytes(devAddr, length, functionCode, startAddr);
 
                resultModel.SendDataStr = generateSendCommandStr(command.ToArray());
                var receptionModel = SendCommand(command.ToArray());
                if (receptionModel.IsSucceed
                    && receptionModel.Datas != null && receptionModel.Datas.Length > 0)
                {
                    resultModel.Datas = receptionModel.Datas;
                    resultModel.ResultList = AnalysisDatas<T>(receptionModel.Datas);
                    resultModel.IsSucceed = true;
                }
            }
            catch (Exception ex)
            {
                resultModel.Msg = ex.Message;
            }
            return resultModel;
        }
 
        /// <summary>
        /// 寫入保持型寄存器 03
        /// </summary>
        /// <param name="devAddr">從站地址</param>
        /// <param name="datas">寫入數(shù)據(jù)</param>
        /// <param name="functionCode">功能碼</param>
        /// <param name="startAddr">起始地址</param>
        /// <returns>返回對象</returns>
        public ModbusResultModel WriteHoldingRegister(byte devAddr, ushort data, ModbusFunctionCode functionCode = ModbusFunctionCode.WriteRegister, ushort startAddr = 0)
        {
            var resultModel = new ModbusResultModel();
            try
            {
                var command = GenerateTcpCommandWriteBytes(devAddr, data, functionCode, startAddr);
 
                resultModel.SendDataStr = generateSendCommandStr(command.ToArray());
                var receptionModel = SendCommand(command.ToArray());
                if (receptionModel.IsSucceed)
                {
                    resultModel.IsSucceed = true;
                }
            }
            catch (Exception ex)
            {
                resultModel.Msg = ex.Message;
            }
            return resultModel;
        }
    }
}

這就是全部的代碼。

以上就是使用C#實(shí)現(xiàn)自己封裝的Modbus工具類庫的詳細(xì)內(nèi)容,更多關(guān)于C# Modbus的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論