C#中如何和西门子通信

cs 复制代码
public interface IPlcDevice :IDisposable
{
    /// <summary>
    /// PLC连接状态
    /// </summary>
    bool IsConnected { get; }

    /// <summary>
    /// 连接PLC
    /// </summary>
    /// <returns></returns>
    bool Connect();

    /// <summary>
    /// 断开连接
    /// </summary>
    void Disconnect();


    #region 同步读写方法
    /// <summary>
    /// 读取一个模块所有字节地址数据
    /// </summary>
    /// <param name="startByte"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    byte[] ReadDB6Bytes(int DBnum, int startByte, int length);
    /// <summary>
    /// 写字节
    /// </summary>
    /// <param name="startAddress"></param>
    /// <param name="value"></param>
    void WriteBytes(ushort startAddress, int value);
    /// <summary>
    /// 读取保持寄存器
    /// </summary>
    /// <param name="startAddress">起始地址</param>
    /// <param name="numberOfPoints">长度</param>
    /// <returns></returns>
    ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfPoints);
    /// <summary>
    /// 读取单个保存寄存器
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <returns></returns>
    ushort ReadSingleRegisters(ushort startAddress);
    /// <summary>
    /// 读取单个保存寄存器
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <param name="s">位</param>
    /// <returns></returns>
    ushort ReadSingleRegisters(ushort startAddress, byte s);
    /// <summary>
    /// 读取线圈
    /// </summary>
    /// <param name="startAddress">起始地址</param>
    /// <param name="numberOfPoints">长度</param>
    /// <returns></returns>
    bool[] ReadCoils(ushort startAddress, ushort numberOfPoints);
    /// <summary>
    /// 向指定位地址写值
    /// </summary>
    /// <param name="startAddress">字节地址</param>
    /// <param name="bitAddress">位地址</param>
    /// <param name="value">值</param>
    void WriteSingleRegister(ushort address, ushort bitAddress, int value);
    /// <summary>
    /// 写单个寄存器
    /// </summary>
    /// <param name="address">地址</param>
    /// <param name="value">写入值</param>
    void WriteSingleRegister(ushort address, ushort value);
    /// <summary>
    /// 写多个寄存器
    /// </summary>
    /// <param name="startAddress">起始地址</param>
    /// <param name="values">写入值数组</param>
    void WriteMultipleRegisters(ushort startAddress, ushort[] values);
    /// <summary>
    /// 写单个线圈
    /// </summary>
    /// <param name="address">地址</param>
    /// <param name="value">写入值</param>
    void WriteSingleCoil(ushort address, bool value);
    /// <summary>
    /// 读取32位长整型数
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <returns></returns>
    int ReadInt32(ushort startAddress);
    
    /// <summary>
    /// 写入32位整型数
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <param name="value">写入值</param>
    void WriteInt32(ushort startAddress, int value);
    /// <summary>
    /// 读取浮点数
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <returns></returns>
    float ReadFloat(ushort startAddress);
    /// <summary>
    /// 读取字符串
    /// </summary>
    /// <param name="startAddress">起始地址</param>
    /// <param name="wordLength">字长度</param>
    /// <param name="encoding">编码格式</param>
    /// <returns></returns>
    string ReadString(ushort startAddress, ushort wordLength = 20, Encoding encoding = null);     
    /// <summary>
    /// 读取字符串,自动判断编码格式
    /// </summary>
    /// <param name="startAddress">起始地址</param>
    /// <param name="wordLength">字长度</param>
    /// <returns></returns>
    string ReadStringAutoDetect(ushort startAddress, ushort wordLength = 20);
    /// <summary>
    /// 写入字符串
    /// </summary>
    /// <param name="startAddress">起始地址</param>
    /// <param name="text">写入文本</param>
    /// <param name="encoding">编码格式</param>
    void WriteString(ushort startAddress, string text, Encoding encoding = null);
    #endregion

    #region 异步读写方法
    /// <summary>
    /// 异步读取db模块所有字节地址
    /// </summary>
    /// <param name="dbNumber"></param>
    /// <param name="startByte"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    Task<byte[]> ReadBytesAsync(int dbNumber, int startByte, int length);

    /// <summary>
    /// 异步读单个保持寄存器
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <returns></returns>
    Task<ushort> ReadSingleRegistersAsync(ushort startAddress);
    /// <summary>
    /// 异步写单个保持寄存器
    /// </summary>
    /// <param name="address">地址</param>
    /// <param name="value">写入值</param>
    /// <returns></returns>
    Task WriteSingleRegisterAsync(ushort address, ushort value);
    /// <summary>
    /// 异步读浮点数
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <returns></returns>
    Task<float> ReadFloatAsync(ushort startAddress);
    /// <summary>
    /// 异步写浮点数
    /// </summary>
    /// <param name="address">地址</param>
    /// <param name="value">写入值</param>
    /// <returns></returns>
    Task WriteFloatAsync(ushort address, float value);
    /// <summary>
    /// 异步读32位整数
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <returns></returns>
    Task<int> ReadInt32Async(ushort startAddress);
    /// <summary>
    /// 异步写32位整数
    /// </summary>
    /// <param name="address">地址</param>
    /// <param name="value">写入值</param>
    /// <returns></returns>
    Task WriteInt32Async(ushort address, int value);
    /// <summary>
    /// 异步读取字符串
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <param name="wordLength">字长度</param>
    /// <param name="encoding">解码方式</param>
    /// <returns></returns>
    Task<string> ReadStringAsync(ushort startAddress, ushort wordLength = 20, Encoding encoding = null);
    /// <summary>
    /// 异步写字符串
    /// </summary>
    /// <param name="startAddress">地址</param>
    /// <param name="text">写入文本</param>
    /// <returns></returns>
    Task WriteStringAsync(ushort startAddress,string text, Encoding encoding = null);


    #endregion

}
cs 复制代码
using NPOI.SS.Formula.Functions;
using NPOI.XSSF.Streaming.Values;
using S7.Net;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar;
using DataType = S7.Net.DataType;

