首页 > 其他分享 >S7协议(通用写法)

S7协议(通用写法)

时间:2023-11-26 18:23:32浏览次数:31  
标签:通用 S7 DB PLC type var using 写法 public

  S7 通信协议是西门子公司推出的一种工业通信协议,用于在工业自动化领域中实现设备之间的通信。它是一种基于以太网的协议,支持多种通信方式,如 TCP/IP、UDP/IP、ISO-on-TCP 等。

主要用于西门子 S7 系列 PLC(可编程逻辑控制器)之间的通信,也可以用于与其他设备之间的通信,如人机界面(HMI)、变频器、传感器等。通过 S7 通信协议,可以实现数据的读取、写入、传输和处理等功能,从而实现设备之间的互联互通。具有高效、可靠、安全等特点,广泛应用于工业自动化领域。同时,西门子公司还提供了丰富的工具和软件,方便用户进行 S7 通信协议的开发和应用。      使用西门子提供的工具和软件进行 S7 通信协议的开发和应用,一般需要以下步骤:
  1. 安装西门子提供的工具和软件:首先需要安装西门子提供的相关工具和软件,如 TIA Portal(博途)、STEP 7 等。这些工具和软件可以帮助用户进行 S7 通信协议的配置、编程和调试。
  2. 配置通信模块:在进行 S7 通信协议的开发和应用之前,需要先配置通信模块,如以太网模块、PROFIBUS 模块等。在配置通信模块时,需要设置模块的参数,如 IP 地址、子网掩码、网关等。
  3. 编写通信程序:在配置好通信模块后,可以使用西门子提供的编程语言,如 LAD(梯形图)、FBD(功能块图)、STL(语句表)等,编写通信程序。在编写通信程序时,需要使用 S7 通信协议提供的指令和功能块,如 READ、WRITE、TRANSMIT、RECEIVE 等。
  4. 调试通信程序:在编写好通信程序后,可以使用西门子提供的调试工具,如 PLCSIM(仿真软件)等,对通信程序进行调试。在调试过程中,可以查看通信数据的传输情况,以及检查程序是否存在错误。
  5. 应用通信程序:在调试通过后,可以将通信程序下载到实际的设备中,进行实际的通信应用。在应用通信程序时,需要注意设备之间的连接方式、数据格式等,以确保通信的稳定性和可靠性。
  开发语言使用C#,开发工具为VS2022,只涉及到后端代码,不包含前端页面。       1、安装nuget包(s7netplus),支持S7200、Logo0BA8、S7200Smart、S7300、S7400、S71200、S71500        2、 S7通信类(S7支持多种读写方式,例如Bytes、Class、Struct等),下面是优化过的部分读写方式 查看代码
using S7.Net;
using S7.Net.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using static S7Communication.S7Enums;
using DateTime = System.DateTime;

namespace S7Communication
{
    public class S7CommunicationHelp
    {
        //限制长度
        private const int LimitReadDataItemsCount = 18;

        public static S7CommunicationHelp Instance;

        private S7CommunicationHelp()
        {
            Instance = new S7CommunicationHelp();
        }

        /// <summary>
        /// 定义一个plc
        /// </summary>
        private Plc _plc;

        /// <summary>
        ///连接
        /// </summary>
        public bool IsConnected = false;

        /// <summary>
        /// 连接PLC
        /// </summary>
        /// <param name="type">PLC CPU类型</param>
        /// <param name="IP">PLC服务器IP</param>
        /// <param name="Rack">机台号</param>
        /// <param name="Slot">插槽号</param>
        /// <returns></returns>
        public BaseResult PLCConnect(PLC_CPUType type, string IP, short Rack, short Slot)
        {
            var cpuType = (CpuType)Enum.Parse(typeof(CpuType), type.ToString());
            //实例化
            _plc = new Plc(cpuType, IP, Rack, Slot);
            IsConnected = false;
            try
            {
                _plc.Open();
                IsConnected = _plc.IsConnected;
                LogHelp.AddLog<InfoLogEntity>(IsConnected ?
                                  $"TCP服务器 IP:{IP} 机台号{Rack} 插槽号{Slot} 连接成功! " :
                                  $"TCP服务器 IP:{IP} 机台号{Rack} 插槽号{Slot} 连接失败! ");
            }
            catch (Exception ex)
            {
                LogHelp.AddLog<InfoLogEntity>($"PLC连接失败:{ex.Message} ");
            }

            return IsConnected;
        }

