实现效果
实现步骤:
注意:详细的参数这里就不说明了,自己网上搜即可;
打开GX Works3 创建FX5U项目
系统参数设置PLC的具体型号(我有实物PLC)
设置IP及组态参数
添加通讯设备(这里PLC做客户端,因此添加:Active连接设备);
设置PLC的端口号、服务器IP、服务器端口号;
当前添加的设备No为1,记住这个参数,后面程序要输入;
配置完后点击应用并下载到PLC,下载完要重启PLC;
下面不废话,直接上PLC程序;
重点:
在线监控数据
监控D1300是通讯接收数据的起始地址,同时它还存储对方使用了多少个字节发送数据过来;那么我们要截取数据就要从D1301及以后开始截;
还看到PC只发了5个字符,但是收到却多了一位(发:SN123;收:SN1239);那么就要处理一下;把多余的字符删掉;
本项目案例把收到的数据又传回给PC;经过上面的处理已经拿到完整的数据了,然后置位一下M11就能把数据发给PC,注意每次发送都要触发一下M11,可以自己改成自动发送;
C#部分
创建一个页面 SocketPage.xaml
页面代码
<Page x:Class="WpfApp4.Views.SocketPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp4.Views"mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="650"Title="SocketPage" ><Grid><Grid.ColumnDefinitions><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="35"/><RowDefinition Height="35"/><RowDefinition Height="35"/><RowDefinition/></Grid.RowDefinitions><StackPanel Orientation="Horizontal" Grid.Row="0"><Border Height="30" Width="100" Background="White"><TextBlock Text="状态显示" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"/></Border><Border Height="30" Width="500" Background="#FF0ABEFF"><TextBlock Text="欢迎使用该软件" x:Name="txtb_serverData" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/></Border></StackPanel><StackPanel Orientation="Horizontal" Grid.Row="1"><Border Height="30" Width="100" Background="White"><TextBlock Text="读取信息" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"/></Border><Border Height="30" Width="500" Background="#FF0ABEFF"><TextBlock Text="------" x:Name="txtb_reData" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/></Border></StackPanel><StackPanel Orientation="Horizontal" Grid.Row="2"><Border Height="30" Width="100" Background="White"><TextBlock Text="连接设备" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"/></Border><Border Height="30" Width="500" Background="#FF0ABEFF"><TextBlock Text="127.0.0.0:888" x:Name="txtb_ConnentDevice" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/></Border></StackPanel><StackPanel Orientation="Horizontal" Grid.Row="3"><GroupBox Header="服务器与PLC通讯" Width="250" Height="150" FontSize="20" BorderBrush="#FF0ABEFF" BorderThickness="2"><Grid><Grid.ColumnDefinitions><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition/><RowDefinition/><RowDefinition/></Grid.RowDefinitions><StackPanel VerticalAlignment="Center" Orientation="Horizontal" Grid.Row="0"><Border HorizontalAlignment="Left" ><TextBlock Text="服务器IP: " /></Border><Border HorizontalAlignment="Right" ><TextBox Text="192.168.2.223" x:Name="txb_ServerAdderess" VerticalAlignment="Center" TextAlignment="Center" FontSize="16" Width="145"/></Border></StackPanel><StackPanel VerticalAlignment="Center" Orientation="Horizontal" Grid.Row="1"><Border HorizontalAlignment="Left" ><TextBlock Text="端口号: " /></Border><Border HorizontalAlignment="Right"><TextBox Text="8000" x:Name="txb_Prot" Width="100" TextAlignment="Center"/></Border></StackPanel><Border Grid.Row="2" Width="150" Height="30"><Button x:Name="btn_OpenConnent" Content="打开服务器" Click="Button_OpenProtClick"/></Border></Grid></GroupBox><GroupBox Header="写数据给PLC" Width="250" Height="150" FontSize="20" BorderBrush="#FF0ABEFF" BorderThickness="2"><Grid><Grid.ColumnDefinitions><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition/><RowDefinition/><RowDefinition/></Grid.RowDefinitions><StackPanel VerticalAlignment="Center" Orientation="Horizontal" Grid.Row="0"><Border HorizontalAlignment="Left" ><TextBlock Text="开 头: " Width="70"/></Border><Border HorizontalAlignment="Right" ><TextBox Text="SN" x:Name="txb_WriteSN" VerticalAlignment="Center" TextAlignment="Center" FontSize="16" Width="145"/></Border></StackPanel><StackPanel VerticalAlignment="Center" Orientation="Horizontal" Grid.Row="1"><Border HorizontalAlignment="Left" ><TextBlock Text="序列号: " Width="70"/></Border><Border HorizontalAlignment="Right"><TextBox Text="123456789" x:Name="txb_WriteNume" Width="145" TextAlignment="Center" FontSize="16"/></Border></StackPanel><Border Grid.Row="2" Width="150" Height="30"><Button x:Name="btn_WriteDevice" Content="写入" Click="btn_WriteDevice_Click"/></Border></Grid></GroupBox></StackPanel></Grid>
</Page>
页面后台代码
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;namespace WpfApp4.Views
{/// <summary>/// SocketPage.xaml 的交互逻辑/// </summary>public partial class SocketPage : Page{public SocketPage(){InitializeComponent();}/// <summary>/// 打开/关闭连接/// </summary>bool isConnent = false;/// <summary>/// 服务器已创建/// </summary>bool isOpenConnent = false;/// <summary>/// 触发写入/// </summary>bool btn_Write = false;//第一步:调用socket()函数创建一个用于通信的套接字private Socket listenSocket;//字典集合:存储IP和Socket的集合private Dictionary<string, Socket> OnLineList = new Dictionary<string, Socket>();//编码格式Encoding econding = Encoding.Default;private void Button_OpenProtClick(object sender, EventArgs e){if (isConnent){MessageBox.Show("服务器已开启,请勿重复点击!");return;}if (!isOpenConnent){//第一步:调用socket()函数创建一个用于通信的套接字listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);isOpenConnent = true;}//第二步:给已经创建的套接字绑定一个端口号,这一般通过设置网络套接口地址和调用Bind()函数来实现IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(this.txb_ServerAdderess.Text.Trim()), int.Parse(this.txb_Prot.Text.Trim()));try{listenSocket.Bind(endPoint);}catch (Exception ex){MessageBox.Show("服务器开启失败:" + ex.Message, "开启服务器");//listenSocket.Shutdown(SocketShutdown.Both);//listenSocket.Close();//MessageBox.Show("关闭服务器中......");isOpenConnent = false;return;}//第三步:调用listen()函数使套接字成为一个监听套接字listenSocket.Listen(10);//ShowMessage("服务器开启成功");MessageBox.Show("服务器开启成功");isConnent = true;this.Dispatcher.Invoke(new Action(() =>{txtb_serverData.Text = "服务器开启成功!等待客户端连接中......";btn_OpenConnent.Background = new SolidColorBrush(Colors.Green);}));if (isOpenConnent){//开启一个线程监听Task.Run(new Action(() =>{ListenConnection();}));}}private void ListenConnection(){try{while (true){Socket clientSocket = listenSocket.Accept();string ip = clientSocket.RemoteEndPoint.ToString();//MessageBox.Show(ip + "上线了");this.Dispatcher.Invoke(new Action(() =>{txtb_ConnentDevice.Text = "当前连接设备:" + ip;}));Task.Run(() => ReceiveMsg(clientSocket));Task.Run(() => WriteDeviceMsg(clientSocket));}}catch (Exception){throw;}}/// <summary>/// 接收方法/// </summary>/// <param name="clientSocket"></param>private void ReceiveMsg(Socket clientSocket){try{// // 接收数据byte[] bytesToUse = new byte[60];int numberOfBytesRec = clientSocket.Receive(bytesToUse);string returndata = Encoding.ASCII.GetString(bytesToUse, 0, numberOfBytesRec);//Console.WriteLine("从客户端收到: " + returndata);this.Dispatcher.Invoke(new Action(() =>{txtb_serverData.Text = "从客户端收到: " + returndata;}));while (true){numberOfBytesRec = clientSocket.Receive(bytesToUse);returndata = Encoding.ASCII.GetString(bytesToUse, 0, numberOfBytesRec);Thread.Sleep(10);this.Dispatcher.Invoke(new Action(() =>{txtb_reData.Text = returndata;txtb_serverData.Text = "从客户端收到: " + returndata;}));//Console.WriteLine("从客户端收到: " + returndata);Thread.Sleep(1000);}}catch (Exception ex){MessageBox.Show("接收报错:" + ex.Message);}}private void WriteDeviceMsg(Socket clientSocket){// 发送数据回客户端string response = "Hello from server";byte[] msg = Encoding.ASCII.GetBytes(response);try{while (true){this.Dispatcher.Invoke(new Action(() =>{response = txb_WriteSN.Text.ToString() + txb_WriteNume.Text.ToString();msg = Encoding.ASCII.GetBytes(response);}));if (btn_Write){clientSocket.Send(msg);//Console.WriteLine("发送到客户端: " + response);btn_Write = false;}Thread.Sleep(1000);}}catch (Exception){throw;}}/// <summary>/// 消息发送/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_WriteDevice_Click(object sender, EventArgs e){btn_Write = true;return;}}
}
注意:要把当前连接PLC的网卡设置成服务器IP
最后启动测试就可以了;