C#通过MXComponent与三菱PLC通信

news2024/9/20 15:31:13

1,MXComponent安装包与手册。

https://download.csdn.net/download/lingxiao16888/89767137

2,使用管理员权限打开MXComponent,并进行配置。

3,引用相应的类库。

//通信类库
ActUtlTypeLib.dll或者ActProgType.dll
注明:ActUtlTypeLib.dll与ActProgType.dll的区别是:ActUtlTypeLib.dll完全依赖CommunicationSetupUtility软件的配置,只需要通过CommunicationSetupUtility配置中提供的逻辑站号即可实现与PLC的连接。ActProgType.dll需要自行在C#代码中设置通信的方式,目标,物理连接方式等才可实现与PLC的连接。

//错误代码解析库
ActSupportMsgLib.dll
解析返回的代码(代码类型为int)。正常返回0,异常返回非0数字,通过该类库提供的函数解析出该代码的具体意思。

//类型或者控件所在的位置
以上类库均位于MXComponent安装目录的\Act\Control\下,例如:D:\Program Files\MXComponent\Act\Control

4,应用

1,引用相关命令控件,创建相关类。

  ActUtlTypeLib.ActUtlTypeClass PLC = new ActUtlTypeLib.ActUtlTypeClass();
        ActSupportMsgLib.ActMLSupportMsgClass support = new ActSupportMsgLib.ActMLSupportMsgClass();

2,读取PLC CPU信息。

  //获取当前PLC型号信息
                    string cpuName;
                    int cpuCode;
                    result = PLC.GetCpuType(out cpuName, out cpuCode);
                    if (result == 0)
                    {
                        lblCPUModel.Text = cpuName;
                        lblCPUCode.Text = "0x" + cpuCode.ToString("X8");
                        AddLog(0, "已成功获取PLC CPU信息");
                    }
                    else
                    {
                        AddLog(1, "获取PLC CPU信息失败,原因:" + GetErrorMessage(result));
                    }

效果

3,读写PLC当前时钟。

注明:模拟状态不支持时钟写入。

 private void btnReadPLCTime_Click(object sender, EventArgs e)
        {
            short year, month, day, dayOfWeek, hour, minute, second;
            int result = PLC.GetClockData(out year, out month, out day, out dayOfWeek, out hour, out minute, out second);
            if (result == 0)
            {
                lblPLCDateTime.Text = $"PLC时钟:{year}/{month}/{day} {hour}:{minute}:{second} 星期{dayOfWeek}";
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "读取PLC时钟错误,原因:" + msg);
            }

        }
 private void btnWritePLCTime_Click(object sender, EventArgs e)
        {
            //向PLC写入时钟
            DateTime dt = dateTimePicker1.Value;
            int result = PLC.SetClockData((short)dt.Year, (short)dt.Month, (short)dt.Day, (short)dt.DayOfWeek, (short)dt.Hour, (short)dt.Minute, (short)dt.Second);
            if (result == 0)
            {
                AddLog(0, "PLC时钟设置成功!");
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "PLC时钟设置失败,原因:" + msg);
            }
        }

效果:

4,远程控制PLC状态(Run,Stop,Pause)

  private void plcSwitch_Click(object sender, EventArgs e)
        {
            //参数IOperator:0 远程Run;1 远程 Stop;2 远程Pause
            int result = PLC.SetCpuStatus(plcSwitch.CurrentPosition);
            if (result != 0)
            {
                string msg;
                msg = GetErrorMessage(result);
                AddLog(2, "PLC状态切换失败,原因:" + msg);
            }
            else
            {
                switch (plcSwitch.CurrentPosition)
                {
                    case 0:
                        //自动
                        led_PLC.LEDBackColor = Color.Green;
                        break;
                    case 1:
                        //Stop
                        led_PLC.LEDBackColor = Color.Red;
                        break;
                    default:
                        //pause
                        led_PLC.LEDBackColor = Color.Orange;
                        break;
                }
            }
        }

