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
{
///


/// 将字符串地址转换为IO地址
///

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
{
///


/// 开发包目前只可链接三菱L系列PLC
///

public class uceNetConnectPLC
{
private Socket socket;
IOAddressToStringAddress IoToAdd = new IOAddressToStringAddress();
#region 链接PLC
///
/// 根据参数链接PLC
///

/// IP地址
/// PLC的端口号
///
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";

        }
    }
}

}

`

posted @ 2024-07-19 14:33  XXIIVV  阅读(50)  评论(0)    收藏  举报