namespace Aliro.Agv.HardWare
{
    public class SimaticS7Net : IPlcDevice
    {

        //DataType.DataBlock, 1:
        //对于 S7-200 SMART,其 V 存储区被映射为 DB1。所以当你访问 V 区时,DataType 是 DataBlock,db 参数是 1。
        //例如,VB100 的地址是 DataType.DataBlock, 1, 100, VarType.Byte, 1。
        // 注意注意:如果按照字或者双字访问,地址必须按照双数的方式访问

        //地址计算:
        //startByte 参数是字节地址。VW102 表示从第102个字节开始的一个字(2字节),所以 startByte 是 102。
        //bitAdr 参数是位地址(0-7),只在读写 VarType.Bit 时使用。

        //数据类型和转换:
        //PLC 中的数据类型(如 WORD, DWORD)需要与 C# 中的类型(ushort, uint)正确匹配,特别是处理无符号数时。
        //注意字节序(大端序),S7NetPlus 会自动处理转换。

        //错误处理:
        //务必使用 try-catch 块包裹所有读写操作,因为网络不稳定或 PLC 停机都会导致异常。
        //在操作前检查 plc.IsConnected 状态。

        //常见错误:
        //ErrorNumber : 0x8324:通常表示 IP 地址错误、网络不通或 PLC 未正确启用 GET/PUT 通信。
        //Object reference not set to an instance of an object:plc 对象未初始化。
        //写入值后读取不一致:检查 PLC 程序中是否有其他地方(如逻辑程序)在重写你正在操作的数据区。


        private Plc _plc;
        private string _ipAddress;
        private CpuType _cpuType = CpuType.S71200;

        public short DbNo = 6;  
        public short Rack = 1;
        public short Slot = 1;
        public bool IsConnected => _plc.IsConnected == true;

        public SimaticS7Net(string ipAddress, CpuType _cpuType, short dbNo = 1, short rack = 0, short slot = 1)
        {
            _ipAddress = ipAddress;
            this._cpuType = _cpuType; // CPU类型
            _plc = new Plc(_cpuType, _ipAddress, rack, slot); // 机架号0,槽号1
            DbNo = dbNo;
            Rack = rack;
            Slot = slot;
        }

        public bool Connect()
        {
            try
            {
                if (_plc == null)
                {
                    _plc = new Plc(_cpuType, _ipAddress, Rack, Slot);
                }
                _plc.Open();
                if (_plc.IsConnected)
                {
                    //Console.WriteLine("成功连接到 PLC (S7协议)");
                    return true;
                }
                else
                {
                    //Console.WriteLine("连接失败");
                    return false;
                }
            }
            catch (Exception ex)
            {
                //Console.WriteLine($"连接失败: {ex.Message}");
                return false;
            }
        }