        /// <summary>
        /// 断开PLC
        /// </summary>
        public void PLCDisConnect()
        {
            if (_plc != null)
            {
                _plc.Close();
                LogHelp.AddLog<InfoLogEntity>($"PLC服务器断开连接! ");
            }
        }

        /// <summary>
        /// 按照DataItem方式读取PLC数据
        /// </summary>
        /// <param name="dataItem"></param>
        /// <param name="type">Plc类型</param>
        public void PLC_Read(DataItem dataItem)
        {
            var type = S7DBAttribute.GetPlcType(dataItem.DB);
            var lis = new List<DataItem> { dataItem };
            _plc.ReadMultipleVars(lis);
        }

        /// <summary>
        /// 根据Lambda表达式读取Plc
        /// </summary>
        public F PLC_Read<T, F>(Expression<Func<T, F>> expression) where T : BaseDB where F: struct   
        {
            var dataItem = S7DataItemHelp.GetReadDataItem(expression);
            var lis = new List<DataItem> { dataItem };
            var plcType = S7DBAttribute.GetPlcType(dataItem.DB);
            _plc.ReadMultipleVars(lis);

            var f = (F)lis[0].Value;
            return f;
        }


        /// <summary>
        /// 开始读取
        /// </summary>
        /// <param name="dictDataItems">内容</param>
        /// <param name="sleepTimes"></param>
        public void StartRead(Dictionary<string, DataItem> dictDataItems, int sleepTimes = 300)
        {
            var type = S7DBAttribute.GetPlcType(dictDataItems.First().Value.DB);
            //备份的上次记录
            var dictDataItemsBackup = DeepCopy.DeepCopyByJson(dictDataItems);
            var lisDataItems = dictDataItems.Values.ToList();
            Task.Factory.StartNew(() =>
            {
                bool t = false;
                while (true)
                {
                    if (t)
                    {
                        Thread.Sleep(sleepTimes);
                        continue;
                    }

                    var start1 = DateTime.Now;
                    //单次同时读Plc有限制,超过限制得分多次读
                    if (lisDataItems.Count > LimitReadDataItemsCount)
                    {
                        var tempList = new List<DataItem>();
                        int count = lisDataItems.Count / LimitReadDataItemsCount;
                        for (var j = 0; j <= count; j++)
                        {
                            var items = lisDataItems.Skip(j * LimitReadDataItemsCount).Take(LimitReadDataItemsCount)
                                .ToList();
                            if (items.Count <= 0)
                                continue;
                            _plc.ReadMultipleVars(items);
                            tempList.AddRange(items);
                        }

                        lisDataItems = tempList;
                    }
                    else
                    {
                        _plc.ReadMultipleVars(lisDataItems);
                    }

                    var start2 = DateTime.Now;
                    var dictDataItemsTemp =
                        new Dictionary<string, DataItem>(lisDataItems.Count);
                    int i = 0;
                    foreach (var keyValuePair in dictDataItemsBackup)
                    {
                        try
                        {
                            DataItem currentDataItem = lisDataItems[i];
                            dictDataItemsTemp.Add(keyValuePair.Key, currentDataItem);
                            //不变更的属性不发布
                            if (Equals(keyValuePair.Value.Value, currentDataItem.Value))
                            {
                                continue;
                            }
                        }
                        catch (Exception e)
                        {
                            //to do 
                        }
                        finally
                        {
                            i++;
                        }
                    }

                    //保留备份数据
                    dictDataItemsBackup.Clear();
                    dictDataItemsBackup = DeepCopy.DeepCopyByJson(dictDataItemsTemp);

                    var ts1 = start2 - start1;
                    var ts2 = DateTime.Now - start2;
                    Thread.Sleep(20);

                }
            });
        }


