• 三菱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;
            }
    
        }
    }
    复制代码
  • 相关阅读:
    总结第一、二类斯特林数(模板)
    总结组合数的几种求法(模板)
    HDU5521 Meeting(dijkstra+巧妙建图)
    BZOJ4152 The Captain(dijkstra+巧妙建图)
    CF1194D 1-2-K Game (博弈论)
    JavaScript字符串的操作
    JavaScript基础–闭包
    JavsScript基础–声明提升
    JavaScript基础–作用域
    css基础(一)
  • 原文地址:https://www.cnblogs.com/wwwbdabc/p/11677276.html
Copyright © 2020-2023  润新知