        public void Disconnect()
        {
            try
            {
                _plc?.Close();
                _plc = null;
                //Console.WriteLine("已断开与 PLC 的连接");
            }
            catch (Exception ex)
            {
                //Console.WriteLine($"断开连接时出错: {ex.Message}");
            }
        }

        public void Dispose()
        {
            Disconnect();

            #region 读数据示例 
            //// 读取一个布尔值(位)从 V100.0 (V区,字节100,位0)
            //bool boolValue = (bool)_plc?.Read(DataType.DataBlock, 1, 100, VarType.Bit, 1);
            //Console.WriteLine($"V100.0 (Bool) 的值是: {boolValue}");

            //// 读取一个字节 (8位) 从 VB101
            //byte byteValue = (byte)_plc?.Read(DataType.DataBlock, 1, 101, VarType.Byte, 1);
            //Console.WriteLine($"VB101 (Byte) 的值是: {byteValue}");

            //// 读取一个16位整数 (Int) 从 VW102
            //short shortValue = (short)_plc?.Read(DataType.DataBlock, 1, 102, VarType.Word, 1);
            //// 注意:PLC中的VW102对应C#的short(Int16),并且是高位字节在前(大端序)
            //Console.WriteLine($"VW102 (Int) 的值是: {shortValue}");

            //// 读取一个32位整数 (DInt) 从 VD104
            //int intValue = (int)_plc?.Read(DataType.DataBlock, 1, 104, VarType.DInt, 1);
            //Console.WriteLine($"VD104 (DInt) 的值是: {intValue}");

            //// 读取一个32位浮点数 (Real) 从 VD108
            //float floatValue = (float)_plc?.Read(DataType.DataBlock, 1, 108, VarType.Real, 1);
            //Console.WriteLine($"VD108 (Real) 的值是: {floatValue}");

            //// 读取一个字符串从 VB200 (最大长度20)
            //// 字符串在PLC中通常第一个字节是最大长度,第二个字节是实际长度,后面是字符数据
            //string stringValue = (string)_plc?.Read(DataType.DataBlock, 1, 108, VarType.String, 20);
            //Console.WriteLine($"VB200 (String) 的值是: {stringValue}");
            #endregion

            #region 写数据示例
            //// 写入一个布尔值(位)到 V100.1
            //_plc.WriteBit(DataType.DataBlock, 1, 100, 1, true); // 将 V100.1 设置为 True
            //Console.WriteLine("已写入 V100.1 = True");

            //// 写入一个字节到 VB101
            //_plc.Write(DataType.DataBlock, 1, 101, (byte)123);
            //Console.WriteLine("已写入 VB101 = 123");

            //// 写入一个16位整数到 VW102
            //_plc.Write(DataType.DataBlock, 1, 102, (short)-4567);
            //Console.WriteLine("已写入 VW102 = -4567");

            //// 写入一个32位整数到 VD104
            //_plc.Write(DataType.DataBlock, 1, 104, 789012);
            //Console.WriteLine("已写入 VD104 = 789012");

            //// 写入一个32位浮点数到 VD108
            //_plc.Write(DataType.DataBlock, 1, 108, 123.45f);
            //Console.WriteLine("已写入 VD108 = 123.45");

            //// 写入一个字符串到 VB200
            //// 注意:S7NetPlus的WriteString方法会自动处理最大长度和实际长度字节
            //_plc.Write(DataType.DataBlock, 1, 200, "Hello from C#!");
            //Console.WriteLine("已写入字符串到 VB200");
            #endregion
        }
        #region 新增
        // 读取 DB6 中的所有字
        public byte[] ReadDB6Bytes(int DBnum, int startByte, int length)
        {
            try
            {
                if (!_plc.IsConnected)
                {
                    Console.WriteLine("PLC 未连接");
                    return null;
                }

                // 读取 DB6 中的数据块
                // 参数说明: DataBlockNumber, startByte, dataType, length
                var result = _plc.ReadBytes(DataType.DataBlock, DBnum, startByte, length);

                if (result == null || result.Length != length)
                {
                    Console.WriteLine($"读取失败或数据长度不正确");
                    return null;
                }

                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据时出错: {ex.Message}");
                return null;
            }
        }
        #endregion
        public bool[] ReadCoils(ushort startAddress, ushort numberOfPoints)
        {
            throw new InvalidOperationException("未连接到PLC");
        }