        /// <summary>
        /// 通过初始偏移量试出DB块长度
        /// </summary>
        /// <param name="db">数据块地址</param>
        /// <param name="startByteAdr">建议设置为db块的估计长度,这样试探的次数最小</param>
        /// <param name="type">Plc类型</param>
        /// <returns></returns>
        public int PLC_ReadDbLength(int db, int startByteAdr)
        {
            var type = S7DBAttribute.GetPlcType(db);
            int? dbLength = S7DataItemHelp.GetDbLength(db);
            if (dbLength != null)
            {
                return dbLength.Value;
            }

            var catchError = false;
            var readSuccess = false;
            dbLength = 0;
            while (startByteAdr >= 0)
            {
                try
                {
                    var result =  _plc.ReadBytes(S7.Net.DataType.DataBlock, db, startByteAdr, 1);
                    if (catchError)
                    {
                        dbLength = startByteAdr + 1;
                        break;
                    }

                    readSuccess = true;
                    startByteAdr++;
                }
                catch (Exception)
                {
                    if (readSuccess)
                    {
                        dbLength = startByteAdr;
                        break;
                    }

                    startByteAdr--;
                    catchError = true;
                }
            }

            //记住这个值,避免反复试探
            S7DataItemHelp.SetDBValue(db, dbLength.Value);

            return dbLength.Value;
        }

    }
}

  3、获取DB块中的地址以及偏移量

查看代码
 using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace S7Communication
{
    public static class S7AttributeHelp
    {
        /// <summary>
        /// 获取数据块的地址
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static int GetDB<T>() where T : BaseDB
        {
            Type type = typeof(T);
            S7DBAttribute sprayingDb = (S7DBAttribute)Attribute.GetCustomAttribute(type, typeof(S7DBAttribute));
            if (sprayingDb == null)
            {
                throw new Exception($"{type.FullName}  没有设置DB标签");
            }
            return sprayingDb.DB;
        }

        /// <summary>
        /// 获取数据块的地址
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static int GetDB(Type type)
        {
            S7DBAttribute sprayingDb = (S7DBAttribute)Attribute.GetCustomAttribute(type, typeof(S7DBAttribute));
            if (sprayingDb == null)
            {
                throw new Exception($"{type.FullName}  没有设置DB标签");
            }
            return sprayingDb.DB;
        }

        /// <summary>
        /// 获取在DB块里面的位置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static (int StartByteAdr, Byte BitAdr) GetAdress<T>(string name) where T : BaseDB
        {
            Type type = typeof(T);
            PropertyInfo propertyInfo = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            if (propertyInfo == null)
            {
                throw new Exception($"{type.FullName}  的 {name}  属性不存在");
            }
            S7PropertyAttribute s7Property = (S7PropertyAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(S7PropertyAttribute));
            if (s7Property == null)
            {
                throw new Exception($"{type.FullName}  没有设置DB标签");
            }
            return (s7Property.StartByteAdr, s7Property.BitAdr);
        }

        /// <summary>
        /// 获取在DB块里面的位置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static (int StartByteAdr, Byte BitAdr) GetAdress(Type type, string name)
        {
            PropertyInfo propertyInfo = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            if (propertyInfo == null)
            {
                throw new Exception($"{type.FullName}  的 {name}  属性不存在");
            }
            S7PropertyAttribute s7Property = (S7PropertyAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(S7PropertyAttribute));
            if (s7Property == null)
            {
                throw new Exception($"{type.FullName}  没有设置DB标签");
            }
            return (s7Property.StartByteAdr, s7Property.BitAdr);
        }
    }
}

  4、利用特性读取数据块地址、开始位置、偏移量等信息

查看代码
/// <summary>
    /// S7数据块特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
    public class S7DBAttribute : Attribute
    {
        /// <summary>
        /// 数据块地址
        /// </summary>
        public int DB;
        /// <summary>
        /// 存放所有数据块地址和Plc类型对应关系
        /// </summary>
        public static Dictionary<int, PlcPropertyType> S7DBDictionary = new Dictionary<int, PlcPropertyType>();

        /// <summary>
        /// 根据DB获取对应的DB类型
        /// </summary>
        /// <param name="db">数据块地址</param>
        /// <returns></returns>
        public static PlcPropertyType GetPlcType(int db)
        {
            return S7DBDictionary.ContainsKey(db) ? S7DBDictionary[db] : PlcPropertyType.MainPlc;
        }

        private PlcPropertyType _plcType = PlcPropertyType.MainPlc;

        /// <summary>
        /// Plc类型
        /// </summary>
        public PlcPropertyType PlcType
        {
            get
            {
                return _plcType;
            }
            set
            {
                _plcType = value;
                if (!S7DBDictionary.ContainsKey(DB))
                {
                    S7DBDictionary[DB] = _plcType;
                }
            }
        }
    }

    /// <summary>
    /// DB块字段属性
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class S7PropertyAttribute : Attribute
    {
        /// <summary>
        /// 起点地址
        /// </summary>
        public int StartByteAdr;

        /// <summary>
        /// 偏移量
        /// </summary>
        public byte BitAdr;
    }
}

  5、编写用于写入的DB类