效果:

 5,连续的块数据读取。

   private void btnReadDeviceBlock_Click(object sender, EventArgs e)
        {
            //以4个byte为单位的int块读取
            if (Verification(txt_ReadBlockAddress, txt_ReadBlockSize))
            {
                int num = int.Parse(txt_ReadBlockSize.Text.Trim());
                short[] arr = new short[num];
                int result = PLC.ReadDeviceBlock2(txt_ReadBlockAddress.Text.Trim(), num, out arr[0]);
                if (result == 0)
                {
                    string msg = $"{txt_ReadBlockAddress.Text}连续{num}个地址值为:{string.Join(",", arr)}";
                    AddLog(0, msg);
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, txt_ReadBlockAddress.Text + "块读取失败,原因:" + msg);
                }
            }

        }

        private void btnWriteDeviceBlock_Click(object sender, EventArgs e)
        {
            if (Verification(txt_WriteBlockAddress, txt_WriteBlockValue))
            {


                int num;
                if (!int.TryParse(txt_WriteBlockSize.Text.Trim(), out num))
                {
                    MessageBox.Show("请输入正确的数量!");
                    return;
                }
                int[] arr = txt_WriteBlockValue.Lines.Select(item => Convert.ToInt32(item)).ToArray();
                int result = PLC.WriteDeviceBlock(txt_ReadBlockAddress.Text.Trim(), num, ref arr[0]);
                if (result == 0)
                {
                    string msg = $"从{txt_ReadBlockAddress.Text}开始连续写入{num}个地址值为:{string.Join(",", arr)}";
                    AddLog(0, msg);
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, txt_ReadBlockAddress.Text + "块写入失败,原因:" + msg);
                }
            }
        }
注意事项:使用块连续读写时是以1个word为基准,例如读取数量为1,起始地址为M0的软元件时,返回的是M0-M15的集合;读取数量为1,起始地址为D0的寄存器时返回的时D0。这有别与后面出现的GetDevice()方法。

6,非连续的块数据读写。

 private void btnReadDeviceRandom_Click(object sender, EventArgs e)
        {
            if (Verification(txt_ReadRandomAddress, txt_ReadRandomSize))
            {
                int num;
                if (!int.TryParse(txt_ReadRandomSize.Text.Trim(), out num))
                {
                    MessageBox.Show("只能为正整数");
                    return;

                }
                //对地址进行离散读取,例如一次读取D0,D2,D3,D6等非连续地址
                string[] arr = txt_ReadRandomAddress.Lines;
                short[] values = new short[arr.Length];
                string addres = string.Join("\n", arr);//地址间使用\n进行分割
                //注意这里特意使用ReadDeviceRandom2,而不是ReadDeviceRandom,
                //就是为表示两者除了读取的值,除类型(一个是Int 一个是Short)不同外其他都一样
                int result = PLC.ReadDeviceRandom2(addres, num, out values[0]);
                if (result == 0)
                {
                    //读取成功
                    string[] strs = arr.Where((item, index) => index < num).Select((item, index) => $"{item}={values[index]}").ToArray();
                    AddLog(0, "读取成功:" + string.Join(",", strs));
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "离散读取地址值失败,失败原因:" + msg);
                }
            }
        }

        private void btnWriteDeviceRandom_Click(object sender, EventArgs e)
        {
            if (Verification(txt_WriteRandomAddress, txt_WriteRandomValue))
            {
                string[] address = txt_WriteRandomAddress.Lines;
                int[] values = txt_WriteRandomValue.Lines.Select(item => Convert.ToInt32(item)).ToArray();
                //各地址之间使用\n进行分割
                string addStr = string.Join("\n", address);

                int result = PLC.WriteDeviceRandom(addStr, values.Length, ref values[0]);
                if (result == 0)
                {
                    AddLog(0, "成功写入值。");
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "离散写入失败,失败原因:" + msg);
                }
            }
        }

7,对单个软元件或者寄存器进行读写。

  private void btnGetDevice_Click(object sender, EventArgs e)
        {
            //获取单个寄存器的值
            if (!Regex.IsMatch(txt_ReadDeviceAddress.Text.Trim(), @"^[a-zA-Z]+\d+(\.\d+)?$"))
            {
                MessageBox.Show("地址格式错误!");
                txt_ReadDeviceAddress.Focus();
                return;
            }
            short value;
            int result = PLC.GetDevice2(txt_ReadDeviceAddress.Text.Trim(), out value);
            if (result == 0)
            {
                string msg = $"读取成功,{value}";
                AddLog(0, msg);
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "读取失败,原因:" + msg);
            }

        }

        private void btnSetDevice_Click(object sender, EventArgs e)
        {
            //对单个寄存器进行写入
            if (Verification(txt_WriteDeviceAddress, txt_WriteDeviceValue))
            {
                int value = int.Parse(txt_WriteDeviceValue.Text.Trim());
                int result = PLC.SetDevice(txt_WriteDeviceAddress.Text, value);
                if (result == 0)
                {
                    AddLog(0, "成功写入!");
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "写入失败,原因:" + msg);
                }
            }
        }