        public float ReadFloat(ushort startAddress)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                return (float)_plc.Read(DataType.DataBlock, DbNo, startAddress, VarType.Real, 1);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfPoints)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                var objValue = _plc.Read(DataType.DataBlock, DbNo, startAddress, VarType.Word, numberOfPoints);
                if (objValue is ushort[] result)
                {
                    return result;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public ushort ReadSingleRegisters(ushort startAddress)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                var result = (ushort)_plc.Read(DataType.DataBlock, DbNo, startAddress, VarType.Word, 1);
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取寄存器失败: {ex.Message}");
                throw;
            }
        }
        public ushort ReadSingleRegisters(ushort startAddress, byte s = 0)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                var result = (ushort)_plc.Read(DataType.DataBlock, DbNo, startAddress, VarType.Bit, 1, s);
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取寄存器失败: {ex.Message}");
                throw;
            }
        }

        public int ReadInt32(ushort startAddress)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                // 
                var value = _plc.Read(DataType.DataBlock, DbNo, startAddress, VarType.DInt, 1);
                return Convert.ToInt32(value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public string ReadString(ushort startAddress, ushort wordLength = 20, Encoding encoding = null)
        {
            if (!IsConnected || _plc == null)
                throw new InvalidOperationException("未连接到PLC");

            if (encoding == null)
                encoding = Encoding.ASCII;

            try
            {
                // 读取一个字符串从 VB 
                // 字符串在PLC中通常第一个字节是字符长度,后面是字符数据
                var str = (string)_plc?.Read(DataType.DataBlock, DbNo, startAddress, VarType.String, wordLength * 2);

                //var objValue = _plc?.Read(DataType.DataBlock, 1, startAddress, VarType.Byte, wordLength * 2);
                //// 移除首字节
                //byte[] strBytes = (byte[])objValue;                 
                //var strASCII = encoding.GetString((byte[])strBytes);

                // 截取有效字符串
                int index = str.IndexOf('\r');
                var subStr = str;
                if (index > 0)
                {
                    subStr = str.Substring(1, index - 1);
                }
                else
                {
                    // 以0作为结束付
                    int length = subStr.Length;
                    for (int i = 0; i < subStr.Length; i++)
                    {
                        if (subStr[i] == 0x00)
                        {
                            length = i;
                            break;
                        }
                    }
                    subStr = str.Substring(1, length - 1);
                }

                //// 读取保持寄存器(每个寄存器2个字节)
                //ushort[] registers = _modbusMaster.ReadHoldingRegisters(_slaveId, startAddress, wordLength);
                //// 将寄存器数组转换为字节数组
                //byte[] byteData = ConvertRegistersToBytesCDAB(registers);
                ////// 将字节数组转换为字符串
                ////var str = GlobalFunction.byteToHexStr(byteData);
                //// 转换为字符串(自动处理终止符)
                //var str = ConvertBytesToString(byteData, encoding);

                return subStr;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取字符串失败: {ex.Message}");
                throw;
            }
        }

        public string ReadStringAutoDetect(ushort startAddress, ushort wordLength = 20)
        {
            throw new NotImplementedException();
        }

        public void WriteInt32(ushort startAddress, int value)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                _plc.Write(DataType.DataBlock, DbNo, startAddress, value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入寄存器失败: {ex.Message}");
                throw;
            }
        }

        public void WriteBytes(ushort startAddress, int value)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                byte[] BT = new byte[1] { 0x01};
                _plc.WriteBytes(DataType.DataBlock,6,0,BT);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入寄存器失败: {ex.Message}");
                throw;
            }
        }


        public void WriteMultipleRegisters(ushort startAddress, ushort[] values)
        {
            throw new NotImplementedException();
        }

        public void WriteSingleCoil(ushort address, bool value)
        {
            throw new NotImplementedException();
        }

        public void WriteSingleRegister(ushort address, ushort value)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                _plc.Write(DataType.DataBlock, DbNo, address, value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入寄存器失败: {ex.Message}");
                throw;
            }
        }
        public void WriteSingleRegister(ushort address, ushort bitAddress, int value)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                _plc.Write(DataType.DataBlock, DbNo, address, value, bitAddress);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入寄存器失败: {ex.Message}");
                throw;
            }
        }

        public void WriteString(ushort startAddress, string text, Encoding encoding = null)
        {
            if (!IsConnected || _plc == null)
                throw new InvalidOperationException("未连接到PLC");

            if (encoding == null)
                encoding = Encoding.ASCII;

            try
            {

                // 写入一个字符串到 VB
                // 注意:S7NetPlus的WriteString方法会自动处理最大长度和实际长度字节
                _plc.Write(DataType.DataBlock, DbNo, startAddress, text);

                //// 将字符串转换为字节数组
                //byte[] byteData = encoding.GetBytes(text);
                //// 确保字节数为偶数(补齐)
                //if (byteData.Length % 2 != 0)
                //{
                //    Array.Resize(ref byteData, byteData.Length + 1);
                //    byteData[byteData.Length - 1] = 0x00; // 用空字符填充
                //}

                //// 将字节数组转换为寄存器数组
                //ushort[] registers = ConvertBytesToRegisters(byteData);

                //// 写入PLC
                //_modbusMaster.WriteMultipleRegisters(_slaveId, startAddress, registers);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入字符串失败: {ex.Message}");
                throw;
            }
        }

        #region 异步读写方法
        public async Task<byte[]> ReadBytesAsync(int dbNumber, int startByte, int length)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }

            try
            {
                var r = _plc.ReadBytes(DataType.DataBlock, dbNumber, startByte, length);
                return r;
            }
            catch
            {
                return null;
            }
        }
        public async Task<ushort> ReadSingleRegistersAsync(ushort startAddress)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                var t = await _plc.ReadAsync(DataType.DataBlock, DbNo, startAddress, VarType.Word, 1);
                return Convert.ToUInt16(t);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取寄存器失败: {ex.Message}");
                throw;
            }
        }

        public async Task WriteSingleRegisterAsync(ushort address, ushort value)
        {
            if (!IsConnected || _plc == null)
            {
                throw new InvalidOperationException("未连接到PLC");
            }
            try
            {
                await _plc.WriteAsync(DataType.DataBlock, DbNo, address, value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入寄存器失败: {ex.Message}");
                throw;
            }
        }

        public async Task<float> ReadFloatAsync(ushort startAddress)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                var t = await _plc.ReadAsync(DataType.DataBlock, DbNo, startAddress, VarType.Real, 1);
                return Convert.ToSingle(t);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public async Task WriteFloatAsync(ushort startAddress, float value)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                await _plc.WriteAsync(DataType.DataBlock, DbNo, startAddress, value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public async Task<int> ReadInt32Async(ushort startAddress)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                var t = await _plc.ReadAsync(DataType.DataBlock, DbNo, startAddress, VarType.DInt, 1);
                return Convert.ToInt32(t);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public async Task WriteInt32Async(ushort startAddress, int value)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                await _plc.WriteAsync(DataType.DataBlock, DbNo, startAddress, value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public async Task<string> ReadStringAsync(ushort startAddress, ushort wordLength = 20, Encoding encoding = null)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                // 读取一个字符串从 VB 
                // 字符串在PLC中通常第一个字节是字符长度,后面是字符数据
                var objValue = await _plc?.ReadAsync(DataType.DataBlock, DbNo, startAddress, VarType.String, wordLength * 2);
                var str = Convert.ToString(objValue);

                //var objValue = _plc?.Read(DataType.DataBlock, 1, startAddress, VarType.Byte, wordLength * 2);
                //// 移除首字节
                //byte[] strBytes = (byte[])objValue;                 
                //var strASCII = encoding.GetString((byte[])strBytes);

                // 截取有效字符串
                int index = str.IndexOf('\r');
                var subStr = str;
                if (index > 0)
                {
                    subStr = str.Substring(1, index - 1);
                }
                else
                {
                    // 以0x00作为结束符
                    int length = subStr.Length;
                    for (int i = 0; i < subStr.Length; i++)
                    {
                        if (subStr[i] == 0x00)
                        {
                            length = i;
                            break;
                        }
                    }
                    subStr = str.Substring(1, length - 1);
                }
                return subStr;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }

        public async Task WriteStringAsync(ushort startAddress, string text, Encoding encoding = null)
        {
            if (!IsConnected || _plc == null) throw new Exception("未连接到 PLC");
            try
            {
                await _plc.WriteAsync(DataType.DataBlock, DbNo, startAddress, text);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据失败: {ex.Message}");
                throw;
            }
        }


        #endregion

    }
}

