1、导入S7.net通信文件:打开工具->NuGet包管理器->管理解决方案得NuGet程序包,入下图搜索S7,安装S7netplus。
在程序中引用S7.Net文件
建立西门子PLC类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using S7.Net;namespace 相机打开
{class SiemensPLC{//构造函数public SiemensPLC(){_plc = new Plc((CpuType)_plcType, _ipAddress, _crack, _slot);//_plc = new Plc(CpuType.S71500, _ipAddress, _crack, _slot);}/// <summary>/// PLC类型:S7200=0;Logo0BA8=1;S7200Smart=2;S7300=10,S7400=20;S71200=30;S71500=40;/// </summary>public int PLCType { get => _plcType; set => _plcType = value; }/// <summary>/// IP地址/// </summary>public string IpAdress { get => _ipAddress; set => IpAdress = value; }/// <summary>/// 机架/// </summary>public short Crack { get => _crack; set => _crack = value; }/// <summary>/// 槽/// </summary>public short Slot { get => _slot; set => _slot = value; }int _plcType=40;string _ipAddress="192.168.1.12";short _crack = 0;short _slot = 1;Plc _plc;/// <summary>/// PLC连接状态/// </summary>/// <returns></returns>public bool ConnectState { get => _plc.IsConnected; }/// <summary>/// PLC连接/// </summary>public void Connect(){try{_plc.Open();}catch(Exception ex){MessageBox.Show("PLC连接失败:"+ex.Message.ToString());}}/// <summary>/// 连接/// </summary>public void Disconnect(){try{_plc.Close();}catch (Exception ex){MessageBox.Show("PLC断开失败:" + ex.Message.ToString());}}/// <summary>/// 读取/// </summary>/// <param name="varName"></param>/// <returns></returns>public object Read(string varName,string varType){try{switch(varType){case "布尔":case "整数":return _plc.Read(varName);case "实数":return ((uint)_plc.Read(varName)).ConvertToFloat();case "字符":int dblength = varName.IndexOf(':') - 2;//DB号的长度int db = Convert.ToInt32(varName.Substring(2, dblength));//DB号int adrlength = varName.Length - varName.IndexOf(':') - 1;//startByteAdr的长度int startByteAddress = Convert.ToInt32(varName.Substring(varName.IndexOf(':') + 1, adrlength));//startByteAdrvar count = (byte)_plc.Read(DataType.DataBlock, db, startByteAddress, VarType.Byte, 1);return (string)_plc.Read(DataType.DataBlock, db, startByteAddress, VarType.S7String, count);default:return null;} }catch(Exception ex){MessageBox.Show("读取失败:" + ex.Message.ToString());return null;}}/// <summary>/// 写入/// </summary>/// <param name="varName"></param>/// <param name="varValue"></param>/// <param name="type"></param>位、字节、单字、双字和字符public void Write(string varName,string varValue,string type){try{switch(type){case "位":_plc.Write(varName, (varValue == "1") ? true : false);break;case "字节":_plc.Write(varName, Convert.ToByte(varValue));break;case "单字":_plc.Write(varName, Convert.ToInt16(varValue));break;case "双字":_plc.Write(varName, Convert.ToInt32(varValue));break;case "实数":_plc.Write(varName, Convert.ToSingle(varValue));break;case "字符":int dblength = varName.IndexOf(':') - 2;//DB号的长度int db = Convert.ToInt32(varName.Substring(2,dblength));//DB号int adrlength = varName.Length - varName.IndexOf(':')-1;//startByteAdr的长度int startByteAddress = Convert.ToInt32(varName.Substring(varName.IndexOf(':')+1, adrlength));//startByteAdr//var temp = System.Text.Encoding.ASCII.GetBytes(varValue);//编码var temp = System.Text.Encoding.Unicode.GetBytes(varValue);//编码var bytes = S7.Net.Types.S7String.ToByteArray(varValue, temp.Length);//字节数组_plc.WriteBytes(DataType.DataBlock, db, startByteAddress, bytes);break;default:break;}}catch(Exception ex){MessageBox.Show("写入失败:" + ex.Message.ToString());}}}
}
参考教程:https://www.cnblogs.com/xhubobo/p/14573092.html
https://www.cnblogs.com/minily/p/13324120.html
建立winform程序
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;
using System.Threading;
using S7.Net;
using HalconDotNet;
using System.Diagnostics;namespace 相机打开
{public partial class Form1 : Form{bool isMThread = false;//是否位多线程模式bool isStart = false;//线程模式启动Task collectTask;//识别子线程// Local iconic variables HObject ho_Image = null, ho_GrayImage = null;// Local control variables HTuple hv_AcqHandle = null;//相机窗口句柄HTuple hv_WindowHandle = null;//窗口句柄HTuple hv_Width = new HTuple(), hv_Height = new HTuple();//PLC变量SiemensPLC PLC = new SiemensPLC();bool connectState = false;//线程变量Thread monitorThread;public Form1(){InitializeComponent();// Default settings used in HDevelop HOperatorSet.SetSystem("width", 512);HOperatorSet.SetSystem("height", 512);if (HalconAPI.isWindows)HOperatorSet.SetSystem("use_window_thread", "true");action();}/// <summary>/// 视觉窗口初始化/// </summary>private void action(){// Initialize local and output iconic variables HOperatorSet.GenEmptyObj(out ho_Image);HOperatorSet.GenEmptyObj(out ho_GrayImage);//Image Acquisition 01: Code generated by Image Acquisition 01//判断窗口是否打开if(HDevWindowStack.IsOpen()){HOperatorSet.CloseWindow(HDevWindowStack.Pop());}HOperatorSet.SetWindowAttr("background_color", "black");hv_WindowHandle = this.hWindowControl1.HalconID;HOperatorSet.OpenWindow(0, 0, this.hWindowControl1.Width, this.hWindowControl1.Height, this.hWindowControl1.HalconWindow, "visible", "", out hv_WindowHandle);HDevWindowStack.Push(hv_WindowHandle);}/// <summary>/// 采用定时器方式/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void timer1_Tick(object sender, EventArgs e){if(hv_AcqHandle==null){return;}CollectImage();//图像采集}/// <summary>/// 图像采集/// </summary>private void CollectImage(){ho_Image.Dispose();if (hv_AcqHandle==null){return;}HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);if (HDevWindowStack.IsOpen()){HOperatorSet.DispObj(ho_Image, HDevWindowStack.GetActive());}//HOperatorSet.WaitSeconds(0.1);ho_GrayImage.Dispose();HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage);HOperatorSet.DispObj(ho_GrayImage, HDevWindowStack.GetActive());HOperatorSet.GetImageSize(ho_GrayImage, out hv_Width, out hv_Height);HOperatorSet.SetPart(HDevWindowStack.GetActive(), 0, 0, hv_Height, hv_Width);//HOperatorSet.WaitSeconds(0.1);}/// <summary>/// 相机打开/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_OpenCamera_Click(object sender, EventArgs e){//打开相机HOperatorSet.OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "rgb",-1, "false", "default", "[0] Integrated Camera", 0, -1, out hv_AcqHandle);HOperatorSet.GrabImageStart(hv_AcqHandle, -1);}/// <summary>/// 启动停止按钮/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_StartCollect_Click(object sender, EventArgs e){if(this.rdb_Timer.Checked==true){if (this.timer1.Enabled == false){this.timer1.Enabled = true;this.btn_StartCollect.Text = "停止采集";this.rdb_MThread.Enabled = false;this.rdb_Timer.Enabled = false;}else{this.timer1.Enabled = false;this.btn_StartCollect.Text = "开始采集";this.rdb_MThread.Enabled = true;this.rdb_Timer.Enabled = true;}}else if(this.rdb_MThread.Checked==true){if(this.btn_StartCollect.Text=="开始采集"){isStart = true;btn_StartCollect.Text = "停止采集";this.rdb_MThread.Enabled = false;this.rdb_Timer.Enabled = false;//实例化子线程collectTask = new Task(() =>{while (isStart){CollectImage();}});collectTask.Start();}else{this.btn_StartCollect.Text = "开始采集";this.rdb_MThread.Enabled = true;this.rdb_Timer.Enabled = true;isStart = false;}}else{MessageBox.Show("请先选择模式!");}}/// <summary>/// 关闭窗体/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Form1_FormClosing(object sender, FormClosingEventArgs e){Process.GetCurrentProcess().Kill();}private void btn_PLCConnect_Click(object sender, EventArgs e){//连接线程ThreadPool.QueueUserWorkItem(t => PLC.Connect());}/// <summary>/// 退出按钮/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_Exit_Click(object sender, EventArgs e){Process.GetCurrentProcess().Kill();}private void btn_Disconnect_Click(object sender, EventArgs e){//断开线程ThreadPool.QueueUserWorkItem(t => PLC.Disconnect());}private void Form1_Load(object sender, EventArgs e){//监控线程monitorThread = new Thread(monitorFunc);monitorThread.Start();}private void btn_SingleRead_Click(object sender, EventArgs e){ThreadPool.QueueUserWorkItem(t=>SingleRead());}/// <summary>/// 关闭相机/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_CloseCamera_Click(object sender, EventArgs e){if (collectTask.Status == TaskStatus.Running || this.timer1.Enabled == true){MessageBox.Show("请先停止采集!");return;}//关闭相机if (hv_AcqHandle != null){HOperatorSet.CloseFramegrabber(hv_AcqHandle);}ho_Image.Dispose();ho_GrayImage.Dispose();}private void btn_Write_Click(object sender, EventArgs e){ThreadPool.QueueUserWorkItem(t=>SingleWrite());}public void monitorFunc(){while(true){connectState = PLC.ConnectState;this.Invoke((MethodInvoker)delegate{lbl_ConnectState.Text = connectState ? "Connected" : "Disconnected";btn_PLCConnect.Enabled = connectState ? false : true;btn_Disconnect.Enabled = connectState ? true : false;lbl_ConState.BackColor = connectState ? Color.Lime : Color.Red;});Thread.Sleep(100);}}public void SingleRead(){ connectState = PLC.ConnectState;this.Invoke((MethodInvoker)delegate{var value = PLC.Read(tbx_RSignleName.Text.Trim(), cbx_RTypeSelect.Text.Trim());tbx_RSingleValue.Text = Convert.ToString(value);});}public void SingleWrite(){this.Invoke((MethodInvoker)delegate{PLC.Write(tbx_WSignleName.Text.Trim(), tbx_WSingleValue.Text.Trim(), cbx_WTypeSelect.Text.Trim());});}}
}
里面还包含一部分Halcon程序,最终的目的是实现PLC程序通过Halcon程序控制相机。
建立S71500PLC仿真
采用S7-PLCSIM Advanced 3.0
建立西门子博图项目
提前设置电脑的PG端口
在博图中建立一个DB块
打开西门子仿真软件
这个仿真软件用一段时间后就需要重启,否则博图下载程序时找不到端口,有时候还需要重新启动博图软件才能正常下载程序
首先连接PLC,然后给DB1.DBX0.0赋值1,观察博图的监控画面
写入成功
读取成功
分别尝试字节、单字、双字写入读取都顺利
实数读写
比较麻烦的是字符串的读取和写入
西门子PLC有两种字符串,一种是String,另一种是WString,前者是每一个字符由两个字节构成,大小为256个字节;后者是每一个字符由四个字节构成,大小为512个字节。
所以英文字符采用String,中文字符采用WString,虽然WString在博图中无法查看具体字符串,只能看到编码,但是不影响正常的写入和读取。