基于ModbusTCP与西门子PLC通讯项目案例

目录

一、西门子PLC仿真环境搭建

【1.1】创建PLC项目

【1.2】编写PLC程序

二、C#代码编写

【2.1】窗口制作

【2.2】效果演示

【2.3】读取源码

【2.4】FrmSiemensSet源码

【2.5】Variable源码


一、西门子PLC仿真环境搭建

【1.1】创建PLC项目

  • 搭建PLCSIM-Advacend模拟仿真

  • 设置PLC的IP地址和PLCSIM一致

  • 勾选GET/PUT(如果是S7协议必须勾选)选项

  • 勾选块编译时仿真

  • 创建变量用于测试,相关的DB块需要设置为去除优化访问

【1.2】编写PLC程序

【PLC作为服务器】

【Modbus Poll测试】

二、C#代码编写

【2.1】窗口制作

【2.2】效果演示

【2.3】读取源码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
​
using Approach.DataConvertLib;
using Approach.ModbusTCPLib;
​
namespace Approach.ModbusTCP
{public partial class FrmSiemens : Form{/// <summary>/// 【字段】ModbusTCP连接对象/// </summary>private ModbusTcp _modbusTcp = new ModbusTcp();
​/// <summary>/// 【字段】ModbusTCP连接成功标识/// </summary>private bool _isConnected = false;
​/// <summary>/// 【字段】多线程取消对象/// </summary>private CancellationTokenSource _cts = null;
​public FrmSiemens(){InitializeComponent();}
​/// <summary>/// 【控件事件】建立连接/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_Connect_Click(object sender, EventArgs e){// 获取UI信息string plcIp = txt_Ip.Text.Trim();int plcPort = int.Parse(txt_Port.Text.Trim());
​_isConnected = _modbusTcp.Connect(plcIp, plcPort);if (_isConnected == true){MessageBox.Show("与西门子PLC连接成功!", "连接提示");// 开启线程(创建取消线程对象)_cts = new CancellationTokenSource();// 开启线程(创建线程对象)Task.Run(new Action(() =>{PlcCommunicatin();}), _cts.Token);}else{MessageBox.Show("与西门子PLC连接失败!", "连接提示");}}
​/// <summary>/// 【方法】与PLC进行通信的线程方法/// </summary>private void PlcCommunicatin(){// 线程循环执行while(!_cts.IsCancellationRequested){// 通过ModbusTCP读取寄存器信息(PLC发送182字节->读取91个字)byte[] readData = _modbusTcp.ReadOutputRegisters(0, 91);// 读取对应的字节个数if(readData != null && readData.Length == 182) // 读取成功{// 解析报文,跟新UI数据Invoke(new Action(() => {UpdateUI(readData, gb_Read);UpdateUI(readData, gb_Write);}));}}}
​/// <summary>/// 【方法】/// </summary>/// <param name="data"> 被处理的数据字节数组 </param>/// <param name="conrtol"> 控件对象 </param>private void UpdateUI(byte[] data, Control control){if (!control.HasChildren)return;
​// 程序走到这里说明:Control控件中包含一个或者多个子控件foreach (var item in control.Controls.OfType<Label>()){// 排除掉一些标签控件if (item.Tag == null || item.Tag.ToString().Length == 0)continue;// 程序走到这里说明:获取的控件是需要进行操作的控件Variable variable = GetVariableByTag(item.Tag.ToString());if (variable != null){switch (variable.ValueType){case DataType.Bool:{item.BackColor = BitLib.GetBitFromByteArray(data, variable.Start, variable.OffsetOrLength) == true ? Color.LimeGreen : Color.Red;break;}case DataType.Byte:{item.Text = ByteLib.GetByteFromByteArray(data, variable.Start).ToString();break;}case DataType.Short:{item.Text = ShortLib.GetShortFromByteArray(data, variable.Start).ToString();break;}case DataType.UShort:{item.Text = UShortLib.GetUShortFromByteArray(data, variable.Start).ToString();break;}case DataType.Int:{item.Text = IntLib.GetIntFromByteArray(data, variable.Start).ToString();break;}case DataType.UInt:{item.Text = UIntLib.GetUIntFromByteArray(data, variable.Start).ToString();break;}case DataType.Float:{item.Text = FloatLib.GetFloatFromByteArray(data, variable.Start).ToString();break;}case DataType.Double:{item.Text = DoubleLib.GetDoubleFromByteArray(data, variable.Start).ToString();break;}case DataType.Long:{item.Text = LongLib.GetLongFromByteArray(data, variable.Start).ToString();break;}case DataType.ULong:{item.Text = ULongLib.GetULongFromByteArray(data, variable.Start).ToString();break;}case DataType.String:{item.Text = StringLib.GetSiemensStringFromByteArray(data, variable.Start, variable.OffsetOrLength);break;}}}}}
​/// <summary>/// 【方法】解析Lable->Tag的内容,将其转换为Variable这个类/// </summary>/// <param name="tagText"></param>/// <returns></returns>private Variable GetVariableByTag(string tagText){if (!tagText.Contains(";"))return null;
​// 程序走到这里说明该控件Tag内容是可以解析的string[] values = tagText.Split(';'); // 分割字符串if (values.Length != 3)return null;
​try{return new Variable(){ValueType = (DataType)Convert.ToInt32(values[0]),Start = Convert.ToInt32(values[1]),OffsetOrLength = Convert.ToInt32(values[2])};}catch (Exception){return null;}}
​/// <summary>/// 【控件事件】断开连接/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_DisConnect_Click(object sender, EventArgs e){if (_isConnected == true){_modbusTcp.DisConnect();}}
​/// <summary>/// 【控件事件】双击Label控件弹出数据修改对话框/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void CommonModify_DoubleClick(object sender, EventArgs e){if(sender is Label label){if (label.Tag == null || label.Tag.ToString().Length <= 0)return;
​// 程序走到这里说明:Label的Tag的值可以解析// 获取源值string srcValue = label.Text;// 获取Variable对象Variable variable = GetVariableByTag(label.Tag.ToString());FrmSiemensSet frmSiemensSet = new FrmSiemensSet(srcValue, variable, _modbusTcp);frmSiemensSet.ShowDialog();}}}
}

【2.4】FrmSiemensSet源码

using Approach.DataConvertLib;
using Approach.ModbusTCPLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
​
namespace Approach.ModbusTCP
{public partial class FrmSiemensSet : Form{private Variable _variable = null;private ModbusTcp _modbusTcp = null;
​public FrmSiemensSet(string srcValue, Variable variable, ModbusTcp modbusTcp){InitializeComponent();lbl_SrcValue.Text = srcValue;lbl_ValueType.Text = variable.ValueType.ToString();
​_variable = variable;_modbusTcp = modbusTcp;}
​
​
​private void btn_Ok_Click(object sender, EventArgs e){bool bResult = false;try{switch (_variable.ValueType){case DataType.Short:{bResult = _modbusTcp.PreSetSingleRegister((ushort)(_variable.Start / 2), Convert.ToInt16(txt_SetValue.Text.Trim()));break;}case DataType.UShort:{bResult = _modbusTcp.PreSetSingleRegister((ushort)(_variable.Start / 2), Convert.ToInt16(txt_SetValue.Text.Trim()));break;}case DataType.Int:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromInt(Convert.ToInt32(txt_SetValue.Text.Trim())));break;}case DataType.UInt:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromUInt(Convert.ToUInt32(txt_SetValue.Text.Trim())));break;}case DataType.Float:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromFloat(Convert.ToSingle(txt_SetValue.Text.Trim())));break;}case DataType.Double:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromDouble(Convert.ToDouble(txt_SetValue.Text.Trim())));break;}case DataType.Long:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromLong(Convert.ToInt64(txt_SetValue.Text.Trim())));break;}case DataType.ULong:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromULong(Convert.ToUInt64(txt_SetValue.Text.Trim())));break;}case DataType.String:{bResult = _modbusTcp.PreSetMultiRegisters((ushort)(_variable.Start / 2), ByteArrayLib.GetByteArrayFromSiemensString(txt_SetValue.Text.Trim()));break;}default:{MessageBox.Show("不支持该数据类型写入", "参数设置");return;}}}catch(Exception ex){MessageBox.Show("请检查参数数据类型是否正确:" + ex.Message, "参数设置");return;}
​if (bResult == true){this.DialogResult = DialogResult.OK;}}private void btn_Cancel_Click(object sender, EventArgs e){this.DialogResult = DialogResult.Cancel;}
​private void FrmSiemensSet_KeyDown(object sender, KeyEventArgs e){if (e.KeyCode == Keys.Enter)btn_Ok_Click(null, null);}}
}

