实现效果
实现步骤:
注意:详细的参数这里就不说明了,自己网上搜即可;
打开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
最后启动测试就可以了;