三菱PLC 编程口串口通讯

工作中写的三菱PLC串口通讯,封装成了一个类,可以方便随时调用;

数据传送分为 循环 和 一次性 两种方式;

为了避免冲突,数据的收发使用了一个线程来排队完成。

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO.Ports;

namespace 三菱PLC读写
{
    class mitsubishi
    {
        Thread mitsubishiTread; //mitsubishi
        SerialPort m_sp;
        int m_sendAddr, m_sendLen, m_recieveAddr, m_recieveLen;
        bool[] m_Q = new bool[5];    //是否已请求
        bool[] m_R = new bool[5];    //是否已回复
        char[] m_T = new char[5];    //类型
        int[] m_A = new int[5];    //地址
        char[] m_C = new char[5];    //命令
        int[] m_D = new int[5];    //发出数据
        bool[] m_R_Bool = new bool[5];    //返回值
        int[] m_R_Int = new int[5];    //返回值
        public byte[] m_wData, m_rData;    //循环写和读数据
        char[] m_WData;    //循环写数据转换格式
        bool circle = false;    //是否循环读写,判断不同字节长度


        #region mitsubishi类构造函数
        public mitsubishi(string portName, int sendA, int sendL, int revA, int revL)    //(串口号、写入起始地址、写入字节长度、读取起始地址、读取字节长度)
        {
            m_sp = new SerialPort();
            m_sp.PortName = portName;
            m_sp.BaudRate = 9600;
            m_sp.DataBits = 7;
            m_sp.StopBits = (StopBits)1;
            m_sp.Parity = Parity.Even;
            m_sp.ReadTimeout = 500;

            //收发数据起始地址和字节长度
            m_sendAddr = sendA;
            m_sendLen = sendL;
            m_recieveAddr = revA;
            m_recieveLen = revL;
            m_wData = new byte[sendL];
            m_rData = new byte[revL];
            m_WData = new char[sendL*2];

            if (!m_sp.IsOpen)
            {
                m_sp.Open();
                Thread.Sleep(500);  //串口打开,等待0.5S后开始启动线程

                mitsubishiTread = new Thread(new ThreadStart(start));
                mitsubishiTread.Start();
            }
            else
            {
                MessageBox.Show("串口已被打开,请检查端口!");
                m_sp.Close();
            }
        
        }
        #endregion

        #region 单线程排队发送
        public void start()
        {
            while (true)
            {
                //这里用排序发送
                if (!m_sp.IsOpen)
                {
                    m_sp.Open();
                    Thread.Sleep(500);  //串口打开,等待0.5S后开始发送
                }

                //有排队先完成
                m_First();

                //循环写部分
                circle = true;
                for (int i = 0; i < m_sendLen; i++)
                {
                    m_WData[i * 2] = Tran2(m_wData[i] / 0x10);
                    m_WData[i * 2 + 1] = Tran2(m_wData[i] % 0x10);
                }
                char[] m_write = SendData('d', m_sendAddr, 'w', m_WData);
                if(m_write[0] - 6 != 0)
                {
                    MessageBox.Show("循环写入数据出错!");
                }

                //有排队先完成
                m_First();

                //循环读部分
                circle = true;
                char[] m_read = SendData('d', m_recieveAddr, 'r', m_WData);
                if(m_read.Length/2 == m_recieveLen)
                {
                    for (int i = 0; i < m_read.Length; i = i + 2)
                    {
                        m_rData[i/2] = (byte)(Tran1(m_read[i])*0x10 + Tran1(m_read[i+1]));
                    }
                }
                else
                {
                    MessageBox.Show("循环读出数据出错!");
                }

            }
        }
        #endregion


        #region 优先处理
        private void m_First()
        {
            circle = false;
            for (int i = 0; i < 5; i++)
            {
                if (m_Q[i] && !m_R[i])  //有请求但无回复
                {
                    int m_Data_Len;
                    if (m_C[i] == 'D' || m_C[i] == 'S')
                    {
                        m_Data_Len = 8;
                    }
                    else
                    {
                        m_Data_Len = 4;
                    }
                    char[] m_Data = HTC(m_D[i], m_Data_Len);
                    char[] m_return = SendData(m_T[i], m_A[i], m_C[i], m_Data);

                    int n = m_return.Length;
                    if (n > 1)
                    {
                        m_R_Int[i] = 0;
                        for (int j = n - 1; j > 0; j = j - 2)
                        {
                            m_R_Int[i] *= 0x100;
                            m_R_Int[i] += (Tran1(m_return[j - 1]) * 0x10 + Tran1(m_return[j]));
                        }
                    }
                    else if (n == 1 && m_return[0] - 6 == 0)
                    {
                        m_R_Bool[i] = true;
                    }

                    m_R[i] = true;
                }
            }
        }
        #endregion


