C#通过HSLCommunication库操作PLC用法

C# 基于 HSLCommunication 操作 PLC 完整用法指南

你需要掌握 C# 通过 HSLCommunication 库操作 PLC 的完整流程和实用用法,下面将从环境搭建、核心操作、资源管理到完整示例进行详细讲解,以主流西门子 S7-1200/1500 PLC 为例,其他品牌(三菱、欧姆龙等)用法可类比替换。

一、环境准备(前提步骤)

1. 安装 HSLCommunication 库

HSLCommunication 以 NuGet 包形式分发,两种安装方式任选:

  • 图形界面安装 :Visual Studio 中右键项目 → 管理 NuGet 程序包 → 浏览 → 搜索HslCommunication → 安装最新稳定版
  • 命令行安装:打开程序包管理器控制台,执行以下命令
cs 复制代码
Install-Package HslCommunication

2. 引入核心命名空间

在 C# 代码文件头部引入必要命名空间,针对西门子 PLC 的核心命名空间如下:

cs 复制代码
using System;
using System.Collections.Generic;
using HslCommunication;          // 核心公共命名空间
using HslCommunication.Profinet;  // 工业总线公共命名空间
using HslCommunication.Profinet.Siemens;  // 西门子PLC专属命名空间
// 三菱PLC替换为:using HslCommunication.Profinet.Mitsubishi;
// 欧姆龙PLC替换为:using HslCommunication.Profinet.Omron;

二、核心操作流程

HSLCommunication 操作 PLC 的统一核心流程:创建 PLC 实例 → 建立连接 → 读写操作 → 释放资源

1. 创建 PLC 通信实例

针对不同品牌 PLC,HSLCommunication 提供了专属实例类,以西门子 S7-1200/1500 为例,创建 TCP/IP 通信实例:

cs 复制代码
// 构造函数参数说明:
// 1. PLC型号(S71200/S71500/S7300/S7400)
// 2. PLC的局域网IP地址(需与电脑在同一网段)
// 3. 机架号(默认0,无需修改)
// 4. 槽号(S71200/1500默认1;S7300默认2)
SiemensS7Net plcClient = new SiemensS7Net(SiemensPLCS.S71200, "192.168.1.100", 0, 1);

// 可选配置:设置连接超时和读写超时(单位:毫秒,默认3000)
plcClient.ConnectTimeOut = 5000;  // 连接超时时间
plcClient.ReceiveTimeOut = 5000;  // 读写超时时间

其他品牌 PLC 实例创建示例:

  • 三菱 FX 系列(以太网):MitsubishiFxNet plcClient = new MitsubishiFxNet("192.168.1.101");
  • 欧姆龙 CJ 系列(FINS 协议):OmronFinsNet plcClient = new OmronFinsNet("192.168.1.102");

2. 建立 PLC 连接

使用ConnectServer()方法建立连接,该方法返回OperateResult对象(HSL 核心返回类型,用于判断操作是否成功):

cs 复制代码
// 建立与PLC的连接
OperateResult connectResult = plcClient.ConnectServer();

// 判断连接是否成功
if (connectResult.IsSuccess)
{
    Console.WriteLine("PLC连接成功!");
    // 连接成功后,执行读写操作
}
else
{
    // 连接失败,输出错误信息
    Console.WriteLine($"PLC连接失败!错误原因:{connectResult.Message}");
    // 连接失败时,建议释放资源
    plcClient.Dispose();
    return;
}

3. 核心读写操作(最常用)

HSLCommunication 提供了丰富的读写方法,核心分为单个地址读写批量地址读写,支持 bool、int16、int32、float 等常用数据类型。

(1)单个地址读写
① 布尔类型(位操作:M0.0、I0.1、Q0.2、DB1.DBX0.0)