8,对缓冲区进行读写。

  private void btnReadBuffer_Click(object sender, EventArgs e)
        {
            //缓冲区地址读取
            int ioNum, num, address;
            if (!int.TryParse(txt_ReadBufferStartIO.Text.Trim(), out ioNum))
            {
                MessageBox.Show("起始地址格式错误");
                return;
            }
            if (!int.TryParse(txt_ReadBufferSize.Text.Trim(), out num))
            {
                MessageBox.Show("数量格式错误");
                return;
            }
            if (!int.TryParse(txt_ReadBufferStartAddress.Text.Trim(), out address))
            {
                MessageBox.Show("地址格式错误,地址只能为数字");
                return;
            }
            short[] values = new short[num];
            int result = PLC.ReadBuffer(ioNum, address, num, out values[0]);
            if (result == 0)
            {
                string msg = $"缓冲区读取成功:{string.Join(",", values)}";
                AddLog(0, msg);
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "缓冲区读取失败,原因:" + msg);
            }

        }

        private void btnWriteBuffer_Click(object sender, EventArgs e)
        {
            //缓冲区地址写入
            int ioNum, address;
            if (!int.TryParse(txt_WriteBufferIO.Text.Trim(), out ioNum))
            {
                MessageBox.Show("起始地址格式错误");
                return;
            }

            if (!int.TryParse(txt_WriteBufferAddress.Text.Trim(), out address))
            {
                MessageBox.Show("地址格式错误,地址只能为数字");
                return;
            }
            if (string.IsNullOrEmpty(txt_WriteBufferValue.Text.Trim()))
            {
                MessageBox.Show("请勿写入空值");
                return;
            }
            foreach (var item in txt_WriteBufferValue.Lines)
            {
                if (!Regex.IsMatch(item, @"^\d+(\r|\n|\r\n)?$"))
                {
                    MessageBox.Show("写入的数据格式错误,写入的数据只能是short.");
                    return;
                }
            }
            short[] values = txt_WriteBufferValue.Lines.Select(item => Convert.ToInt16(item)).ToArray();
            int result = PLC.WriteBuffer(ioNum, address, values.Length, ref values[0]);
            if (result == 0)
            {
                string msg = $"缓冲区成功写入。";
                AddLog(0, msg);
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "缓冲区写入失败,原因:" + msg);
            }
        }

效果

9,软元件登录,解除。

  private void btn_AddEntryDevice_Click(object sender, EventArgs e)
        {
            //软元件之间使用\n进行分割
            if (string.IsNullOrEmpty(txt_EntryDevices.Text.Trim()))
            {
                MessageBox.Show("登录的软元件不能为空");
                return;
            }
            foreach (var item in txt_EntryDevices.Lines)
            {
                if (!Regex.IsMatch(item, @"[a-zA-Z]+\d+(\.\d+)?"))
                {
                    MessageBox.Show("登录的软元件格式错误!");
                    return;
                }
            }
            //周期,单位为秒,范围为1s-1hour超过这个范围将报异常
            int cycle;
            if (!int.TryParse(txt_Cycle.Text, out cycle))
            {
                MessageBox.Show("周期值只能为正正数");
                return;
            }
            //规定需要使用\n进行分割
            string devices = string.Join("\n", txt_EntryDevices.Lines);
            //登录的软元件数量,单次登录的软元件数量不能超过20个。
            int num = txt_EntryDevices.Lines.Length;
            //----------------------------------------
            //登录软元件触发OnDeviceStatus的条件,例如M0,对应的条件设置为1,则只有当M0为1(即ON)时才定时触发该事件
            int[] entryDeviceConditionList = new int[num];
            for (int i = 0; i < txt_EntryDeviceCondition.Lines.Length; i++)
            {
                if (i < num)
                {
                    entryDeviceConditionList[i] = Convert.ToInt32(txt_EntryDeviceCondition.Lines[i]);
                }
               
            }
            int result = PLC.EntryDeviceStatus(devices, num, cycle, ref entryDeviceConditionList[0]);
            if (result == 0)
            {
                AddLog(0, "软元件登录成功");
                foreach (var item in txt_EntryDevices.Lines)
                {
                    lst_EntryDevice.Items.Add(item);
                }
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, $"软元件登录失败,原因:{msg}");
            }
        }

        private void btn_RemoveEntryDevice_Click(object sender, EventArgs e)
        {
           int result=   PLC.FreeDeviceStatus();
            if (result == 0)
            {
                AddLog(0, "软元件释放成功");
                lst_EntryDevice.Items.Clear();
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, $"软元件释放失败,原因:{msg}");
            }
        }

10,项目编译注意事项

如果出现编译异常,提示需要注册等信息,请将项目属性->生成->目标平台 设置为x86,再重新编译。