        #region  编码转换
        private int Tran1(Char InChar)   //ASCII码转数字,接收时使用
        {
            int OutInt;
            if (InChar < 0x40)
            {
                OutInt = InChar - 0x30;
            }
            else
            {
                OutInt = InChar - 0x37;
            }
            return OutInt;
        }

        private Char Tran2(int InChar)   //数字转ASCII码,发送时使用
        {
            Char OutChar;
            if (InChar < 10)
            {
                OutChar = (Char)(InChar + 0x30);
            }
            else
            {
                OutChar = (Char)(InChar + 0x37);
            }
            return OutChar;
        }
        #endregion


        #region 发送或接收数据,返回Char数组
        private Char[] SendData(Char type, int startAdd, Char cmd, char[] inChar) //(S、D、M、X、Y、T、C)   (E00/1000/100/80/A0/C0/1C0)   (0、1、w/W、r/R)
        {
            Char[] outChar = null;

            //报文长度
            int n = 0;
            if (cmd == '0' || cmd == '1') //  0、1复位置位
            {
                n = 9;
            }
            else if (cmd == 'R' || cmd == 'r') // R/r读单双字
            {
                n = 11;
            }
            else if (cmd == 'w' || cmd == 'W') // w写单字
            {
                n = 11 + inChar.Length;
            }

            char[] subuffer = new char[n];

            //报文首
            subuffer[0] = (char)2;

            //命令代码
            if (cmd == '0')
            {
                subuffer[1] = (char)0x38;
            }
            else if (cmd == '1')
            {
                subuffer[1] = (char)0x37;
            }
            else if (n == 11)
            {
                subuffer[1] = (char)0x30;
            }
            else
            {
                subuffer[1] = (char)0x31;
            }

            //首地址
            int Addr = 0;
            if (type == 'S' || type == 's') // S、s
            {
                Addr = 0xE00;
            }
            else if (type == 'D' || type == 'd') // D、d
            {
                Addr = 0x1000;
            }
            else if (type == 'M' || type == 'm') // M、m
            {
                Addr = 0x100;
            }
            else if (type == 'X' || type == 'x') // X、x
            {
                Addr = 0x80;
            }
            else if (type == 'Y' || type == 'y') // Y、y
            {
                Addr = 0xA0;
            }
            else if (type == 'T' || type == 't') // T、t
            {
                Addr = 0xC0;
            }
            else if (type == 'C' || type == 'c') // C、c
            {
                Addr = 0x1C0;
            }

            //计算首地址
            Char[] Addrs = new Char[4];
            if (n == 9)
            {
                Addr = Addr * 8 + startAdd;
                Addrs = HTC(Addr, 4);
            }
            else
            {
                Addr += (startAdd * 2);
                Addrs = StartData(Addr);
            }
            Addrs.CopyTo(subuffer, 2);

            //字节长度
            if (circle)
            {
                if (cmd == 'R' || cmd == 'W') // R/W  读写双字
                {
                    subuffer[7] = Tran2(m_sendLen % 0x10);
                    subuffer[6] = Tran2 (m_sendLen / 0x10);
                }
                else if (cmd == 'r' || cmd == 'w') // r/w  读写单字
                {
                    subuffer[7] = Tran2(m_recieveLen % 0x10);
                    subuffer[6] = Tran2 (m_recieveLen / 0x10);
                }
            }
            else
            {
                subuffer[6] = (char)0x30;
                if (cmd == 'R' || cmd == 'W') // R/W  读写双字
                {
                    subuffer[7] = (char)0x34;
                }
                else if (cmd == 'r' || cmd == 'w') // r/w  读写单字
                {
                    subuffer[7] = (char)0x32;
                }
            }

            //数据内容
            if (cmd == 'w' || cmd == 'W')
            {
                inChar.CopyTo(subuffer, 8);
            }


            //报文尾
            subuffer[n - 3] = (char)3;

            //校验码            
            Char[] T = new Char[2];
            T = CCD(subuffer, n - 3);
            T.CopyTo(subuffer, n - 2);

            if (m_sp.IsOpen)
            {
                m_sp.Write(subuffer, 0, n);
                //MessageBox.Show("已发送成功!");
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    int Len = m_sp.BytesToRead;
                    if (Len > 0)
                    {
                        i = 5;  //跳出循环
                        char[] RecieveBuf = new char[Len];
                        m_sp.Read(RecieveBuf, 0, Len);

                        if (Len == 1)   //非写入或出错状态
                        {
                            outChar = RecieveBuf;
                        }
                        else   //写入状态,读取返回数据
                        {
                            T = CCD(RecieveBuf, Len - 3); //验证接收信息校验码
                            if (T[0] == RecieveBuf[Len - 2] && T[1] == RecieveBuf[Len - 1])
                            {
                                Char[] outChar2 = new Char[Len - 4];
                                Array.Copy(RecieveBuf, 1,outChar2, 0,  Len - 4);
                                outChar = outChar2;
                            }
                        }
                    }
                }

            }
            return outChar;
        }
        #endregion


