当前位置:网站首页>C#使用西门子S7 协议读写PLC DB块
C#使用西门子S7 协议读写PLC DB块
2022-07-06 21:42:00 【小丫头呀】
- 教大家使用C#如何方便快速的读写西门子DB块的值,实现上位机跟plc进行通讯的流程
- 使用的西门子PLC型号,S7 1200
1.Nuget 安装s7 驱动包

2.西门子plc定义一个db块,这个是我们上位机要读写的DB

3. 根据西门子S7 协议文档
读取DB块的方式有很多种,直接根据该DB的偏移量进行读写也行,但读或写数据都需要进行对应的数据类型转换才能最终拿到值或写进去,个人觉得太麻烦了。不过文档也提供了一种比较简单的方式,就是读写类的方式。
3.1 读写类的原理,是通过反射处理的,不过我们并不需要关心它是如何反射的,我们只关心我们要如何使用。
3.2 首先,需要建立一个类,跟西门子 DB块 名称一样的实体类
西门子plc建立的DB 块名称

C# 建立对应的db块名称的类属性

4. 类建立完成,我们通过接口的方式实现读写数据
接口定义两种,普通接口和泛型接口。后面会介绍使用泛型接口和普通接口的区别以及好处
4.1 普通接口的实现
根据s7 文档,提供了ReadClass读取的方法。提供读取的方法有很多种,我们只介绍一种方式,就是通过传入建立好的实体类。其他自行研究实现。
public void ReadClass(object sourceClass, int db, int startByteAdr = 0)
- sourceClass 分配值的类实例
- db 数据块
- startByteAdr 读取字体起始地址
4.2 我们知道该方法的传入参数后,接着需要定义接口的方法。

为什么要定义返回一个实体,因为我们读数据时,需要传入一个实体,读取结束后,Plc的Db块的值就会反射在这个实体中,我们通过这个实体取到最新读到的数值。接下来我们实现这个接口方法。