【2.5】Variable源码

using Approach.DataConvertLib;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
namespace Approach.ModbusTCP
{/// <summary>/// 变量实体类封装/// </summary>public class Variable{/// <summary>/// 标签名称/// </summary>public string ValueName { get; set; }
​/// <summary>/// 起始字节/// </summary>public int Start { get; set; }
​/// <summary>/// 数据类型/// </summary>public DataType ValueType { get; set; }
​/// <summary>/// (位偏移)或(字符串)长度/// </summary>public int OffsetOrLength { get; set; }
​/// <summary>/// 变量实际值/// </summary>public object Value { get; set; }}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/127664.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三相PWM整流器滞环电流控制Simulink仿真模型

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Maven 配置阿里云镜像

1. 查找maven setting.xml配置文件 find / -name "setting.xml" 2. 添加阿里云镜像 修改maven根目录下的conf文件夹中的setting.xml文件中的mirrors下添加mirror标签 <settings> <localRepository>E:\Maven\repository</localRepository> <…

【哈士奇赠书活动 - 41期】- 〖产品设计软技能:创业公司篇〗

文章目录 ⭐️ 赠书 - 《产品设计软技能&#xff1a;创业公司篇》⭐️ 内容简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《产品设计软技能&#xff1a;创业公司篇》 ⭐️ 内容简介 在创业公司设计产品与在成熟公司设计产品存在明显差异。《产品设计软…

混沌工程初分享

混沌工程初分享 一、什么是混沌工程 1、什么是混沌 混沌是一种现象&#xff0c;在一个动力系统中&#xff0c;因为各种不同的参数变化导致的一系列的连锁反应。比如&#xff1a; 在南美洲亚马逊河流域热带雨林中的蝴蝶&#xff0c;偶尔的几次振翅&#xff0c;可以在两周以后引…

全栈开发笔记2:项目部署上线的三种方式

文章目录 最原始的方式宝塔Docker 部署其他 本文为编程导航实战项目学习笔记。 项目部署的三种方式&#xff1a; 最原始方式✅ yum 手动安装 jdk mysql tomcat nginx打包前端项目&#xff0c;放到某个目录&#xff0c;修改 nginx 配置修改线上的 mysql 配置&#xff0c;打包 j…

国庆出游远程实测:ToDesk 、TeamViewer、AnyDesk远程控制软件稳定性

ToDesk 、TeamViewer、AnyDesk远程控制软件稳定性 【前言】【实测软件】【测试环境】【实操体验】1. 软件安装2. 登录速度3. 文件传输4. 操作延迟5. 画面清晰度6. 安全防护 【本文小结】 【前言】 随着科技的不断发展&#xff0c;远程控制软件已成为我们生活中不可或缺的一部分…

任务工单发送失败重试方案设计

需求背景&#xff1a; 该系统为一个工单系统&#xff0c;其中任务工单为该系统中的一个模块&#xff1b;任务工单它是需要周期性调度的一种任务类型&#xff1b;可以按照用户配置的时间周期定时性触发的。由于任务需要发送到对应的工作人员上&#xff0c;所以这里需要先对员工进…

WEB各类常用测试工具

一、单元测试/测试运行器 1、Jest 知名的 Java 单元测试工具&#xff0c;由 Facebook 开源&#xff0c;开箱即用。它在最基础层面被设计用于快速、简单地编写地道的 Java 测试&#xff0c;能自动模拟 require() 返回的 CommonJS 模块&#xff0c;并提供了包括内置的测试环境 …

CocosCreator3.8研究笔记(二十四)CocosCreator 动画系统-动画编辑器实操-关键帧实现动态水印动画效果

上一篇&#xff0c;我们介绍了动画编辑器相关功能面板说明&#xff0c;感兴趣的朋友可以前往阅读&#xff1a; CocosCreator3.8研究笔记&#xff08;二十三&#xff09;CocosCreator 动画系统-动画编辑器相关功能面板说明。 熟悉了动画编辑器的基础操作&#xff0c;那么再使用动…

在PyCharm中添加anaconda环境

本文略过创建anaconda环境的部分~ 下文默认anaconda环境已经创建好 1. 点击新建项目 2. 1&#xff09;修改项目名称 2&#xff09;选择 “Previously configured interpreter” 曾经配置的解释器 3&#xff09;选择“Add Interpreter” 添加新的解释器 3. 选择 “A…

机器学习必修课 - 编码分类变量 encoding categorical variables

1. 数据预处理和数据集分割 import pandas as pd from sklearn.model_selection import train_test_split导入所需的Python库 !git clone https://github.com/JeffereyWu/Housing-prices-data.git下载数据集 # Read the data X pd.read_csv(/content/Housing-prices-data/t…

点击、拖拉拽开发可视化大屏,网友直呼不可思议

可视化大屏既足够炫酷&#xff0c;又能快速整合多业务系统数据&#xff0c;可视化分析数据&#xff0c;是一种可运用于博览中心、会议中心、监控中心、企业大屏看板等场景的常用数据可视化分析形式。但可视化大屏虽然好用&#xff0c;在开发制作上却难倒了不少人&#xff0c;直…