布尔类型是 PLC 的位状态,对应输入、输出、中间继电器等,核心方法:

  • 读取:ReadBool(string address)

  • 写入:Write(string address, bool value)

    cs 复制代码
    try
    {
        // 读取M0.0的状态
        OperateResult<bool> readBoolResult = plcClient.ReadBool("M0.0");
        if (readBoolResult.IsSuccess)
        {
            bool m00Value = readBoolResult.Content; // 获取读取结果
            Console.WriteLine($"M0.0 当前值:{m00Value}");
        }
        else
        {
            Console.WriteLine($"读取M0.0失败:{readBoolResult.Message}");
        }
    
        // 写入M0.0为true(置1)
        OperateResult writeBoolResult = plcClient.Write("M0.0", true);
        if (writeBoolResult.IsSuccess)
        {
            Console.WriteLine("M0.0 写入true成功!");
        }
        else
        {
            Console.WriteLine($"M0.0 写入失败:{writeBoolResult.Message}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"布尔类型读写异常:{ex.Message}");
    }
    ② 数值类型(int32、float、int16 等)

    以工业场景最常用的int32(双字,对应 PLC DInt 类型)和float(实数,对应 PLC Real 类型)为例:

  • 读取:ReadInt32(string address)ReadFloat(string address)

  • 写入:Write(string address, int value)Write(string address, float value)

    cs 复制代码
    try
    {
        // 1. 读写int32类型(对应PLC DB1.DBD0,数据块双字地址)
        // 读取DB1.DBD0的值
        OperateResult<int> readInt32Result = plcClient.ReadInt32("DB1.DBD0");
        if (readInt32Result.IsSuccess)
        {
            int db1Dbd0Value = readInt32Result.Content;
            Console.WriteLine($"DB1.DBD0(int32):{db1Dbd0Value}");
        }
        else
        {
            Console.WriteLine($"读取DB1.DBD0失败:{readInt32Result.Message}");
        }
    
        // 写入DB1.DBD0为2025
        OperateResult writeInt32Result = plcClient.Write("DB1.DBD0", 2025);
        if (writeInt32Result.IsSuccess)
        {
            Console.WriteLine("DB1.DBD0 写入2025成功!");
        }
        else
        {
            Console.WriteLine($"DB1.DBD0 写入失败:{writeInt32Result.Message}");
        }
    
        // 2. 读写float类型(对应PLC DB1.DBD4,数据块实数地址)
        // 读取DB1.DBD4的值
        OperateResult<float> readFloatResult = plcClient.ReadFloat("DB1.DBD4");
        if (readFloatResult.IsSuccess)
        {
            float db1Dbd4Value = readFloatResult.Content;
            Console.WriteLine($"DB1.DBD4(float):{db1Dbd4Value:F2}"); // 保留2位小数输出
        }
        else
        {
            Console.WriteLine($"读取DB1.DBD4失败:{readFloatResult.Message}");
        }
    
        // 写入DB1.DBD4为6.66f
        OperateResult writeFloatResult = plcClient.Write("DB1.DBD4", 6.66f);
        if (writeFloatResult.IsSuccess)
        {
            Console.WriteLine("DB1.DBD4 写入6.66成功!");
        }
        else
        {
            Console.WriteLine($"DB1.DBD4 写入失败:{writeFloatResult.Message}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"数值类型读写异常:{ex.Message}");
    }
    (2)批量读写操作(高效推荐)

    当需要读写多个 PLC 地址时,批量操作可减少网络通信次数,提升效率,核心用法如下:

  • 批量读取:传入地址数组,返回结果数组

  • 批量写入:传入键值对字典(地址为键,值为待写入数据)

    cs 复制代码
    try
    {
        // 1. 批量读取布尔类型(M0.0、M0.1、I0.0)
        string[] boolAddresses = new string[] { "M0.0", "M0.1", "I0.0" };
        OperateResult<bool[]> readBoolBatchResult = plcClient.ReadBool(boolAddresses);
        if (readBoolBatchResult.IsSuccess)
        {
            bool[] boolValues = readBoolBatchResult.Content;
            for (int i = 0; i < boolAddresses.Length; i++)
            {
                Console.WriteLine($"{boolAddresses[i]}:{boolValues[i]}");
            }
        }
        else
        {
            Console.WriteLine($"批量读取布尔类型失败:{readBoolBatchResult.Message}");
        }
    
        // 2. 批量写入(混合布尔、int32、float类型)
        Dictionary<string, object> writeDict = new Dictionary<string, object>()
        {
            { "M0.1", false },        // 布尔类型
            { "DB1.DBD8", 1000 },     // int32类型
            { "DB1.DBD12", 9.99f }    // float类型
        };
        OperateResult writeBatchResult = plcClient.Write(writeDict);
        if (writeBatchResult.IsSuccess)
        {
            Console.WriteLine("所有地址批量写入成功!");
        }
        else
        {
            Console.WriteLine($"批量写入失败:{writeBatchResult.Message}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"批量读写异常:{ex.Message}");
    }

    4. 资源释放(关键步骤)

    通信完成后,需关闭连接并释放资源,避免内存泄漏,推荐两种方式:

    方式 1:使用 using 语句(推荐,自动释放)

    using 语句会自动调用对象的Dispose()方法,无需手动释放资源:

    cs 复制代码
    // using包裹PLC实例,代码块执行完毕后自动释放资源
    using (SiemensS7Net plcClient = new SiemensS7Net(SiemensPLCS.S71200, "192.168.1.100", 0, 1))
    {
        // 建立连接、执行读写操作...
        OperateResult connectResult = plcClient.ConnectServer();
        if (connectResult.IsSuccess)
        {
            // 读写逻辑
        }
    } // 此处自动释放plcClient资源,无需手动调用Dispose()
    方式 2:手动释放资源

    若不使用using语句,需在操作完成后手动关闭连接并释放:

    cs 复制代码
    SiemensS7Net plcClient = new SiemensS7Net(SiemensPLCS.S71200, "192.168.1.100", 0, 1);
    try
    {
        // 建立连接、读写操作...
    }
    finally
    {
        // 关闭连接
        plcClient.DisconnectServer();
        // 释放资源
        plcClient.Dispose();
        Console.WriteLine("PLC连接已关闭,资源已释放!");
    }

    三、关键注意事项

  • 地址格式规范 :需使用 PLC 标准地址格式,避免读写失败

    • 西门子:M0.0(中间继电器)、I0.1(输入)、Q0.2(输出)、DB1.DBD0(数据块双字)、DB1.DBX0.0(数据块位)
    • 三菱:X0(输入)、Y0(输出)、M0(中间继电器)、D0(数据寄存器)
  • OperateResult 对象 :HSL 所有操作均返回该对象(或泛型OperateResult<T>

    • IsSuccess:判断操作是否成功(bool 类型)
    • Message:操作失败时,获取详细错误信息(字符串类型)
    • Content:泛型版本专属,获取操作成功后的结果数据(T 类型)
  • 数据类型匹配 :必须保证 C# 数据类型与 PLC 数据类型一致

    • PLC DInt(双字)→ C# int(int32)
    • PLC Real(实数)→ C# float(单精度浮点)
    • PLC Int(字)→ C# short(int16)
    • PLC Bit(位)→ C# bool
  • 异常处理 :所有读写操作建议包裹在try-catch块中,捕获网络中断、地址不存在等异常。

四、完整可运行示例代码

cs 复制代码
using System;
using System.Collections.Generic;
using HslCommunication;
using HslCommunication.Profinet.Siemens;

namespace HslPlcOperationDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 使用using语句自动释放PLC资源
            using (SiemensS7Net plcClient = new SiemensS7Net(SiemensPLCS.S71200, "192.168.1.100", 0, 1))
            {
                try
                {
                    // 1. 建立PLC连接
                    OperateResult connectResult = plcClient.ConnectServer();
                    if (!connectResult.IsSuccess)
                    {
                        Console.WriteLine($"PLC连接失败:{connectResult.Message}");
                        Console.ReadKey();
                        return;
                    }
                    Console.WriteLine("PLC连接成功!\n");

                    // 2. 单个读写布尔类型(M0.0)
                    SingleReadWriteBool(plcClient);

                    // 3. 单个读写数值类型(int32 + float)
                    SingleReadWriteNumber(plcClient);

                    // 4. 批量读写操作
                    BatchReadWrite(plcClient);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"程序异常:{ex.Message}");
                }
                finally
                {
                    // 手动关闭连接(可选,using会自动释放)
                    plcClient.DisconnectServer();
                    Console.WriteLine("\nPLC连接已关闭!");
                }
            }

            Console.ReadKey();
        }

        /// <summary>
        /// 单个读写布尔类型
        /// </summary>
        private static void SingleReadWriteBool(SiemensS7Net plcClient)
        {
            // 读取M0.0
            OperateResult<bool> readResult = plcClient.ReadBool("M0.0");
            if (readResult.IsSuccess)
            {
                Console.WriteLine($"M0.0 读取值:{readResult.Content}");
            }
            else
            {
                Console.WriteLine($"M0.0 读取失败:{readResult.Message}");
            }

            // 写入M0.0为true
            OperateResult writeResult = plcClient.Write("M0.0", true);
            if (writeResult.IsSuccess)
            {
                Console.WriteLine("M0.0 写入true成功!\n");
            }
            else
            {
                Console.WriteLine($"M0.0 写入失败:{writeResult.Message}\n");
            }
        }

        /// <summary>
        /// 单个读写数值类型(int32 + float)
        /// </summary>
        private static void SingleReadWriteNumber(SiemensS7Net plcClient)
        {
            // 读写int32(DB1.DBD0)
            OperateResult<int> readIntResult = plcClient.ReadInt32("DB1.DBD0");
            if (readIntResult.IsSuccess)
            {
                Console.WriteLine($"DB1.DBD0(int32)读取值:{readIntResult.Content}");
            }
            else
            {
                Console.WriteLine($"DB1.DBD0 读取失败:{readIntResult.Message}");
            }

            OperateResult writeIntResult = plcClient.Write("DB1.DBD0", 2025);
            if (writeIntResult.IsSuccess)
            {
                Console.WriteLine("DB1.DBD0 写入2025成功!");
            }
            else
            {
                Console.WriteLine($"DB1.DBD0 写入失败:{writeIntResult.Message}");
            }

            // 读写float(DB1.DBD4)
            OperateResult<float> readFloatResult = plcClient.ReadFloat("DB1.DBD4");
            if (readFloatResult.IsSuccess)
            {
                Console.WriteLine($"DB1.DBD4(float)读取值:{readFloatResult.Content:F2}");
            }
            else
            {
                Console.WriteLine($"DB1.DBD4 读取失败:{readFloatResult.Message}");
            }

            OperateResult writeFloatResult = plcClient.Write("DB1.DBD4", 6.66f);
            if (writeFloatResult.IsSuccess)
            {
                Console.WriteLine("DB1.DBD4 写入6.66成功!\n");
            }
            else
            {
                Console.WriteLine($"DB1.DBD4 写入失败:{writeFloatResult.Message}\n");
            }
        }

        /// <summary>
        /// 批量读写操作
        /// </summary>
        private static void BatchReadWrite(SiemensS7Net plcClient)
        {
            // 批量读取布尔类型
            string[] boolAddrs = new string[] { "M0.0", "M0.1", "I0.0" };
            OperateResult<bool[]> batchReadResult = plcClient.ReadBool(boolAddrs);
            if (batchReadResult.IsSuccess)
            {
                Console.WriteLine("批量读取布尔类型结果:");
                for (int i = 0; i < boolAddrs.Length; i++)
                {
                    Console.WriteLine($"{boolAddrs[i]}:{batchReadResult.Content[i]}");
                }
            }
            else
            {
                Console.WriteLine($"批量读取布尔类型失败:{batchReadResult.Message}");
            }

            // 批量写入混合类型
            Dictionary<string, object> writeDict = new Dictionary<string, object>()
            {
                { "M0.1", false },
                { "DB1.DBD8", 1000 },
                { "DB1.DBD12", 9.99f }
            };
            OperateResult batchWriteResult = plcClient.Write(writeDict);
            if (batchWriteResult.IsSuccess)
            {
                Console.WriteLine("批量写入所有地址成功!");
            }
            else
            {
                Console.WriteLine($"批量写入失败:{batchWriteResult.Message}");
            }
        }
    }
}
相关推荐
JIngJaneIL2 小时前
基于springboot + vue房屋租赁管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
期待のcode3 小时前
Java的抽象类和接口
java·开发语言
wadesir3 小时前
Go语言中高效读取数据(详解io包的ReadAll函数用法)
开发语言·后端·golang
小高不明4 小时前
前缀和一维/二维-复习篇
开发语言·算法
龘龍龙4 小时前
Python基础(八)
开发语言·python
幺零九零零5 小时前
Golang-Swagger
开发语言·后端·golang
叫我A先生5 小时前
【OpenGL小作坊】C# + OpenTK + OpenGL实现.tif点云转换成.obj模型
c#·opengl
code bean5 小时前
【Halcon】Halcon模板匹配技术深度解析:形状匹配 vs 局部可形变匹配
c#·halcon
陌路物是人非5 小时前
记一个 @Resource BUG
java·开发语言·bug