        #region 和校验
        private char[] CCD(char[] InChar, int len)    //和校验
        {
            int S = 3;
            for (int i = 1; i < len; i++)
            {
                S += InChar[i];
            }
            char[] OutChar = HTC(S % 0x100, 2);
            return OutChar;
        }
        #endregion


        #region 字元件起始地址转化
        private char[] StartData(int inData)    //字元件起始地址转化
        {
            int t = inData;
            int[] tt = new int[4];
            char[] H = new char[4];
            for (int i = 3; i >= 0; i--)
            {
                tt[i] = t % 0x10;
                t = t / 0x10;
                H[i] = Tran2(tt[i]);
            }
            return H;
        }
        #endregion


        #region 位元件起始地址、发送数据转化
        public char[] HTC(int inData, int inBit)    //位元件起始地址、发送数据转化
        {
            byte[] TranByte = System.BitConverter.GetBytes(inData);
            int len = TranByte.Length;
            if (2 * len > inBit)
            {
                len = inBit / 2;
            }

            char[] OutChar = new char[inBit];
            for (int i = 0; i < len; i++)
            {
                int HL = TranByte[i];
                int H = HL / 0x10;
                OutChar[2 * i] = Tran2(H);

                int L = HL % 0x10;
                OutChar[2 * i + 1] = Tran2(L);
            }

            return OutChar;
        }
        #endregion


        #region 读SD/D
        public int read(string s)
        {
            int outInt = 0;
            if (System.Text.RegularExpressions.Regex.IsMatch(s, @"^[dDsS]d{1,4}$+"))
            {
                Char[] inChar = s.ToCharArray(0, 1);
                Char type = inChar[0],cmd;
                if (type == 'd' || type == 's')
                {
                    cmd = 'r';
                }
                else
                { 
                    cmd = 'R';
                }
                int addr = Convert.ToInt32(s.Substring(1));
                int n = 5;
                for (int i = 0; i < 5; i++)
                {
                    if (!m_Q[i])
                    {
                        n = i;
                        i = 5;
                        m_Q[n] = true;
                        m_T[n] = type;
                        m_A[n] = addr;
                        m_C[n] = cmd;
                        m_R[n] = false;
                        m_R_Bool[n] = false;
                    }
                }

                for (int i = 0; i <= 5; i++)
                {
                    Thread.Sleep(100);
                    if (m_R[n])
                    {
                        m_Q[n] = false;
                        m_R[n] = false;
                        outInt = m_R_Int[n];
                        i = 5;
                    }
                }
            }
            else
            {
                MessageBox.Show("指令格式错误!");
            }
            return outInt;
        }
        #endregion


        #region 写SD/D
        public bool write(string s,int d)
        {
            bool outBool = false;
            if (System.Text.RegularExpressions.Regex.IsMatch(s, @"^[dDsS]d{1,4}$+"))
            {
                Char type = s.ToCharArray(0, 1)[0], cmd;
                if (type == 'd' || type == 's')
                {
                    cmd = 'w';
                }
                else
                {
                    cmd = 'W';
                }
                int addr = Convert.ToInt32(s.Substring(1));
                int n = 5;
                for (int i = 0; i < 5; i++)
                {
                    if (!m_Q[i])
                    {
                        n = i;
                        i = 5;
                        m_Q[n] = true;
                        m_T[n] = type;
                        m_A[n] = addr;
                        m_C[n] = cmd;
                        m_D[n] = d;
                        m_R[n] = false;
                        m_R_Bool[n] = false;
                    }
                }

                for (int i = 0; i <= 5; i++)
                {
                    Thread.Sleep(100);
                    if (m_R[n])
                    {
                        m_Q[n] = false;
                        m_R[n] = false;
                        outBool = m_R_Bool[n];
                        i = 5;
                    }
                }
            }
            else
            {
                MessageBox.Show("指令格式错误!");
            }
            return outBool;
        }
        #endregion


