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";

            }
        }
    }

}


posted @   XXIIVV  阅读(158)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示