Modbus 串口 C#

前言

Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。

Modbus允许多个 (大约240个) 设备连接在同一个网络上进行通信,举个例子,一个测量温度和湿度的装置,并且将结果发送给计算机。在数据采集与监视控制系统(SCADA)中,Modbus通常用来连接监控计算机和远程终端控制系统(RTU)。

常用用法

在这里插入图片描述

通讯格式

以功能码03为例
在这里插入图片描述

C#实验常用的03,06,10

 public class Modbus
    {
        protected SerialPort port;
        public Modbus(SerialPort serialPort)
        {
            this.port = serialPort;
        }

        public void OpenPort()
        {
            try
            {
                if (!port.IsOpen)
                {
                    port.Open();
                }
                port.DiscardInBuffer();
                port.DiscardOutBuffer();
            }
            catch (Exception ex)
            {
            }
        }

        public void ClosePort()
        {
            try
            {
                if (port != null && port.IsOpen)
                {
                    port.Close();
                    port = null;
                }
            }
            catch (Exception ex)
            {
            }
        }

        protected int ReadData(byte[] buffer, int expectCount = 0)
        {
            int r = port.Read(buffer, 0, buffer.Length);
            while (port.BytesToRead > 0)
            {
                int n = port.Read(buffer, r, buffer.Length - r);
                r += n;
            }
            while (r < expectCount)
            {
                r += port.Read(buffer, r, buffer.Length - r);
            }       
            return r;
        }

        /// <summary>
        /// 读取保持型寄存器 功能码03
        /// </summary>
        /// <param name="stationID">站号</param>
        /// <param name="addr">寄存器地址</param>
        /// <param name="length">寄存器数量</param>
        /// <param name="buffer">接收数据的缓存</param>
        /// <returns>收到的字节数</returns>
        public int ReadRegister(int stationID, ushort addr, int length, byte[] buffer)
        {
            OpenPort();
            byte[] cmdHead = new byte[6];
            cmdHead[0] = (byte)stationID;
            cmdHead[1] = 0x03;
            cmdHead[2] = (byte)((addr >> 8) & 0xFF);
            cmdHead[3] = (byte)(addr & 0xFF);
            cmdHead[4] = (byte)((length >> 8) & 0xFF);
            cmdHead[5] = (byte)(length & 0xFF);
            byte[] command = CRC.AppendCRC16(cmdHead);
            //发送指令
            port.Write(command, 0, command.Length);
            int bytes = ReadData(buffer, 5 + 2 * length);
            return bytes;
        }


        /// <summary>
        /// 写入保持型寄存器 功能码06
        /// </summary>
        /// <param name="stationID">站号</param>
        /// <param name="addr">寄存器地址</param>
        /// <param name="value">写入值</param>
        /// <returns></returns>
        public int WriteRegister(int stationID, ushort addr, int value, byte[] buffer = null)
        {
            OpenPort();
            byte[] cmdHead = new byte[6];
            cmdHead[0] = (byte)stationID;
            cmdHead[1] = 0x06;
            cmdHead[2] = (byte)((addr >> 8) & 0xFF);
            cmdHead[3] = (byte)(addr & 0xFF);
            cmdHead[4] = (byte)((value >> 8) & 0xFF);
            cmdHead[5] = (byte)(value & 0xFF);
            byte[] command = CRC.AppendCRC16(cmdHead);

            //发送指令。
            port.Write(command, 0, command.Length);
            if (buffer != null)
            {
                int bytes = ReadData(buffer, 8);
                return bytes;
            }
            return 0;
        }

        /// <summary>
        /// 写入一段连续的寄存器 功能码10
        /// </summary>
        /// <param name="stationID">站号</param>
        /// <param name="addr">寄存器地址</param>
        /// <param name="value">写入值</param>
        /// <returns></returns>
        public int WriteRegisters(int stationID, ushort addr, byte[] value, byte[] buffer = null)
        {
            OpenPort();
            int registerCount = value.Length / 2;
            byte[] cmdHead = new byte[7 + value.Length];
            cmdHead[0] = (byte)stationID;
            cmdHead[1] = 0x10;
            cmdHead[2] = (byte)((addr >> 8) & 0xFF);
            cmdHead[3] = (byte)(addr & 0xFF);
            cmdHead[4] = (byte)((registerCount >> 8) & 0xFF);
            cmdHead[5] = (byte)(registerCount & 0xFF);
            cmdHead[6] = (byte)(value.Length & 0xFF);
            for (int i = 0; i < value.Length; i++)
            {
                cmdHead[7 + i] = value[i];
            }
            byte[] command = CRC.AppendCRC16(cmdHead);

            //发送指令。
            port.Write(command, 0, command.Length);
            if (buffer != null)
            {
                int bytes = ReadData(buffer, 8);
                return bytes;
            }
            return 0;
        }

长期分享工控干货,喜欢的话可以点赞关注,谢谢!

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
/// /// 读保持寄存器03 /// /// 数据读取延迟 /// 设备从站地址 /// 数据起始地址 /// 寄存器数量 /// 返回的寄存器数值 /// 返回异常描述 /// 是否读取成功 public bool ReadHoldReg(int timeout, byte slaveAddress, ushort startAddress, ushort regCountIn, out ushort[] holdRegs, out ModbusException ex) /// /// 读输入寄存器04 /// /// 数据读取延迟 /// 设备从站地址 /// 数据地址 /// 寄存器数量 /// 返回的寄存器数值 /// 返回异常描述 /// 是否读取成功 public bool ReadInputReg(int timeout, byte slaveAddress, ushort startAddress, ushort regCountIn, out ushort[] InputRegs, out ModbusException ex) /// /// 写单寄存器(06功能码) /// /// 数据读取延迟 /// 设备从站地址 /// 寄存器地址 /// 寄存器值 /// 返回异常描述 /// 是否写入成功 public bool WriteSingleReg(int timeout, byte slaveAddress, ushort regAdr, ushort regValue, out ModbusException ex) /// /// 写单个线圈(05功能码) /// /// 数据读取延迟 /// 设备从站地址 /// 寄存器地址 /// 寄存器值 /// 返回异常描述 /// 是否写入成功 public bool WriteSingleCoil(int timeout, byte slaveAddress, ushort regAdr, ushort ONorOFF, out ModbusException ex) /// /// 写多寄存器(10功能码) /// /// 数据读取延迟 /// 设备从站地址 /// 寄存器起始地址 /// 寄存器值 /// 返回异常描述 /// 是否写入成功 public bool WriteMutilReg(int timeout, byte slaveAddress, ushort regAdr, ushort[] regValue, out ModbusException ex) ....................
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值