查看代码
 /// <summary>
    /// 风扇
    /// </summary>
    [S7DB(DB = 706)]
    public class FanDB_R : BaseDB
    {
        /// <summary>
        /// 风扇1功率百分比值(前)
        /// </summary>
        [S7Property(StartByteAdr = 0, BitAdr = 0)]
        public float FanPowerFront { get; set; }

        /// <summary>
        /// 风扇2功率百分比值(后)
        /// </summary>
        [S7Property(StartByteAdr = 4, BitAdr = 1)]
        public float FanPowerRear { get; set; }
     
    }

    6、编写用于读取的DB类

查看代码
/// <summary>
    /// 风扇
    /// </summary>
    [S7DB(DB = 706)]
    public class FanDB_R : BaseDB
    {
        /// <summary>
        /// 风扇1功率百分比值(前)
        /// </summary>
        [S7Property(StartByteAdr = 0, BitAdr = 0)]
        public float FanPowerFront { get; set; }

        /// <summary>
        /// 风扇2功率百分比值(后)
        /// </summary>
        [S7Property(StartByteAdr = 4, BitAdr = 1)]
        public float FanPowerLeftRear { get; set; }
    }

  7、编写操作类

查看代码
 using S7.Net.Types;
using S7Communication.DBData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace S7Communication
{
    public class FanViewModel
    {
        public static FanViewModel Instance=new FanViewModel();

        private FanViewModel()
        {
            //读取逻辑
        }

        /// <summary>
        /// 风扇1功率百分比值(左前)
        /// </summary>
        public float FanPowerFront { get; set; }

        /// <summary>
        /// 风扇2功率百分比值(左后)
        /// </summary>
        public float FanPowerRear { get; set; }



        /// <summary>
        /// 启停前面的风扇
        /// </summary>
        /// <param name="isOpen">true:开启 false:关闭</param>
        /// <param name="PowerLeftFront">功率</param>
        public void FanPowerFrontOpen(bool isOpen,float powerValue=0)
        {
            if (isOpen)
            {
                S7CommunicationHelp.Instance.PLC_Write<FanDB_W, float>(x => x.FanPowerFront, powerValue);
            }
            else
            {
                S7CommunicationHelp.Instance.PLC_Write<FanDB_W, float>(x => x.FanPowerFront, 0);
            }

        }

        /// <summary>
        /// 启停后面的风扇
        /// </summary>
        /// <param name="isOpen">true:开启 false:关闭</param>
        /// <param name="PowerLeftFront">功率</param>
        public void FanPowerLeftRearOpen(bool isOpen, float powerValue = 0)
        {
            if (isOpen)
            {
                S7CommunicationHelp.Instance.PLC_Write<FanDB_W, float>(x => x.FanPowerFront, powerValue);
            }
            else
            {
                S7CommunicationHelp.Instance.PLC_Write<FanDB_W, float>(x => x.FanPowerFront, 0);
            }

        }
    }
}

  8、调用类

查看代码
 
using static S7Communication.S7Enums;

namespace S7Communication
{
    public class Progarm
    {
       public static void Main(string[] args)
        {
            PLC_CPUType _CPUType = PLC_CPUType.S71200;
            string ip = "192.168.1.32";
            short rack = 0;
            short slot=1;
            S7CommunicationHelp.Instance.PLCConnect(_CPUType,ip, rack,slot);

            if (S7CommunicationHelp.Instance.IsConnected)
            {
                //开启左前方风扇
                FanViewModel.Instance.FanPowerFrontOpen(true,30);

                //关闭左前方风扇
                FanViewModel.Instance.FanPowerFrontOpen(false);


            }
        }
    }

}

以上内容仅供参考

具体代码可以通过github下载:https://github.com/luoyekuangfeng/S7Communication.git

标签:通用,S7,DB,PLC,type,var,using,写法,public
From: https://www.cnblogs.com/zhaoyongsheng/p/17852590.html

