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;
    }));
相关推荐
先鱼鲨生26 分钟前
【Qt】初识Qt
开发语言·qt
wangnaisheng1 小时前
【C#】一个类中的接口方法使用static和不使用static的区别
c#
chao_7891 小时前
QT开发工具对比:Qt Creator、Qt Designer、Qt Design Studio
开发语言·qt
程序猿多布1 小时前
C# 定时器实现
c#
大飞pkz2 小时前
【Unity】使用XLua进行热修复
unity·c#·游戏引擎·lua·游戏开发·xlua·lua热修复
珊瑚里的鱼3 小时前
LeetCode 102题解 | 二叉树的层序遍历
开发语言·c++·笔记·算法·leetcode·职场和发展·stl
码上飞扬3 小时前
Java大师成长计划之第12天:性能调优与GC原理
java·开发语言
Wabi_sabi_x3 小时前
C++设计模式:面向对象的八大设计原则之一
开发语言·c++·设计模式
万叶学编程4 小时前
鸿蒙移动应用开发--ArkTS语法进阶实验
开发语言·javascript·ecmascript
chilling heart4 小时前
JAVA---继承
java·开发语言·学习