5,Demo代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace Demo
{
    public partial class Form1 : Form
    {
        ActUtlTypeLib.ActUtlTypeClass PLC = new ActUtlTypeLib.ActUtlTypeClass();
        ActSupportMsgLib.ActMLSupportMsgClass support = new ActSupportMsgLib.ActMLSupportMsgClass();
        public Form1()
        {
            InitializeComponent();
            AddLog(0, "应用启动!");
            groupBox1.Enabled = false;
            groupBox2.Enabled = false;
            groupBox3.Enabled = false;
            PLC.OnDeviceStatus += PLC_OnDeviceStatus;
        }
        private void PLC_OnDeviceStatus(string szDevice, int lData, int lReturnCode)
        {
            //登录软元件的所触发的事件
            if (lReturnCode == 0)
            {
                AddLog(0, $"登录的软元件:{szDevice}={lData}");
            }
            else
            {
                string msg = GetErrorMessage(lReturnCode);
                AddLog(2, $"登录的软元件异常,原因:{msg}");
            }
        }
        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txt_Station.Text.Trim()))
            {
                MessageBox.Show("逻辑站点不能为空");
                return;
            }
            int stationNum;
            if (int.TryParse(txt_Station.Text.Trim(), out stationNum))
            {
                if (stationNum < 0)
                {
                    MessageBox.Show("逻辑站点必须为正数");
                    return;
                }
            }
            else
            {
                MessageBox.Show("逻辑站点必须为正数");
                return;
            }
            if (btnConnect.Text.Equals("连接"))
            {
                PLC.ActLogicalStationNumber = stationNum;
                PLC.ActPassword = txt_Pwd.Text.Trim();
                int result = PLC.Open();
                if (result == 0)
                {
                    AddLog(0, "PLC已成功连接!");
                    btnConnect.Text = "断开";
                    btnConnect.BackColor = Color.Green;
                    groupBox1.Enabled = true;
                    groupBox2.Enabled = true;
                    groupBox3.Enabled = true;
                    //获取当前PLC型号信息
                    string cpuName;
                    int cpuCode;
                    result = PLC.GetCpuType(out cpuName, out cpuCode);
                    if (result == 0)
                    {
                        lblCPUModel.Text = cpuName;
                        lblCPUCode.Text = "0x" + cpuCode.ToString("X8");
                        AddLog(0, "已成功获取PLC CPU信息");
                    }
                    else
                    {
                        AddLog(1, "获取PLC CPU信息失败,原因:" + GetErrorMessage(result));
                    }
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "PLC 连接失败!原因:" + msg);
                }
            }
            else
            {
                int result = PLC.Close();
                if (result == 0)
                {
                    lblCPUCode.Text = "";
                    lblCPUModel.Text = "";
                    lblPLCDateTime.Text = "";
                    groupBox1.Enabled = false;
                    groupBox2.Enabled = false;
                    groupBox3.Enabled = false;
                    AddLog(0, "PLC已断开连接");
                    btnConnect.Text = "连接";
                    btnConnect.BackColor = Color.DarkKhaki;
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "PLC 断开连接失败!原因:" + msg);
                }
            }
        }
        private void btnReadPLCTime_Click(object sender, EventArgs e)
        {
            short year, month, day, dayOfWeek, hour, minute, second;
            int result = PLC.GetClockData(out year, out month, out day, out dayOfWeek, out hour, out minute, out second);
            if (result == 0)
            {
                lblPLCDateTime.Text = $"PLC时钟:{year}/{month}/{day} {hour}:{minute}:{second} 星期{dayOfWeek}";
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "读取PLC时钟错误,原因:" + msg);
            }
        }
        private void plcSwitch_Click(object sender, EventArgs e)
        {
            //参数IOperator:0 远程Run;1 远程 Stop;2 远程Pause
            int result = PLC.SetCpuStatus(plcSwitch.CurrentPosition);
            if (result != 0)
            {
                string msg;
                msg = GetErrorMessage(result);
                AddLog(2, "PLC状态切换失败,原因:" + msg);
            }
            else
            {
                switch (plcSwitch.CurrentPosition)
                {
                    case 0:
                        //自动
                        led_PLC.LEDBackColor = Color.Green;
                        break;
                    case 1:
                        //Stop
                        led_PLC.LEDBackColor = Color.Red;
                        break;
                    default:
                        //pause
                        led_PLC.LEDBackColor = Color.Orange;
                        break;
                }
            }
        }
        private void btnWritePLCTime_Click(object sender, EventArgs e)
        {
            //向PLC写入时钟
            DateTime dt = dateTimePicker1.Value;
            int result = PLC.SetClockData((short)dt.Year, (short)dt.Month, (short)dt.Day, (short)dt.DayOfWeek, (short)dt.Hour, (short)dt.Minute, (short)dt.Second);
            if (result == 0)
            {
                AddLog(0, "PLC时钟设置成功!");
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "PLC时钟设置失败,原因:" + msg);
            }
        }
        /// <summary>
        /// 根据错误代码获取错误信息
        /// </summary>
        /// <param name="errorCode"></param>
        /// <returns></returns>
        string GetErrorMessage(int errorCode)
        {
            object str;
            support.GetErrorMessage(errorCode, out str);
            if (str != null)
            {
                return System.Text.RegularExpressions.Regex.Replace(str.ToString(), @"\r|\n", "");
            }
            return "";
        }
        void AddLog(int level, string msg)
        {
            ListViewItem item = new ListViewItem();
            item.ImageIndex = level;
            item.SubItems.Add(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
            item.SubItems.Add(msg);
            listView1.Items.Add(item);
            listView1.EnsureVisible(listView1.Items.Count - 1);
        }
        private void btnReadDeviceBlock_Click(object sender, EventArgs e)
        {
            //以4个byte为单位的int块读取
            if (Verification(txt_ReadBlockAddress, txt_ReadBlockSize))
            {
                int num = int.Parse(txt_ReadBlockSize.Text.Trim());
                short[] arr = new short[num];
                int result = PLC.ReadDeviceBlock2(txt_ReadBlockAddress.Text.Trim(), num, out arr[0]);
                if (result == 0)
                {
                    string msg = $"{txt_ReadBlockAddress.Text}连续{num}个地址值为:{string.Join(",", arr)}";
                    AddLog(0, msg);
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, txt_ReadBlockAddress.Text + "块读取失败,原因:" + msg);
                }
            }
        }
        private void btnWriteDeviceBlock_Click(object sender, EventArgs e)
        {
            if (Verification(txt_WriteBlockAddress, txt_WriteBlockValue))
            {
                int num;
                if (!int.TryParse(txt_WriteBlockSize.Text.Trim(), out num))
                {
                    MessageBox.Show("请输入正确的数量!");
                    return;
                }
                int[] arr = txt_WriteBlockValue.Lines.Select(item => Convert.ToInt32(item)).ToArray();
                int result = PLC.WriteDeviceBlock(txt_ReadBlockAddress.Text.Trim(), num, ref arr[0]);
                if (result == 0)
                {
                    string msg = $"从{txt_ReadBlockAddress.Text}开始连续写入{num}个地址值为:{string.Join(",", arr)}";
                    AddLog(0, msg);
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, txt_ReadBlockAddress.Text + "块写入失败,原因:" + msg);
                }
            }
        }
        bool Verification(TextBox tb01, TextBox tb02)
        {
            //第一个必须为有效的PLC地址,第一个必须为数字
            if (string.IsNullOrEmpty(tb01.Text.Trim()))
            {
                MessageBox.Show("不能为空!");
                tb01.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(tb02.Text.Trim()))
            {
                MessageBox.Show("不能为空!");
                tb02.Focus();
                return false;
            }
            foreach (var item in tb01.Lines)
            {
                if (!Regex.IsMatch(item, @"^[a-zA-Z]+\d+(\.\d+)?(\r|\n|\r\n)?$"))
                {
                    MessageBox.Show("地址格式错误!");
                    tb01.Focus();
                    return false;
                }
            }
            foreach (var item in tb02.Lines)
            {
                double val;
                if (!double.TryParse(item, out val))
                {
                    MessageBox.Show("数据格式错误!");
                    tb02.Focus();
                    return false;
                }
            }
            return true;
        }
        private void btnReadDeviceRandom_Click(object sender, EventArgs e)
        {
            if (Verification(txt_ReadRandomAddress, txt_ReadRandomSize))
            {
                int num;
                if (!int.TryParse(txt_ReadRandomSize.Text.Trim(), out num))
                {
                    MessageBox.Show("只能为正整数");
                    return;
                }
                //对地址进行离散读取,例如一次读取D0,D2,D3,D6等非连续地址
                string[] arr = txt_ReadRandomAddress.Lines;
                short[] values = new short[arr.Length];
                string addres = string.Join("\n", arr);//地址间使用\n进行分割
                //注意这里特意使用ReadDeviceRandom2,而不是ReadDeviceRandom,
                //就是为表示两者除了读取的值,除类型(一个是Int 一个是Short)不同外其他都一样
                int result = PLC.ReadDeviceRandom2(addres, num, out values[0]);
                if (result == 0)
                {
                    //读取成功
                    string[] strs = arr.Where((item, index) => index < num).Select((item, index) => $"{item}={values[index]}").ToArray();
                    AddLog(0, "读取成功:" + string.Join(",", strs));
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "离散读取地址值失败,失败原因:" + msg);
                }
            }
        }
        private void btnWriteDeviceRandom_Click(object sender, EventArgs e)
        {
            if (Verification(txt_WriteRandomAddress, txt_WriteRandomValue))
            {
                string[] address = txt_WriteRandomAddress.Lines;
                int[] values = txt_WriteRandomValue.Lines.Select(item => Convert.ToInt32(item)).ToArray();
                //各地址之间使用\n进行分割
                string addStr = string.Join("\n", address);
                int result = PLC.WriteDeviceRandom(addStr, values.Length, ref values[0]);
                if (result == 0)
                {
                    AddLog(0, "成功写入值。");
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "离散写入失败,失败原因:" + msg);
                }
            }
        }
        private void btnGetDevice_Click(object sender, EventArgs e)
        {
            //获取单个寄存器的值
            if (!Regex.IsMatch(txt_ReadDeviceAddress.Text.Trim(), @"^[a-zA-Z]+\d+(\.\d+)?$"))
            {
                MessageBox.Show("地址格式错误!");
                txt_ReadDeviceAddress.Focus();
                return;
            }
            short value;
            int result = PLC.GetDevice2(txt_ReadDeviceAddress.Text.Trim(), out value);
            if (result == 0)
            {
                string msg = $"读取成功,{value}";
                AddLog(0, msg);
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "读取失败,原因:" + msg);
            }
        }
        private void btnSetDevice_Click(object sender, EventArgs e)
        {
            //对单个寄存器进行写入
            if (Verification(txt_WriteDeviceAddress, txt_WriteDeviceValue))
            {
                int value = int.Parse(txt_WriteDeviceValue.Text.Trim());
                int result = PLC.SetDevice(txt_WriteDeviceAddress.Text, value);
                if (result == 0)
                {
                    AddLog(0, "成功写入!");
                }
                else
                {
                    string msg = GetErrorMessage(result);
                    AddLog(2, "写入失败,原因:" + msg);
                }
            }
        }
        private void btnReadBuffer_Click(object sender, EventArgs e)
        {
            //缓冲区地址读取
            int ioNum, num, address;
            if (!int.TryParse(txt_ReadBufferStartIO.Text.Trim(), out ioNum))
            {
                MessageBox.Show("起始地址格式错误");
                return;
            }
            if (!int.TryParse(txt_ReadBufferSize.Text.Trim(), out num))
            {
                MessageBox.Show("数量格式错误");
                return;
            }
            if (!int.TryParse(txt_ReadBufferStartAddress.Text.Trim(), out address))
            {
                MessageBox.Show("地址格式错误,地址只能为数字");
                return;
            }
            short[] values = new short[num];
            int result = PLC.ReadBuffer(ioNum, address, num, out values[0]);
            if (result == 0)
            {
                string msg = $"缓冲区读取成功:{string.Join(",", values)}";
                AddLog(0, msg);
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "缓冲区读取失败,原因:" + msg);
            }
        }
        private void btnWriteBuffer_Click(object sender, EventArgs e)
        {
            //缓冲区地址写入
            int ioNum, address;
            if (!int.TryParse(txt_WriteBufferIO.Text.Trim(), out ioNum))
            {
                MessageBox.Show("起始地址格式错误");
                return;
            }
            if (!int.TryParse(txt_WriteBufferAddress.Text.Trim(), out address))
            {
                MessageBox.Show("地址格式错误,地址只能为数字");
                return;
            }
            if (string.IsNullOrEmpty(txt_WriteBufferValue.Text.Trim()))
            {
                MessageBox.Show("请勿写入空值");
                return;
            }
            foreach (var item in txt_WriteBufferValue.Lines)
            {
                if (!Regex.IsMatch(item, @"^\d+(\r|\n|\r\n)?$"))
                {
                    MessageBox.Show("写入的数据格式错误,写入的数据只能是short.");
                    return;
                }
            }
            short[] values = txt_WriteBufferValue.Lines.Select(item => Convert.ToInt16(item)).ToArray();
            int result = PLC.WriteBuffer(ioNum, address, values.Length, ref values[0]);
            if (result == 0)
            {
                string msg = $"缓冲区成功写入。";
                AddLog(0, msg);
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, "缓冲区写入失败,原因:" + msg);
            }
        }
        private void btn_AddEntryDevice_Click(object sender, EventArgs e)
        {
            //软元件之间使用\n进行分割
            if (string.IsNullOrEmpty(txt_EntryDevices.Text.Trim()))
            {
                MessageBox.Show("登录的软元件不能为空");
                return;
            }
            foreach (var item in txt_EntryDevices.Lines)
            {
                if (!Regex.IsMatch(item, @"[a-zA-Z]+\d+(\.\d+)?"))
                {
                    MessageBox.Show("登录的软元件格式错误!");
                    return;
                }
            }
            //周期,单位为秒,范围为1s-1hour超过这个范围将报异常
            int cycle;
            if (!int.TryParse(txt_Cycle.Text, out cycle))
            {
                MessageBox.Show("周期值只能为正正数");
                return;
            }
            //规定需要使用\n进行分割
            string devices = string.Join("\n", txt_EntryDevices.Lines);
            //登录的软元件数量,单次登录的软元件数量不能超过20个。
            int num = txt_EntryDevices.Lines.Length;
            //----------------------------------------
            //登录软元件触发OnDeviceStatus的条件,例如M0,对应的条件设置为1,则只有当M0为1(即ON)时才定时触发该事件
            int[] entryDeviceConditionList = new int[num];
            for (int i = 0; i < txt_EntryDeviceCondition.Lines.Length; i++)
            {
                if (i < num)
                {
                    entryDeviceConditionList[i] = Convert.ToInt32(txt_EntryDeviceCondition.Lines[i]);
                }
            }
            int result = PLC.EntryDeviceStatus(devices, num, cycle, ref entryDeviceConditionList[0]);
            if (result == 0)
            {
                AddLog(0, "软元件登录成功");
                foreach (var item in txt_EntryDevices.Lines)
                {
                    lst_EntryDevice.Items.Add(item);
                }
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, $"软元件登录失败,原因:{msg}");
            }
        }
        private void btn_RemoveEntryDevice_Click(object sender, EventArgs e)
        {
           int result=   PLC.FreeDeviceStatus();
            if (result == 0)
            {
                AddLog(0, "软元件释放成功");
                lst_EntryDevice.Items.Clear();
            }
            else
            {
                string msg = GetErrorMessage(result);
                AddLog(2, $"软元件释放失败,原因:{msg}");
            }
        }
    }
}