这是一个基于 S7.Net 库实现的西门子 PLC(S7-1200/1500 等)通信类

核心属性

  • IsConnected:检查 PLC 连接状态

  • DbNo:默认的数据块编号(默认为 6)

  • Rack/Slot:PLC 的机架号和槽号

连接管理

  1. Connect():连接到 PLC,返回连接是否成功

  2. Disconnect():断开与 PLC 的连接

  3. Dispose():实现 IDisposable 接口,清理资源

同步读取方法

  1. ReadFloat():从指定地址读取 32 位浮点数(Real 类型)

  2. ReadInt32():从指定地址读取 32 位整数(DInt 类型)

  3. ReadSingleRegisters():从指定地址读取单个 16 位寄存器(Word 类型)

    • 两个重载版本:一个读取字,一个读取位(bit)
  4. ReadHoldingRegisters():批量读取多个 16 位寄存器

  5. ReadString():从指定地址读取字符串(String 类型),自动处理字符串终止符

  6. ReadDB6Bytes():读取数据块的原始字节数组(方法名固定为 DB6,但参数支持任意 DB 块)

同步写入方法

  1. WriteSingleRegister()
  • 写入单个 16 位寄存器(Word)

  • 重载版本支持写入位(bit)

  1. WriteInt32():写入 32 位整数(DInt)

  2. WriteBytes():写入字节数组(目前代码中硬编码为 DB6,地址 0)

  3. WriteString():写入字符串到 PLC