        #region 置位X/Y/M/T/C
        public bool set(string s)
        {
            bool outBool = false;
            if (System.Text.RegularExpressions.Regex.IsMatch(s, @"^[xXyYmMtTcC]d{1,4}$+"))
            {
                Char[] inChar = s.ToCharArray(0, 1);
                Char type = inChar[0];
                int addr = Convert.ToInt32(s.Substring(1));
                int n = 5;
                for (int i = 0; i < 5; i++)
                {
                    if (!m_Q[i])
                    {
                        n = i;
                        i = 5;
                        m_Q[n] = true;
                        m_T[n] = type;
                        m_A[n] = addr;
                        m_C[n] = '1';
                        m_R[n] = false;
                        m_R_Bool[n] = false;
                    }
                }

                for (int i = 0; i <= 5; i++)
                {
                    Thread.Sleep(100);
                    if (m_R[n])
                    {
                        m_Q[n] = false;
                        m_R[n] = false;
                        outBool = m_R_Bool[n];
                        i = 5;
                    }
                }
            }
            else
            {
                MessageBox.Show("指令格式错误!");
            }
            return outBool;
        }
        #endregion


        #region 复位X/Y/M/T/C
        public bool rst(string s)
        {
            bool outBool = false;
            if (System.Text.RegularExpressions.Regex.IsMatch(s, @"^[xXyYmMtTcC]d{1,4}$+"))
            {
                Char[] inChar = s.ToCharArray(0, 1);
                Char type = inChar[0];
                int addr = Convert.ToInt32(s.Substring(1));
                int n = 5;
                for (int i = 0; i < 5; i++)
                {
                    if (!m_Q[i])
                    {
                        n = i;
                        i = 5;
                        m_Q[n] = true;
                        m_T[n] = type;
                        m_A[n] = addr;
                        m_C[n] = '0';
                        m_R[n] = false;
                        m_R_Bool[n] = false;
                    }
                }

                for (int i = 0; i <= 5; i++)
                {
                    Thread.Sleep(100);
                    if (m_R[n])
                    {
                        m_Q[n] = false;
                        m_R[n] = false;
                        outBool = m_R_Bool[n];
                        i = 5;
                    }
                }
            }
            else
            {
                MessageBox.Show("指令格式错误!");
            }
            return outBool;
        }
        #endregion


    }
}
复制代码

在程序中调用封装的类:

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO.Ports;

namespace 三菱PLC读写
{
    public partial class Form1 : Form
    {
        mitsubishi mit = new mitsubishi("COM6",0,10,10,10);
        public Form1()
        {
            InitializeComponent();
            
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
        }



        
        //读
        private void button1_Click(object sender, EventArgs e)
        {
            int result1 = mit.read("D100"); //读D100双字
            int result2 = mit.read("d100"); //读D100单字
        }

        //将100写入到D8340双字
        private void button2_Click_1(object sender, EventArgs e)
        {
            bool result = mit.write("S340", 100); 
        }

        //置位
        private void button3_Click_1(object sender, EventArgs e)
        {
            bool result = mit.set("M0");
        }

        //复位
        private void button4_Click(object sender, EventArgs e)
        {
            bool result = mit.rst("Y0");
        }

        //循环写入D1,D1位置在2、3两个字节
        private void button5_Click(object sender, EventArgs e)
        {
            int sendData = 5678;
            mit.m_wData[2] = (byte)(sendData % 0x100);
            mit.m_wData[3] = (byte)(sendData / 0x100);
        }

        //循环读取D12,D12位置在4、5两个字节
        private void button6_Click(object sender, EventArgs e)
        {
            int revData = mit.m_rData[4] + mit.m_rData[5] * 0x100;
        }

    }
}
复制代码
原文地址:https://www.cnblogs.com/wwwbdabc/p/11677276.html