C#操作三菱FX系列PLC数据(通讯)
具体三菱PLC的通信协议格式如这篇博文中的举例,可以参考一下
点击查看代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/*
CreateBy:sappmims@163.com
date:2019-10-10
使用Socket方式与PLC通讯中的数据使用的是 地址转换为具体的操作方法,这段代码只使用了int 读写,bool读写。
俗话说的D 地址,M地址。
具体就是将如 读取M300的位, 这样一个地址转换为 500000FF03FF000018001004010001 M*00 0300 0001 这样一个地址头,然后再使用socket发送到PLC。等待PLC返回数据。
因为三菱PLC的操作都是在socket传送的数据中心完成的,所以发送的字符串中的相应的位就代表需要干的事情。这里面还是有很多规定的,具体的相关协议可以参考三菱的官方文档,不同系列PLC之间使用的也不一样。
当前这个代码通讯的PLC为:L61PR,R61,其他的PLC还没有经过测试。
*/
namespace UCE_NetConnectPLC
{
/// <summary>
/// 将字符串地址转换为IO地址
/// </summary>
class IOAddressToStringAddress
{
/// <summary>
/// 转换为读取INT地址
/// </summary>
/// <param name="IO">IO地址</param>
/// <returns></returns>
public string GetReadIntAddress(string IO)
{
//500000FF03FF000018001004010000 D*00 7000 0002 //D7000读取 int
string strHed = IO.Substring(0, 1);//得出地址头,M,D地址头 M3000得出M,
string address = IO.Substring(1, IO.Length - 1);//得出地址的长度
string addr = "500000FF03FF000018001004010000";//固定信息头
switch (IO.Length)
{
case 2://m3
addr += strHed + "*00000" + address + "0002";//002固定读取头部int
break;
case 3://m30
addr += strHed + "*0000" + address + "0002";
break;
case 4://m300
addr += strHed + "*000" + address + "0002";
break;
default://m3000
addr += strHed + "*00" + address + "0002";
break;
}
return addr;
}
/// <summary>
/// 转换为读取位(布尔)地址
/// </summary>
/// <param name="IO"></param>
/// <returns></returns>
public string GetReadBoolAddress(string IO)
{
//500000FF03FF000018001004010001 M*00 3001 0001 //M3001读取位
string strHed = IO.Substring(0, 1);//得出地址头,M,D地址头 M3000得出M,
string address = IO.Substring(1, IO.Length - 1);//得出地址的长度
string addr = "500000FF03FF000018001004010001";//固定信息头
switch (IO.Length)
{
case 2://m3
addr += strHed + "*00000" + address + "0001";//001固定读取位头部
break;
case 3://m30
addr += strHed + "*0000" + address + "0001";
break;
case 4://m300
addr += strHed + "*000" + address + "0001";
break;
default://m3000
addr += strHed + "*00" + address + "0001";
break;
}
return addr;
}
/// <summary>
/// 转换为读取Log地址
/// </summary>
/// <param name="IO"></param>
/// <returns></returns>
public string GetReadLogAddress(string IO)
{
//500000FF03FF000018001004010000 M*00 3001 0004 //M3001读取 log
string strHed = IO.Substring(0, 1);//得出地址头,M,D地址头 M3000得出M,
string address = IO.Substring(1, IO.Length - 1);//得出地址的长度
string addr = "500000FF03FF000018001004010000";//固定信息头
switch (IO.Length)
{
case 2://m3
addr += strHed + "*00000" + address + "0004";//004固定读取位头部
break;
case 3://m30
addr += strHed + "*0000" + address + "0004";
break;
case 4://m300
addr += strHed + "*000" + address + "0004";
break;
default://m3000
addr += strHed + "*00" + address + "0004";
break;
}
return addr;
}
/// <summary>
/// 转换为写入INT地址,取回地址后需要加上实际数据字符串000A 0000(000A=10)
/// </summary>
/// <param name="IO">IO地址</param>
/// <returns></returns>
public string GetWriteIntAddress(string IO)
{
//500000FF03FF000020001014010000 M*00 01000 0002 000A 0000 //M100写入int 10
string strHed = IO.Substring(0, 1);//得出地址头,M,D地址头 M3000得出M,
string address = IO.Substring(1, IO.Length - 1);//得出地址的长度
string addr = "500000FF03FF000020001014010000";//固定信息头
switch (IO.Length)
{
case 2://m3
addr += strHed + "*00000" + address + "0002";//002固定读取头部int
break;
case 3://m30
addr += strHed + "*0000" + address + "0002";
break;
case 4://m300
addr += strHed + "*000" + address + "0002";
break;
default://m3000
addr += strHed + "*00" + address + "0002";
break;
}
return addr;
}
/// <summary>
/// 转换为写入位地址,取回后续加上位值(1 true,0 false)
/// </summary>
/// <param name="IO">IO地址</param>
/// <returns></returns>
public string GetWriteBoolAddress(string IO)
{
//500000FF03FF000019001014010001 M*00 0100 0001 1 //M100写入位TRUE
string strHed = IO.Substring(0, 1);//得出地址头,M,D地址头 M3000得出M,
string address = IO.Substring(1, IO.Length - 1);//得出地址的长度
string addr = "500000FF03FF000019001014010001";//固定信息头
switch (IO.Length)
{
case 2://m3
addr += strHed + "*00000" + address + "0001";//001固定读取头部int
break;
case 3://m30
addr += strHed + "*0000" + address + "0001";
break;
case 4://m300
addr += strHed + "*000" + address + "0001";
break;
default://m3000
addr += strHed + "*00" + address + "0001";
break;
}
return addr;
}
/// <summary>
/// 转换为写入Log地址,取回后续加上值(0065 0000(0065=100))
/// </summary>
/// <param name="IO">IO地址</param>
/// <returns></returns>
public string GetWriteLogAddress(string IO)
{
//500000FF03FF000028001014010000 M*00 0100 00004 0065 0000
string strHed = IO.Substring(0, 1);//得出地址头,M,D地址头 M3000得出M,
string address = IO.Substring(1, IO.Length - 1);//得出地址的长度
string addr = "500000FF03FF000028001014010000";//固定信息头
switch (IO.Length)
{
case 2://m3
addr += strHed + "*00000" + address + "0004";//004固定读取头部int
break;
case 3://m30
addr += strHed + "*0000" + address + "0004";
break;
case 4://m300
addr += strHed + "*000" + address + "0004";
break;
default://m3000
addr += strHed + "*00" + address + "0004";
break;
}
return addr;
}
}
}
当使用IO地址转换好之后再将具体的数据发送给PLC,具体请参考代码,相应的在代码中都有注释了。
点击查看代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Net.NetworkInformation;
/*
createBy: Bevan Liang.
date:2019-10-16
sappmis@163.com
*/
namespace UCE_NetConnectPLC
{
/// <summary>
/// 开发包目前只可链接三菱L系列PLC
/// </summary>
public class uceNetConnectPLC
{
private Socket socket;
IOAddressToStringAddress IoToAdd = new IOAddressToStringAddress();
#region 链接PLC
/// <summary>
/// 根据参数链接PLC
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="port">PLC的端口号</param>
/// <returns></returns>
public bool ConnectServer(string ip, string port)
{
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//声明套接字
IPAddress ipadd = IPAddress.Parse(ip);
IPEndPoint point = new IPEndPoint(ipadd, Convert.ToInt32(port));
socket.Connect(point);
isConnection = true;
return true;
}
catch (Exception ex)
{
ErrorMsg = "连接错误:"+ex.Message;
return false;
}
}
#endregion
private bool isConnection;
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMsg { get; private set; }
/// <summary>
/// 获取PLC的当前链接状态
/// </summary>
public bool IsConnection
{
get => isConnection;
// set => isConnection = value;
}
/// <summary>
/// 将结果转换成位。
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private bool IsResult(string str)
{
try
{
str = str.Replace("\0","");
if (str.Substring(str.Length - 1, 1) == "1")//这段判断位的代码不够严谨,应该需要充分数据大小的情况再做判断。
{
return true;
}
return false;
}
catch
{
ErrorMsg = "结果转换失败.";
return false;
}
}
#region 根据PLC地址IO获取位信息
/// <summary>
/// 根据PLC地址IO获取位信息
/// </summary>
/// <param name="IO">PLC的IO点</param>
/// <returns></returns>
public bool ResultsBool(ref string IO)
{
bool results = false;
if (IsConnection)
{
string str = IoToAdd.GetReadBoolAddress(IO);
byte[] bt = System.Text.Encoding.ASCII.GetBytes(str);
socket.Send(bt);
results = IsResult(GetDataResult());
return results;
}
else
{
ErrorMsg = "链接PLC失败.";
return results;
}
}
#endregion
#region 读取PLC返回的结果。
/// <summary>
/// 读取PLC返回的结果。
/// </summary>
/// <returns></returns>
private string GetDataResult()
{
string str = null;
while (true)
{
byte[] data = new byte[1024];
socket.Receive(data);
string strdata = Encoding.UTF8.GetString(data);
if (!string.IsNullOrEmpty(strdata))
{
str = strdata;
break;
}
}
return str;
}
#endregion
/// <summary>
/// 关闭PLC的TCP链接
/// </summary>
public void ServerClose()
{
try
{
if (IsConnection)
{
this.socket.Shutdown(SocketShutdown.Both);
}
}
finally
{
this.socket.Close();
}
}
/// <summary>
/// 将字符串转换为16进制,并给足4位
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private string GetValueHexl(string value)
{
string s = string.Empty;
try
{
s = Convert.ToString(Convert.ToInt32(value), 16);
switch (s.Length)
{
case 1:
s = "000" + s;
break;
case 2:
s = "00" + s;
break;
case 3:
s = "0" + s;
break;
default:
break;
}
return s;
}
catch { return s; }
}
/// <summary>
/// 根据IO点读取INT值,获取成功返回真
/// </summary>
/// <param name="IO">IO地址</param>
/// <param name="result">返回值</param>
/// <returns></returns>
public bool GetReadIntResult(string IO,ref int result)
{
string addr = IoToAdd.GetReadIntAddress(IO);
if (IsConnection)
{
byte[] bt = System.Text.Encoding.ASCII.GetBytes(addr);
socket.Send(bt);
result = GetHexToInt(GetDataResult());
return true;
}
else
{
// ErrorMsg = "链接PLC失败";
return false;
}
}
/// <summary>
/// 根据IO写入int值
/// </summary>
/// <param name="IO">IO位置</param>
/// <param name="value">要写入的值</param>
/// <returns></returns>
public bool SetIntToResult(string IO, int value)
{
string addr = IoToAdd.GetWriteIntAddress(IO);
addr += GetIntToHexString(value)+"0000";
if (IsConnection)
{
byte[] bt = System.Text.Encoding.ASCII.GetBytes(addr);
socket.Send(bt);
int results = GetHexToInt(GetDataResult());
return true;
}
else
{
ErrorMsg = "链接PLC失败";
return false;
}
}
/// <summary>
/// 根据IO写入位(bool)值
/// </summary>
/// <param name="IO">IO位置</param>
/// <param name="value">要写入的值(0,1)</param>
/// <returns></returns>
public bool SetBoolToResult(string IO, int value)
{
string addr = IoToAdd.GetWriteBoolAddress(IO);
addr += value;
if (IsConnection)
{
byte[] bt = System.Text.Encoding.ASCII.GetBytes(addr);
socket.Send(bt);
int results = GetHexToInt(GetDataResult());
return true;
}
else
{
ErrorMsg = "链接PLC失败";
return false;
}
}
/// <summary>
/// 转换16进制为十进制
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private int GetHexToInt(string str)
{
try
{
if (str.Length > 0)
{
str = str.Substring(22,4);
int result = int.Parse(str, System.Globalization.NumberStyles.AllowHexSpecifier);
return result;
}
else
{
return 0;
}
}
catch(Exception ex)
{
ErrorMsg = "转换10进制 错误";
return 0;
}
}
/// <summary>
/// 将int32位转换为16进制字符串
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private string GetIntToHexString(int value)
{
var Hex = Convert.ToString(value, 16);
switch (Hex.Length)//根据字符串长度返回适合的IO地址附加码
{
case 1:
return "000" + Hex;
case 2:
return "00" + Hex;
case 3:
return "0" + Hex;
default:
return "0000";
}
}
}
}
完
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?