异步方法(Async 后缀)

  1. ReadSingleRegistersAsync():异步读取单个寄存器

  2. ReadFloatAsync():异步读取浮点数

  3. ReadInt32Async():异步读取 32 位整数

  4. ReadStringAsync():异步读取字符串

  5. WriteSingleRegisterAsync():异步写入单个寄存器

  6. WriteFloatAsync():异步写入浮点数

  7. WriteInt32Async():异步写入 32 位整数

  8. WriteStringAsync():异步写入字符串

未实现方法

  1. ReadCoils():读取线圈(不支持,抛出异常)

  2. WriteSingleCoil():写入单个线圈(不支持)

  3. WriteMultipleRegisters():批量写入寄存器(未实现)

  4. ReadStringAutoDetect():自动检测字符串(未实现)

特点说明

  • 地址映射 :所有方法都通过 DataType.DataBlock 访问数据块

  • 错误处理:每个方法都包含连接状态检查和异常处理

  • 字符串处理:自动处理 PLC 字符串格式(长度字节+字符数据)

  • 字节序处理S7.Net 库自动处理大端序/小端序转换

  • 异步支持:提供了完整的异步读写方法

使用方法

cs 复制代码
var plc = new SimaticS7Net("192.168.1.1", CpuType.S71200);
plc.Connect();

// 读取数据
float temp = plc.ReadFloat(100);  // 读取 DB6.DBD100
string name = plc.ReadString(200, 20);  // 读取 DB6.DBB200 开始的字符串

// 写入数据
plc.WriteSingleRegister(300, 1234);  // 写入 DB6.DBW300 = 1234
plc.WriteString(400, "Hello PLC");  // 写入字符串到 DB6.DBB400

plc.Disconnect();
相关推荐
海底星光5 小时前
c#进阶疗法 -jwt+授权
c#
液态不合群5 小时前
如何提升 C# 应用中的性能
开发语言·算法·c#
布局呆星5 小时前
面向对象中的封装-继承-多态
开发语言·python
柏林以东_5 小时前
异常的分类与用法
java·开发语言
专注API从业者5 小时前
淘宝商品 API 接口架构解析:从请求到详情数据返回的完整链路
java·大数据·开发语言·数据库·架构
木千5 小时前
Qt全屏显示,在顶部工具栏的最右边显示关闭按钮
开发语言·qt
-凌凌漆-5 小时前
【java】java中函数加与不加abstract 的区别
java·开发语言
你撅嘴真丑5 小时前
STL练习
开发语言·c++·算法
Ulyanov5 小时前
Impress.js深度技术解析:架构基础与结构化设计
开发语言·前端·javascript