相关文章

  • GPU部署llama-cpp-python(llama.cpp通用)
    title:GPU部署llama-cpp-python(llama.cpp通用)banner_img:https://cdn.studyinglover.com/pic/2023/08/a5e39db5abf0853e6c456728df8bd971.jpgdate:2023-8-623:01:00tags:-踩坑GPU部署llama-cpp-python(llama.cpp通用)通用流程我们的安装平台是Ubuntu20.04,Python3.......
  • Centos7 系统 /etc/fstab配置文件中文件系统类型错误导致进入紧急模式如何解决
    在格式化分区是我选择的ext4文件格式对分区sdc2进行了格式化,但是在写入配置文件是选择的文件格式是xfs,这导致了我的虚拟机进入系统时直接进入了紧急模式输入root密码进行维护,可以发现出现了命令窗,由于知道错误原因,所以可以直接从根源入手打开配置文件vim/etc/fstab我对设备......
  • Vmware虚拟机如何给Centos7系统添加硬盘且完成挂载
    打开Vmware右键我的计算机内容点击设置选择添加,然后选择硬盘,按照默认选项一直点击下一步直到完成。添加完后可以看到出现一块新硬盘,点击确定进行保存。启动虚拟机后打开终端进入root用户后输入lsblk可以看到sdc就是刚刚添加的新硬盘。现在使用fdisk工具对新硬盘进行分区,输入......
  • linux中普通用户修改密码出现(passwd:Authentication token manipulation error)
    如果在linux中,不管是root用户还是普通用户登录后,修改自己的密码时出现---passwd:Authenticationtokenmanipulationerror错误,如下所示: 1、root自己修改密码失败  2、普通用户修改密码失败报出这样的错误(密码:身份验证令牌操作错误),一般会有2种情况发生。    第1种:密码文......
  • 2023版 STM32实战7 通用同步/异步收发器(串口)F103/F407
    串口简介和习惯-1-通用同步异步收发器(USART)能够灵活地与外部设备进行全双工数据交换,满足外部设备对工业标准NRZ异步串行数据格式的要求。-2-硬件流控制一般是关闭的-3-波特率指单位时间传输bit个数-4-数据位一般是8位-5-一般无校验位编写代码思路-1-参考帮助手册(F1/F4都有)-2......
  • 2023版 STM32实战7 通用同步/异步收发器(串口)F103/F407
    串口简介和习惯-1-通用同步异步收发器(USART)能够灵活地与外部设备进行全双工数据交换,满足外部设备对工业标准NRZ异步串行数据格式的要求。 -2-硬件流控制一般是关闭的 -3-波特率指单位时间传输bit个数 -4-数据位一般是8位 -5-一般无校验位 编写代码思路 -......
  • CentOS7系统下的Linux命令基本操作(三)
    文件搜索命令文件搜索命令:find尽量不要用搜索命令,占用资源太大命令所在路径:/bin/find执行权限:所有用户语法:find[搜索范围][匹配条件]功能描述:文件搜索范例:$find/etc-nameinit在目录/etc中查找文件init若把init改成init,包含init四个字母的就都会被找到,否则只能找到就叫init......
  • C# 中增加一个使用StopWatch记录方法执行时间的通用方法
    目录一背景二源码2.1注意事项三使用方法一背景在很多时候我们在进行代码排查的时候需要在日志中记录代码的执行时间从而方便我们进行代码运行效率的执行,我们在日志中准确记录方法的执行时间,这样方便我们进行代码的排查,下面分享一个我们常用的记录方式,方便使用,而且最重要的......
  • RS808-ASEMI通用60瓦以内适配器桥堆RS808
    编辑:llRS808-ASEMI通用60瓦以内适配器桥堆RS808型号:RS808品牌:ASEMI封装:RS-4正向电流:8A反向电压:800V引线数量:4芯片个数:4芯片尺寸:95MIL漏电流:<5ua恢复时间:>500ns浪涌电流:250A芯片材质:正向电压:1.10V封装尺寸:如图特性:插件、薄体扁桥工作结温:-55℃~150℃包装方式:500/......
  • 807-ORI-S3R500 -多路PCIe3.0的单CPU通用工作站
    ORI-S3R500-多路PCIe3.0的单CPU通用工作站  (研华工业计算机IPC-610,IPC940 升级款)    一、机箱功能和技术指标:系统系统型号ORI-SR500主板支持EEB(12'*13')/CEB(12'*10.5')/ATX(12'*9.6')/MicroATX前置硬盘......