1.上面的实现方式,它是等同于下面的书写方式。
CathodeEntity testClass = new CathodeEntity(); plc.ReadClass(testClass, 5);只不过,我为了防止每一次调用都会重新new 一个CathodeEntity类。我就把这个 CathodeEntity 类设计成单例模式了。永远只实例化一次,我们需要修改的只是这个类的属性值而已。后面的5,意思就我们要读的DB块5
2.单列实例类 CathodeEntity
public class CathodeEntity { public bool CathodeUp { get; set; } public bool EntryAllowed { get; set; } public bool LeaveAllowed { get; set; } // 定义一个静态变量来保存类的实例 private static CathodeEntity uniqueInstance; // 定义一个标识确保线程同步 private static readonly object locker = new object(); // 定义私有构造函数,使外界不能创建该类实例 private CathodeEntity() { } /// <summary> /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 /// </summary> /// <returns></returns> public static CathodeEntity GetInstance() { // 当第一个线程运行到这里时,此时会对locker对象 "加锁", // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁 // lock语句运行完之后(即线程运行完之后)会对该对象"解锁" if (uniqueInstance == null) { lock (locker) { // 如果类的实例不存在则创建,否则直接返回 if (uniqueInstance == null) { uniqueInstance = new CathodeEntity(); } } } return uniqueInstance; } }3.单例设计模式参考
4.3 接下来,调用该接口,就能获取到plc 的值了。

读取到的值跟西门子PLC DB5的值是一样的
5. 以上就是普通接口的实现方式,但如果我们是多个db块,按照常规是不是得写N个实现方法,这样不仅不容易维护,代码量也多。所以我们把接口设计成泛型的实现。
为什么能设计泛型,根据这个s7 协议,读类的方法,第一个参数是object 类型,也可以是具体的实例类型。
5.1 我们要设定接口约束类型。为什么要这样干,就是我们要让实现这个接口的类,规定它这个T类型,你不能传int 或string等,必须传个类给它。这样就防止,接口实现的时候,你传错参数了。
5.2 接着,我们实现这个泛型接口,那么这个t,我们就可以换成,我们跟Plc定义的数据块,建立的对应实体类了。
例如,当前Plc有一个db块5,我们建立对应的实体属性类名是CathodeEntity,我们调用的时候就传CathodeEntity 实体进来。如果plc 有多个db块,我们也要有多个对应的实体类。这个时候我们就可以把不同的实体类传进去,返回来就是plc 具体db块的值了。
实现接口

5.3 调用接口。首先实例化CathodeEntity 实体类,把CathodeEntity传进去,得到的就是对应Db块5的值。如果是其他Db块,就需要建立跟plc db块名称对应的实体类,然后再CathodeEntity 换成要新建读取的类。这样就实现的接口方法复用。

6. 接口调用具体实现。

6.1 Plc 连接类,因为我只需要实例化一次,所以也要把它设计成了单例模式
/// <summary>
/// 正极缓存货架plc
/// </summary>
internal class CathodeBufferRack
{
//定义静态变量保存实例
public static volatile Plc CathodePlc;
//定义一个标识确保线程同步
private static object lockHelper = new object();
//定义私有变量,使外部不能创建该类实例
private CathodeBufferRack()
{
}
public static Plc Instance(string DeviceIp)
{
if(CathodePlc == null)
{
lock (lockHelper)
{
if (CathodePlc == null)
{
CathodePlc = new Plc(CpuType.S71200, DeviceIp, 0,1);
CathodePlc.Open();
if (!CathodePlc.IsConnected)
{
CathodePlc.Close();
CathodePlc = null;
}
}
}
}
return CathodePlc;
}
}7. 写plc db也同样的道理。
7.1 定义写的接口方法

7.2 实现接口方法
7.3 程序调用

7.4 LeaveAllowed 实体更改成true后,传进去。plc驱动程序自动反射,把对应实体plc db块的值直接更新了。这样就不用通过偏移量来操作读写db块了。

如果db块有不同的类型,例如byte ,Int ,DInt ,等,同样的道理,创建对应的数据类型就可以了。
7.5 PLC与C# 常用数据类型转换
| PLC | C# |
| Bool | Bool |
| Word | ushort |
| Int | ushort |
| Dword | uint32 |
| Dint | uint |
| byte | byte |
| Real | bouble |
具体使用参考官网
8. 普通接口和泛型接口对比。
8.1 如下例子所示,普通接口固定死传入实体参数后,它就只能规定你传入CathodeEntity实体类对象。
普通接口方法方法:
但如果,我们要读同一个plc,不同的db块,是不是这个方法就不适用了。那我们得要再重新定义一个接口方法,只是类参数不一样。
但plc.WriteClass()这个方法是适用写不同的db块的,它是由传入的参数决定它要写那个db块。所以这样子重复的做接口实现,增加代码量而且还不容易维护。
所以,我们要学会分析构思代码。
1.首先,得分析这个plc.WriteClass()能接受的参数类型是什么。它的第一个参数是object 类型,就是任意类数据类型。(当然了,这个的任意类型是有限制的,因为它是plc 驱动程序提供的写类的方法,它的任意数据类型就只能限制于类),就是说可以传不同的类给它
2.那我们清楚它接受数据类型后,接着是不是要考滤接口的设计实现。因为它规定了,只能传入任意的类 类型,那也就是,它不能接受int或string 类型了。所以我们定义泛型接口要约束这个泛型接口类型。泛型接口的实现,只能传进来类对象,不能是其他。
3.所以泛型接口实现,传入一个obj
4.然后接口调用的时候,传什么,对应的泛型就是什么
总结:这样减少了代码量,容易维护。
那就先这样吧,理解了点赞收藏啊,防止那天找不到了。
边栏推荐
- HW notes (II)
- 2022年电工杯B 题 5G 网络环境下应急物资配送问题思路分析
- cuda编程
- 接口自动化测试实践指导(中):接口测试场景有哪些
- Unity3D在一建筑GL材料可以改变颜色和显示样本
- Operational amplifier application summary 1
- 2022 middle school Youth Cup mathematical modeling question B fertility policy research ideas under the background of open three children
- Opencv third party Library
- buildroot的根文件系统提示“depmod:applt not found”
- SSM+JSP实现企业管理系统(OA管理系统源码+数据库+文档+PPT)
猜你喜欢

The most complete learning rate adjustment strategy in history LR_ scheduler

1.19.11.SQL客户端、启动SQL客户端、执行SQL查询、环境配置文件、重启策略、自定义函数(User-defined Functions)、构造函数参数

SSM+JSP实现企业管理系统(OA管理系统源码+数据库+文档+PPT)

cuda编程

Mongo shell, the most complete mongodb in history

Imitate Tengu eating the moon with Avatar

tflite模型转换和量化

【自动化经验谈】自动化测试成长之路

【刷题记录】2. 两数相加

Kotlin Android 环境搭建
随机推荐
三重半圆环进度条,直接拿去就能用
idea gradle lombok 报错集锦
[coded font series] opendyslexic font
ABAP Dynamic Inner table Group cycle
Use dumping to back up tidb cluster data to GCS
【刷题记录】2. 两数相加
二叉搜索树的实现
機器人(自動化)課程的持續學習-2022-
Different meat customers joined hands with Dexter to launch different hamburgers in some stores across the country
SSM+JSP实现企业管理系统(OA管理系统源码+数据库+文档+PPT)
【ArcGIS教程】专题图制作-人口密度分布图——人口密度分析
map和set的实现
2022中青杯C题城市交通思路分析
NoSQL之Redis配置与优化
Five years of automated testing, and finally into the ByteDance, the annual salary of 30W is not out of reach
List interview common questions
Do you choose pandas or SQL for the top 1 of data analysis in your mind?
Collection of idea gradle Lombok errors
运算放大器应用汇总1
Redis源码学习(31),字典学习,dict.c(一)

但如果,我们要读同一个plc,不同的db块,是不是这个方法就不适用了。那我们得要再重新定义一个接口方法,只是类参数不一样。



总结:这样减少了代码量,容易维护。