using MainForm.ClassFile; using ModBusClientSimple.Util; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace MainForm.FaForm { public partial class Form_PLCDB_ShowInfo : Form { #region ModbusTCP ModbusClientHelper plc1 = new ModbusClientHelper(GlobalContext.Machine1Address, GlobalContext.MachinePort, 499); #endregion ModbusTCP #region 变量 /// /// 展示的工位名称 /// private string _StationName; /// /// 记录信息方法的载体窗体 /// private Form_PLCDB _Form_PLCDB; /// /// “工位可调试点位预览表.xlsx”文件的地址 /// private string filePath = AppDomain.CurrentDomain.BaseDirectory + "\\DBFile\\工位可调试点位预览表.xlsx"; private DataTable dt; #endregion 变量 #region 单例 private static Form_PLCDB_ShowInfo _Form_PLCDB_ShowInfo; public static Form_PLCDB_ShowInfo Singleton(string stationName, Form_PLCDB form_PLCDB) { if (_Form_PLCDB_ShowInfo == null) { _Form_PLCDB_ShowInfo = new Form_PLCDB_ShowInfo(); } _Form_PLCDB_ShowInfo._StationName = stationName; _Form_PLCDB_ShowInfo._Form_PLCDB = form_PLCDB; _Form_PLCDB_ShowInfo.OnLoadData(); // 加载点位数据 return _Form_PLCDB_ShowInfo; } #endregion 单例 #region 窗体事件 public Form_PLCDB_ShowInfo() { InitializeComponent(); } private void Form_PLCDB_ShowInfo_Load(object sender, EventArgs e) { try { this.Text = string.Concat(_StationName, " 工位DB详情"); // dgv_S0 dgv_DBInfo.ColumnHeadersDefaultCellStyle.BackColor = Color.WhiteSmoke; dgv_DBInfo.ColumnHeadersDefaultCellStyle.ForeColor = Color.Black; dgv_DBInfo.RectColor = Color.Gainsboro; dgv_DBInfo.GridColor = Color.Gainsboro; dgv_DBInfo.BackgroundColor = Color.White; } catch (Exception ex) { string str = ex.StackTrace; MessageBox.Show("PLC交互工位DB详情页面初始化出错!异常信息:" + ex.Message); _Form_PLCDB.AddMessage(LogType.Error, "PLC交互工位DB详情页面初始化出错!异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1) + ";异常信息:" + ex.Message.ToString()); } } private void Form_PLCDB_ShowInfo_VisibleChanged(object sender, EventArgs e) { if (!this.IsDisposed && this.Visible) { SBtn_GetDBValue_LoopStart.Enabled = true; SBtn_GetDBValue_LoopStop.Enabled = false; } else if (!this.IsDisposed && !this.Visible) { if (cts != null) { cts.Cancel(); } SBtn_GetDBValue_LoopStart.Enabled = true; SBtn_GetDBValue_LoopStop.Enabled = false; } } #endregion 窗体事件 #region 方法 /// /// dgv加载数据 /// private void OnLoadData() { try { if (!File.Exists(filePath)) { MessageBox.Show($"‘{filePath}’文件不存在!未读到调试点位数据", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } dt = NPOIHelper.ReadExcel(filePath); if (dt != null && dt.Rows.Count > 0) { dt.Rows.RemoveAt(0); for (int i = 0; i < dt.Rows.Count; i++) { if (dt.Rows[i][1] == DBNull.Value || !dt.Rows[i][1].ToString().Trim().Equals(_StationName)) { dt.Rows.RemoveAt(i); i--; } } dgv_DBInfo.DataSource = dt.DefaultView; } else { dgv_DBInfo.DataSource = new DataTable().DefaultView; MessageBox.Show($"‘{filePath}’文件未包含任何需要读取的数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); } } catch (Exception ex) { string str = ex.StackTrace; MessageBox.Show("PLC交互工位DB详情页面表格加载数据出错!异常信息:" + ex.Message); _Form_PLCDB.AddMessage(LogType.Error, "PLC交互工位DB详情页面表格加载数据出错!异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1) + ";异常信息:" + ex.Message.ToString()); } } #endregion 方法 // 刷新当前值 private void SBtn_GetDBValue_One_Click(object sender, EventArgs e) { try { if (dt == null) { return; } if (!plc1.IsConnected) { plc1.Connect(); } int rowNum = 0; foreach (DataRow row in dt.Rows) { if (row[5] != DBNull.Value && row[4] != DBNull.Value && !string.IsNullOrEmpty(row[5].ToString()) && !string.IsNullOrEmpty(row[4].ToString())) { string value = string.Empty; string plcType = row[4].ToString(); int plcAddress = Convert.ToInt32(row[5].ToString()); switch (plcType) { case "Bool": value = (plc1.ReadHoldingRegisters(plcAddress, 1).FirstOrDefault() == 1).ToString(); // 读取 break; case "Int16": value = plc1.ReadHoldingRegisters(plcAddress).ToString(); // 读取 break; case "Int32": value = plc1.ReadHoldingRegisters(plcAddress).ToString(); // 读取 break; case "String<32>": value = plc1.ReadHoldingRegisters(plcAddress, 32, 32).ToString(); // 读取 break; case "Float": value = plc1.ReadHoldingRegisters(plcAddress).ToString(); // 读取 break; case "Bype<3>": // 日期yyyyMMdd;yyyy、MM、dd共占用3个地址位 string plcDate_Y = plc1.ReadHoldingRegisters(plcAddress, 1).FirstOrDefault().ToString("0000"); // 产品序列号的 当前日期_年 string plcDate_M = plc1.ReadHoldingRegisters(plcAddress + 1, 1).FirstOrDefault().ToString("00"); // 产品序列号的 当前日期_月 string plcDate_D = plc1.ReadHoldingRegisters(plcAddress + 2, 1).FirstOrDefault().ToString("00"); // 产品序列号的 当前日期_日 value = string.Concat(plcDate_Y, plcDate_M, plcDate_D); // 产品序列号的 当前日期 break; default: break; } dgv_DBInfo.Rows[rowNum].Cells[9].Value = value; } rowNum++; } } catch (Exception ex) { string str = ex.StackTrace; MessageBox.Show("PLC交互工位DB详情页面刷新当前值出错!异常信息:" + ex.Message); _Form_PLCDB.AddMessage(LogType.Error, "PLC交互工位DB详情页面刷新当前值出错!异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1) + ";异常信息:" + ex.Message.ToString()); } } #region 循环刷新 /// /// 循环线程结束标志 /// private CancellationTokenSource cts; /// /// 循环刷新当前值 /// private async void SBtn_GetDBValue_LoopStart_Click(object sender, EventArgs e) { cts = new CancellationTokenSource(); SBtn_GetDBValue_LoopStart.Enabled = false; SBtn_GetDBValue_LoopStop.Enabled = true; await Task.Run(() => ThreadCode(cts.Token)); } /// /// 停止循环刷新当前值 /// private void SBtn_GetDBValue_LoopStop_Click(object sender, EventArgs e) { cts.Cancel(); SBtn_GetDBValue_LoopStop.Enabled = false; SBtn_GetDBValue_LoopStart.Enabled = true; } /// /// /// /// private void ThreadCode(CancellationToken token) { while (!token.IsCancellationRequested) { try { if (dt == null) { return; } if (!plc1.IsConnected) { plc1.Connect(); } int rowNum = 0; foreach (DataRow row in dt.Rows) { if (row[5] != DBNull.Value && row[4] != DBNull.Value && !string.IsNullOrEmpty(row[5].ToString()) && !string.IsNullOrEmpty(row[4].ToString())) { string value = string.Empty; string plcType = row[4].ToString(); int plcAddress = Convert.ToInt32(row[5].ToString()); switch (plcType) { case "Bool": value = (plc1.ReadHoldingRegisters(plcAddress, 1).FirstOrDefault() == 1).ToString(); // 读取 break; case "Int16": value = plc1.ReadHoldingRegisters(plcAddress).ToString(); // 读取 break; case "Int32": value = plc1.ReadHoldingRegisters(plcAddress).ToString(); // 读取 break; case "String<32>": value = plc1.ReadHoldingRegisters(plcAddress, 32, 32).ToString(); // 读取 break; case "Float": value = plc1.ReadHoldingRegisters(plcAddress).ToString(); // 读取 break; case "Bype<3>": // 日期yyyyMMdd;yyyy、MM、dd共占用3个地址位 string plcDate_Y = plc1.ReadHoldingRegisters(plcAddress, 1).FirstOrDefault().ToString("0000"); // 产品序列号的 当前日期_年 string plcDate_M = plc1.ReadHoldingRegisters(plcAddress + 1, 1).FirstOrDefault().ToString("00"); // 产品序列号的 当前日期_月 string plcDate_D = plc1.ReadHoldingRegisters(plcAddress + 2, 1).FirstOrDefault().ToString("00"); // 产品序列号的 当前日期_日 value = string.Concat(plcDate_Y, plcDate_M, plcDate_D); // 产品序列号的 当前日期 break; default: break; } dgv_DBInfo.Invoke(new Action(() => { dgv_DBInfo.Rows[rowNum].Cells[9].Value = value; })); } rowNum++; } } catch (Exception ex) { string str = ex.StackTrace; MessageBox.Show("PLC交互工位DB详情页面循环刷新当前值出错!异常信息:" + ex.Message); cts.Cancel(); this.Invoke(new Action(() => { SBtn_GetDBValue_LoopStart.Enabled = true; SBtn_GetDBValue_LoopStop.Enabled = false; })); _Form_PLCDB.AddMessage(LogType.Error, "PLC交互工位DB详情页面循环刷新当前值出错!异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1) + ";异常信息:" + ex.Message.ToString()); } Thread.Sleep(1000); // 等待 } } #endregion 循环刷新 /// /// 写入 /// private void 写入ToolStripMenuItem_Click(object sender, EventArgs e) { try { int selectedRowIndex = dgv_DBInfo.SelectedIndex; if (selectedRowIndex < 0 || selectedRowIndex > dgv_DBInfo.RowCount - 1) { MessageBox.Show("请先选择要写入的‘当前值’单元格", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } if (!plc1.IsConnected) { plc1.Connect(); } if (dgv_DBInfo.Rows[selectedRowIndex].Cells[5].Value != DBNull.Value && dgv_DBInfo.Rows[selectedRowIndex].Cells[4].Value != DBNull.Value && !string.IsNullOrEmpty(dgv_DBInfo.Rows[selectedRowIndex].Cells[5].ToString()) && !string.IsNullOrEmpty(dgv_DBInfo.Rows[selectedRowIndex].Cells[4].ToString())) { string plcVName = dgv_DBInfo.Rows[selectedRowIndex].Cells[3].Value?.ToString(); // DB点位的变量名称 string plcType = dgv_DBInfo.Rows[selectedRowIndex].Cells[4].Value.ToString(); // DB点位的类型 int plcAddress = Convert.ToInt32(dgv_DBInfo.Rows[selectedRowIndex].Cells[5].Value.ToString()); // DB点位的地址 string plcVValue = dgv_DBInfo.Rows[selectedRowIndex].Cells[9].Value.ToString(); // DB点位的值 switch (plcType) { case "Bool": if (plcVValue.ToLower() == "true") { plcVValue = "1"; } else if (plcVValue.ToLower() == "false") { plcVValue = "0"; } else { MessageBox.Show("写入失败!写入的值不是Bool类型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } plc1.WriteSingleRegister(plcAddress, Convert.ToInt32(plcVValue)); // 写入 MessageBox.Show("写入成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); break; case "Int16": int value = 0; try { value = Convert.ToInt32(plcVValue); } catch { MessageBox.Show("写入失败!写入的值不是Int16类型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } plc1.WriteSingleRegister(plcAddress, value); // 写入 MessageBox.Show("写入成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); break; case "Int32": int value1 = 0; try { value1 = Convert.ToInt32(plcVValue); } catch { MessageBox.Show("写入失败!写入的值不是Int32类型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } plc1.WriteMultipleRegisters(plcAddress, value1); // 写入 MessageBox.Show("写入成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); break; case "Float": float value2 = 0; try { value2 = Convert.ToSingle(plcVValue); } catch { MessageBox.Show("写入失败!写入的值不是Float类型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } plc1.WriteMultipleRegisters(plcAddress, value2); // 写入 MessageBox.Show("写入成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); break; case "String<32>": if (plcVValue == null || plcVValue.Length < 1) { MessageBox.Show("写入失败!写入值的长度必须 > 1!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } plc1.WriteMultipleRegisters(plcAddress, plcVValue, 32); // 写入 MessageBox.Show("写入成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); break; //case "Bype<3>": // 日期yyyyMMdd;yyyy、MM、dd共占用3个地址位 default: MessageBox.Show("不支持修改该类型的数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; break; } _Form_PLCDB.AddMessage(LogType.Info, $"用户【{_Form_PLCDB.currentRole}】将‘{plcVName}’【{plcAddress}】的DB值修改为‘{plcVValue}’!"); } } catch (Exception ex) { string str = ex.StackTrace; MessageBox.Show("写入值失败!错误信息:" + ex.Message); _Form_PLCDB.AddMessage(LogType.Error, "PLC交互工位DB详情页面写入当前值出错!异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1) + ";异常信息:" + ex.Message.ToString()); } } } }