C#与西门子PLC通信:S7NetPlus和HslCommunication使用指南

西门子S7协议是用来和PLC进行通讯的一个协议,默认端口是102,数据会保存在一个个DB块中,比较经典的用法是一个DB块专门用来读取,一个用来写入。

DB(数据块)+ {块号}.DBX/DBD/DBW+{字节地址}.{位偏移}

1、数据块是存放全局变量的内存区域,类似数据库的表.

2、三种类型的字节地址是共用的,所以要特别注意不同数据类型占用的长度是不同的,否则会出现异常数据的情形。

提到字节排列就得提到不同的通信设备的排列方式是有区别的,像是C#,三菱PLC就是小端排列类似于ABCD,4个字母表示4个字节;西门子PLC是大端排列,顺序是DCBA,modbus等协议是不规则排列,顺序有BADC,CDAB。

DBX(data block bit) 按位访问,用于访问数据块中的单个位即Bool类型,例如: DB1.DBX0.1 表示数据块1的第0字节的第0位。

每个字节有8位,所以偏移量的范围是0~7.

DBW(Data Block Word)数据块字,用于访问16位的数据,例如:Word,int类型。由于1个字 = 16位也就是2个字节,所以地址必须是偶数,无需使用位偏移。

例如:DB1.DBW0表示数据块1的第0个字节开始的16位数据

DBD(data block double word)数据块双字,用于访问32位的数据,例如:DWord,Dint,Real类型。由于1个双字 = 32位也就是4个字节,所以地址必须是4的整数,无需使用位偏移。

例如:DB1.DBD0表示数据块1的第0个字节开始的32位数据

使用C#实现西门子S7通讯可以通过S7NetPlus,HslCommunication类库来实现

1、使用S7NetPlus实现读写数据

复制代码
    // 第一个参数是CPU的型号
    // 第三个参数是PLC的机架(Rank)
    // 第四个参数是CPU的插槽(Slot)
    using (var plc = new Plc(CpuType.S71200, "127.0.0.1", 0, 1))
    {
        try
        {
            plc.Open();
            if (plc.IsConnected == false)
            {
                this.textBox1.Text = this.textBox1 + "连接失败" + Environment.NewLine;
            }
    
            #region 写入数据
    
            // 写入一个bool类型
            plc.Write("DB1.DBX0.0", true);
    
            // 写入一个无符号整数
            ushort ushortValue = 3600;
            plc.Write("DB1.DBW2.0", ushortValue);
    
            // 写入一个浮点数
            float floatValue = 3.14f;
            plc.Write("DB1.DBD4", floatValue);
    
            // 写入一个有符号整数
            int intValue = 2025;
            plc.Write("DB1.DBD8", intValue);
    
            #endregion
    
            #region 读取数据
    
            // 读取一个bool类型
            var is_am = (bool)plc.Read("DB1.DBX0.0");
            this.textBox1.Text = this.textBox1.Text + "is_am=" + is_am + Environment.NewLine;
    
            // 读取一个无符号的整数类型 - word 对应c#的就是ushort类型
            var second = (ushort)plc.Read("DB1.DBW2.0");
            this.textBox1.Text = this.textBox1.Text + "second=" + second + Environment.NewLine;
    
            // 读取一个浮点数
            var pie = ((uint)plc.Read("DB1.DBD4")).ConvertToFloat();
            this.textBox1.Text = this.textBox1.Text + "pie=" + pie + Environment.NewLine;
    
            // 读取一个有符号的整数
            var year = ((uint)plc.Read("DB1.DBD8")).ConvertToInt();
            this.textBox1.Text = this.textBox1.Text + "year=" + year + Environment.NewLine;
    
            #endregion
        }
        catch (Exception ex)
        {
            this.textBox1.Text = this.textBox1 + ex.Message + Environment.NewLine;
        }
    }

2、使用HslCommunication实现读写功能

写入:

复制代码
        plc = new SiemensS7Net(SiemensPLCS.S1200, "127.0.0.1");
        Random random = new Random();
        var flag = await plc.WriteAsync("DB1.DBX0", random.Next(0, 2) == 0 ? false : true);
        var int_value = await plc.WriteAsync("DB1.DBW2", (short)random.Next(0, 1000));
        var float_value = await plc.WriteAsync("DB1.DBD4", (float)random.Next(0, 10) / 10.0f);

        // 中文不能使用默认的Ascii编码,需要使用UTF8编码
        var arr = new string[3] { "中", "美", "日" };
        var string_value = await plc.WriteAsync("DB1.DBD8", arr[random.Next(0, 3)], Encoding.UTF8);
        await Task.Delay(1000, cts.Token);
        if (int_value.IsSuccess == false)
        {
            this.Invoke(new Action(() => {
                this.textBox1.Text = "通讯失败" + Environment.NewLine + this.textBox1.Text;
            }));
            continue;
        }

读取:

复制代码
    plc = new SiemensS7Net(SiemensPLCS.S1200, "127.0.0.1");
    var flag = await plc.ReadBoolAsync("DB1.DBX0");
    var int_value = await plc.ReadInt16Async("DB1.DBW2");
    var float_value = await plc.ReadFloatAsync("DB1.DBD4");

    // 读取中文不能使用默认的Ascii编码,需要使用UTF8编码
    var string_value = await plc.ReadStringAsync("DB1.DBD8", Encoding.UTF8);
    await Task.Delay(1000, cts.Token);
    if (int_value.IsSuccess == false)
    {
        this.Invoke(new Action(() => {
            this.textBox1.Text = "通讯失败" + Environment.NewLine + this.textBox1.Text;
        }));
        
        continue;
    }

    this.Invoke(new Action(() =>
    {
        this.textBox1.Text = "flag:" + flag.Content.ToString() + Environment.NewLine + this.textBox1.Text;
        this.textBox1.Text = "float_value:" + float_value.Content.ToString() + Environment.NewLine + this.textBox1.Text;
        this.textBox1.Text = "int_value:" + int_value.Content.ToString() + Environment.NewLine + this.textBox1.Text;
        this.textBox1.Text = "string_value:" + string_value.Content.ToString() + Environment.NewLine + this.textBox1.Text;
    }));
相关推荐
泡海椒2 分钟前
JQuick-Excel 项目定位与适用场景:声明式 Java Excel 的边界
java·开发语言·excel
slandarer18 分钟前
MATLAB | R2026b 更新了哪些有趣的新东西
开发语言·数据库·matlab
工具派28 分钟前
Word文档太大怎么拆分?段落结构与两种拆法的边界实测
开发语言·c#·word
wjcroom44 分钟前
实现老型号HP打印机手机无线打印的一些步骤和方法
开发语言·智能手机·php
潜龙95271 小时前
需求文档一键变测试用例:手工用例智能生成平台
开发语言·c#
Lost of 程序猿1 小时前
命令模式实战:把“下单后的动作“打包成可执行的任务
后端·设计模式·c#·asp.net·命令模式
sunburn-1 小时前
Java 排序算法详细教学:从冒泡排序到快速排序
java·开发语言·数据结构·ide·算法
鹤卿1231 小时前
「iOS」GCD
开发语言·ios·objective-c
我是小白呀1 小时前
编排还是事件协作?用 AcmeFlow 讲清企业 Workflow 的控制权
java·开发语言
ACP广源盛139246256731 小时前
接口适配方案选型|GSV6125@ACP HDMI2.0 转 Type‑C/DP1.4 桥接芯片工程评估
大数据·c语言·开发语言·硬件架构·硬件工程·国产芯片