6,Demo链接。

https://download.csdn.net/download/lingxiao16888/89767457

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2145640.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Excel常用函数大全

Excel常用函数介绍与示例应用 在Excel中&#xff0c;函数是进行数据处理和分析的强大工具。对于新手来说&#xff0c;掌握一些基本的函数使用方法能够大大提升工作效率。以下是一份通俗易懂、适合新手的Excel函数使用方法总结&#xff1a; 1. 求和函数&#xff08;SUM&#x…

leetcode75-9 压缩字符串 双指针原地算

题目太复杂了 没做出来 计算过程大概是双指针处理数组&#xff0c; 其中两个知识点一个是length 字符数组直接加 不用加括号 还有就是数字转字符需要转换 数字转换成字符 不能直接转换&#xff01; 需借助数字转字符串&#xff0c; 首先将数字转为字符串&#xff0c;…

C++---类与对象一

类的定义 class className{//成员字段//成员函数 };class定义类的关键字&#xff0c;className是自己决定的类名&#xff0c;{ } 为类的主体&#xff0c;花括号里是类的内容。类的内容大致分为类的成员属性&#xff08;变量&#xff09;和类的成员函数。注意定义类后面需要跟;…

SpringBoot - 基于 Java的超市进销存系统

专业团队&#xff0c;咨询就送开题报告&#xff0c;欢迎大家私信&#xff0c;留言&#xff0c;联系方式在文章底部 摘 要 随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;超市进销存系统也不例外&#xff0c;但目前国内仍都使用人工管理&#xf…

【JUC】17-Synchronized锁升级

1. 锁分类 无锁->偏向锁->轻量级锁->重量级锁 synchronized属于重量级锁&#xff0c;monitor是基于底层os的mutex Lock实现了&#xff0c;挂起线程和恢复线程都需要内核态完成&#xff0c;都需要切换CPU状态来完成。 Monitor与对象以及线程如何关联&#xff1f;  1…

OV-DINO:统一开放词汇检测与语言感知选择性融合

文章目录 摘要1、引言2、相关工作3、方法3.1、概述3.2、统一数据集成3.3、语言感知选择性融合3.4、以检测为中心的预训练 4、实验4.1、预训练数据和评估指标4.2、实施细节4.3、主要结果4.4、消融研究4.5、定性结果 5 、讨论 摘要 开放词汇检测&#xff08;Open-vocabulary Det…

滑动窗口(6)_找到字符串中所有字母异位词

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 滑动窗口(6)_找到字符串中所有字母异位词 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f4…

《SmartX ELF 虚拟化核心功能集》发布,详解 80+ 功能特性和 6 例金融实践

《SmartX ELF 虚拟化核心功能集》电子书现已发布&#xff01;本书详细介绍了 SmartX ELF 虚拟化及云平台核心功能&#xff0c;包含虚机服务、容器服务、网络服务、存储服务、运维管理、工具服务、数据保护等各个方面。 即刻下载电子书&#xff0c;了解如何利用基于 SmartX ELF …

助力电商升级,智象未来(HiDream.ai)开启未来商业新篇章

近日&#xff0c;智象未来&#xff08;HiDream.ai&#xff09;凭借其创新性的“秩象™大模型”&#xff0c;在业界掀起了一场跨行业的创意革命&#xff0c;对视觉设计、运营商服务、品牌营销以及文旅传媒等领域的创新发展产生了深远影响。致力于全球领先的多模态生成式人工智能…

neo4j节点关联路径的表示、节点的增删改查

目录 核心概念节点的增删改查&#xff08;1&#xff09;增&#xff08;2&#xff09;查&#xff08;3&#xff09;删&#xff08;4&#xff09;改 neo4j文档&#xff1a;https://neo4j.com/docs/ https://neo4j.com/docs/cypher-manual/current/introduction/ 核心概念 节点 ne…

【从计算机的发展角度理解编程语言】C、CPP、Java、Python,是偶然还是应时代的产物?

参考目录 前言什么是"computer"?计算机的大致发展历程计算机系统结构阶段(1946~1981)计算机网络和视窗阶段(1982~2007)复杂信息系统阶段(2008~today)人工智能阶段 越新的语言是越好的吗、越值得学习吗&#xff1f; 前言 最近读了 《Python语言程序设计基础》 这本书…

Linux运维篇-服务器简介

目录 前言服务器分类&#xff08;按服务器的机箱结构来划分&#xff09;台式服务器机架式服务器刀片式服务器 外观部件内部结构前面板前面板组件前面板接口说明前面板指示灯和按钮前面板指示灯/按钮说明 后面板后面板组件后面板接口说明后面板指示灯后面板指示灯说明 主板和 iB…

C#|.net core 基础 - 值传递 vs 引用传递

不知道你在开发过程中有没有遇到过这样的困惑&#xff1a;这个变量怎么值被改&#xff1f;这个值怎么没变&#xff1f; 今天就来和大家分享可能导致这个问题的根本原因值传递 vs 引用传递。 在此之前我们先回顾两组基本概念&#xff1a; 值类型** vs 引用类型** **值类型&a…

适合金融行业的银行级别FTP替代升级方案

在数字化办公日益普及的今天&#xff0c;金融领域对数据传输的需求日益增长&#xff0c;场景也变得更加多样化和复杂。这不仅包括内部协作&#xff0c;还涉及金融服务、外部合作以及跨境数据流动等方面。因此&#xff0c;金融行业对数据传输系统的要求越来越高&#xff0c;传统…

LeetCode 算法笔记-第 04 章 基础算法篇

1.枚举 采用枚举算法解题的一般思路如下&#xff1a; 确定枚举对象、枚举范围和判断条件&#xff0c;并判断条件设立的正确性。一一枚举可能的情况&#xff0c;并验证是否是问题的解。考虑提高枚举算法的效率。 我们可以从下面几个方面考虑提高算法的效率&#xff1a; 抓住…

孙怡带你深度学习(3)--损失函数

文章目录 损失函数一、L1Loss损失函数1. 定义2. 优缺点3. 应用 二、NLLLoss损失函数1. 定义与原理2. 优点与注意3. 应用 三、MSELoss损失函数1. 定义与原理2. 优点与注意3. 应用 四、BCELoss损失函数1. 定义与原理2. 优点与注意3. 应用 五、CrossEntropyLoss损失函数1. 定义与原…

『 Linux 』HTTP(一)

文章目录 域名URLURLEncode和URLDecodeHTTP的请求HTTP的响应请求与响应的获取简单的Web服务器 域名 任何客户端在需要访问一个服务端时都需要一个IP和端口号,而当一个浏览器去访问一个网页时通常更多使用的是域名而不是IP:port的方式, www.baidu.com这是百度的域名; 实际上当浏…

数据结构和算法|排序算法系列(五)|排序总结(时间复杂度和是否稳定)

文章目录 选择排序冒泡排序插入排序快排归并排序堆排序 选择排序 一句话总结&#xff0c;开启一个循环&#xff0c;每轮从未排序区间选择****最小的元素&#xff0c;将其放到已排序区间的末尾。「未排序区间一般也放在后面&#xff0c;已排序区间放在前面」 选择排序 时间复…

2024蓝桥杯省B好题分析

题解来自洛谷&#xff0c;作为学习 目录 宝石组合 数字接龙 爬山 拔河 宝石组合 # [蓝桥杯 2024 省 B] 宝石组合## 题目描述在一个神秘的森林里&#xff0c;住着一个小精灵名叫小蓝。有一天&#xff0c;他偶然发现了一个隐藏在树洞里的宝藏&#xff0c;里面装满了闪烁着美…

Flutter Android Package调用python

操作步骤 一、创建一个Flutter Package 使用以下指令创建一个Flutter Package flutter create --templateplugin --platformsandroid,ios -a java flutter_package_python 二、修改android/build.gradle文件 在buildscript——>dependencies中添加以下内容 //导入Chaqu…