From 6e3ed638862c7cc8f15104672650ac533a57a00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?liming=20=E8=94=A1?= Date: Fri, 4 Sep 2026 20:21:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8A=A5=E8=AD=A6=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JY.DAL/ConstValue.cs | 43 + JY.Inspection/Common/PLCAlarmParse.cs | 54 +- JY.Inspection/Frm/FrmTest.Designer.cs | 13 + JY.Inspection/Frm/FrmTest.cs | 5 + JY.Inspection/HomeForm.cs | 52 +- JY.Inspection/HomeForm.resx | 2 +- PLCCommunication/OmronPLCUI.cs | 40 +- 数据库/S1319.sql | Bin 23022 -> 11 bytes 欧姆龙报警寄存器对应表.csv | 2402 +++++++++++++++++++++++++ 9 files changed, 2590 insertions(+), 21 deletions(-) create mode 100644 欧姆龙报警寄存器对应表.csv diff --git a/JY.DAL/ConstValue.cs b/JY.DAL/ConstValue.cs index ef31caa..1eba6ab 100644 --- a/JY.DAL/ConstValue.cs +++ b/JY.DAL/ConstValue.cs @@ -60,5 +60,48 @@ namespace JY.DAL { "CCDI5", "左面凹坑数量" }, { "CCDI6", "右面凹坑数量" } }; + + /// + /// 报警地址信息: 起始地址-长度(分组数,每个分组10个寄存器) + /// + public static readonly Dictionary AlarmAddressDic = new Dictionary() + { + { 10010, 15 } + }; + + // 展开后的平铺映射表:Key为连续的位索引(0, 1, 2...),Value为实际的物理地址 + public static readonly Dictionary FlatAddressMap = new Dictionary(); + + /// + /// 根据数组索引获取对应的物理地址 + /// + public static int GetAddressByIndex(int index) + { + if (FlatAddressMap.TryGetValue(index, out int address)) + { + return address; + } + throw new IndexOutOfRangeException($"索引 {index} 超出了地址字典的映射范围。"); + } + + static ConstValue() + { + FlatAddressMap = new Dictionary(); + int bitIndex = 0; + + // 按起始地址排序,确保映射顺序正确 + foreach (var kvp in AlarmAddressDic.OrderBy(x => x.Key)) + { + int startAddress = kvp.Key; + ushort length = kvp.Value; + + // 将当前段的每一位索引映射到具体的物理地址 + for (int i = 0; i < length; i++) + { + FlatAddressMap[bitIndex] = startAddress + i; + bitIndex++; + } + } + } } } diff --git a/JY.Inspection/Common/PLCAlarmParse.cs b/JY.Inspection/Common/PLCAlarmParse.cs index 1572f78..b2c2400 100644 --- a/JY.Inspection/Common/PLCAlarmParse.cs +++ b/JY.Inspection/Common/PLCAlarmParse.cs @@ -1,4 +1,7 @@ -using JY.Inspection.Entity; +using JY.DAL; +using JY.Inspection.Entity; +using NPOI.SS.Formula.Functions; +using System; using System.Collections.Generic; using System.Linq; @@ -47,6 +50,53 @@ namespace JY.Inspection.Common return listAlarmStatus; } + /// + /// 欧姆龙NX系列Ethernet/IP通讯时将报警地址值转成报警List {直接读取标签地址/无需高低位互换} + /// + /// PLC地址值,如100 + /// PLC读取出来的值 + /// PLC地址类型,默认值R + /// + public static List OmronEIPByte2Status(List byteData, char plcAddrPrefix = 'D') + { + var listAlarmStatus = new List(); + // byte[]转为二进制字符串表示 + string strResult = ""; + byte[] revBytes = SWAPbyte(byteData.ToArray()); //字节高低位互换 + for (int i = 0; i < revBytes.Length; i++) + { + string strTemp = System.Convert.ToString(revBytes[i], 2); + strTemp = strTemp.PadLeft(8, '0').StrReverse(); + strResult += strTemp; + } + + int groupIndex = -1; + for (int i = 0; i < strResult.Length; i++) + { + var plcByte = i % 160; + + //如果是16的倍数地址+1 + if (groupIndex == -1 || (plcByte % 160 == 0 && i != 0)) + { + groupIndex += 1; + } + + int address = ConstValue.GetAddressByIndex(groupIndex); + + //将地址和状态添加到结果集 + listAlarmStatus.Add(new AlarmStatus() + { + PLCAdress = $"{plcAddrPrefix}{address}.{plcByte.ToString()}", + Status = strResult[i] == '1' + }); + + //if (strResult[i] == '1') + // Console.WriteLine($"{plcAddrPrefix}{plcAddrSuffix}.{plcByte.ToString("X")}:{strResult[i]}"); + } + + return listAlarmStatus; + } + /// /// 欧姆龙NX系列Ethernet/IP通讯时将报警地址值转成报警List {直接读取标签地址/无需高低位互换} @@ -55,7 +105,7 @@ namespace JY.Inspection.Common /// PLC读取出来的值 /// PLC地址类型,默认值R /// - public static List OmronEIPByte2Status(int plcAddrSuffix, List byteData, char plcAddrPrefix = 'W') + public static List OmronEIPByte2Status(int plcAddrSuffix, List byteData, char plcAddrPrefix = 'D') { var listAlarmStatus = new List(); // byte[]转为二进制字符串表示 diff --git a/JY.Inspection/Frm/FrmTest.Designer.cs b/JY.Inspection/Frm/FrmTest.Designer.cs index b3b96ff..eead20c 100644 --- a/JY.Inspection/Frm/FrmTest.Designer.cs +++ b/JY.Inspection/Frm/FrmTest.Designer.cs @@ -33,6 +33,7 @@ this.btn_stationArrival = new MetroFramework.Controls.MetroButton(); this.btn_sendMQTTClient = new MetroFramework.Controls.MetroButton(); this.btn_logPLCData = new MetroFramework.Controls.MetroButton(); + this.btn_testAlarm = new MetroFramework.Controls.MetroButton(); this.SuspendLayout(); // // btn_readCollectItemCfg @@ -85,11 +86,22 @@ this.btn_logPLCData.UseSelectable = true; this.btn_logPLCData.Click += new System.EventHandler(this.btn_logPLCData_Click); // + // btn_testAlarm + // + this.btn_testAlarm.Location = new System.Drawing.Point(426, 229); + this.btn_testAlarm.Name = "btn_testAlarm"; + this.btn_testAlarm.Size = new System.Drawing.Size(125, 53); + this.btn_testAlarm.TabIndex = 5; + this.btn_testAlarm.Text = "报警测试"; + this.btn_testAlarm.UseSelectable = true; + this.btn_testAlarm.Click += new System.EventHandler(this.btn_testAlarm_Click); + // // FrmTest // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(998, 586); + this.Controls.Add(this.btn_testAlarm); this.Controls.Add(this.btn_logPLCData); this.Controls.Add(this.btn_sendMQTTClient); this.Controls.Add(this.btn_stationArrival); @@ -108,5 +120,6 @@ private MetroFramework.Controls.MetroButton btn_stationArrival; private MetroFramework.Controls.MetroButton btn_sendMQTTClient; private MetroFramework.Controls.MetroButton btn_logPLCData; + private MetroFramework.Controls.MetroButton btn_testAlarm; } } \ No newline at end of file diff --git a/JY.Inspection/Frm/FrmTest.cs b/JY.Inspection/Frm/FrmTest.cs index 873e3a4..16a528e 100644 --- a/JY.Inspection/Frm/FrmTest.cs +++ b/JY.Inspection/Frm/FrmTest.cs @@ -74,5 +74,10 @@ namespace JY.Inspection.Frm LogHelper.WriteErrorLine("错误日志"); } + + private void btn_testAlarm_Click(object sender, EventArgs e) + { + + } } } diff --git a/JY.Inspection/HomeForm.cs b/JY.Inspection/HomeForm.cs index a5bd4f3..6abb88f 100644 --- a/JY.Inspection/HomeForm.cs +++ b/JY.Inspection/HomeForm.cs @@ -173,14 +173,15 @@ namespace JY.Inspection /// List NGList = new List(); + //private readonly object lockObject = new object(); /// /// 报警原始数据 /// - List listAlamByte = new List(); + //List listAlamByte = new List(); //报警表单数据 List listAlarmForm = null; //PLC报警状态值 - List listAlarmStatus = null; + //List listAlarmStatus = null; /// @@ -278,6 +279,8 @@ namespace JY.Inspection this.ControlBox = true; // 或设置窗口可调整大小 this.Resizable = true; + + } private void InitDgvBColumns() @@ -560,6 +563,8 @@ namespace JY.Inspection CheckClassShift(); InitOmronCom(); + string strFileName = Environment.CurrentDirectory + "\\欧姆龙报警寄存器对应表.csv"; + listAlarmForm = CSVHelper.ReadCSV(strFileName,","); CancellationToken token1 = mctsA1.Token; CancellationToken token2 = mctsA2.Token; @@ -739,7 +744,7 @@ namespace JY.Inspection IsStartNGFL = IniFileHelper.ReadIniData("MES配置", "StartNGFL") == "1" ? true : false; chkStartNGFL.Checked = IsStartNGFL; - listAlamByte = GetListByte(200); + //listAlamByte = GetListByte(200); Global.systemConfig.isUpMes = IniFileHelper.ReadIniData("SYSTEM_CONFIGURE", "IsMesUP") == "1" ? true : false; @@ -3123,30 +3128,43 @@ namespace JY.Inspection if (!mt.IsCancellationRequested) { sw.Restart(); - byte[] res = new byte[2]; - for (int i = 0; i < 30; i++) + //byte[] res = new byte[2]; + //for (int i = 0; i < 30; i++) + //{ + // res = omronPLCCom.lstMcUI[0].Readbyte("W6100[" + i + "].Word区", 1); + // if (res != null) + // { + // for (int j = i; j < res.Length + i; j++) + // { + // listAlamByte[i + j] = res[j - i]; + // } + // } + //} + byte[] res = null; + List listAlamByte = new List(); + foreach (var address in ConstValue.AlarmAddressDic.Keys) { - res = omronPLCCom.lstMcUI[0].Readbyte("W6100[" + i + "].Word区", 1); - if (res != null) + ushort byteLen = (ushort)(ConstValue.AlarmAddressDic[address] * 10); + res = omronPLCCom.lstMcUI[0].ReadByteFins($"D{address}", byteLen); + + if (res == null) { - for (int j = i; j < res.Length + i; j++) - { - listAlamByte[i + j] = res[j - i]; - } + continue; } + + listAlamByte.AddRange(res); } //AddLog(0, "读取报警耗时:" + sw.ElapsedMilliseconds + "ms"); if (listAlamByte == null) { return; } - string strFileName = Environment.CurrentDirectory + "\\欧姆龙报警寄存器对应表.csv"; - listAlarmForm = CSVHelper.ReadCSV(strFileName); + + //string strFileName = Environment.CurrentDirectory + "\\欧姆龙报警寄存器对应表.csv"; + //listAlarmForm = CSVHelper.ReadCSV(strFileName); //如果未配置报警地址信息返回 TODO if (listAlarmForm == null) { return; } - int startPlcAddr = 0;//TODO 读取起始地址 - //3.公用方法解析byte[]数据 => List - if (listAlamByte == null) { return; } //如果未配置报警地址信息返回 + //TODO 切换三菱和欧姆龙 - listAlarmStatus = PLCAlarmParse.OmronEIPByte2Status(startPlcAddr, listAlamByte); + List listAlarmStatus = PLCAlarmParse.OmronEIPByte2Status(listAlamByte); //4.判定有不良后,关联AlarmStatus 和AlarmForm if (listAlarmStatus == null) { return; } //状态信息为空返回 diff --git a/JY.Inspection/HomeForm.resx b/JY.Inspection/HomeForm.resx index 61a885d..042681c 100644 --- a/JY.Inspection/HomeForm.resx +++ b/JY.Inspection/HomeForm.resx @@ -331,7 +331,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAE - CgAAAk1TRnQBSQFMAgEBAwEAAQgBCQEIAQkBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + CgAAAk1TRnQBSQFMAgEBAwEAASgBCQEoAQkBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA diff --git a/PLCCommunication/OmronPLCUI.cs b/PLCCommunication/OmronPLCUI.cs index 77c5993..7c11af5 100644 --- a/PLCCommunication/OmronPLCUI.cs +++ b/PLCCommunication/OmronPLCUI.cs @@ -64,6 +64,8 @@ namespace PLCCommunication /// 欧姆龙Fins协议 /// public HslCommunication.Profinet.Omron.OmronCipNet omronCipNet = null; + + public HslCommunication.Profinet.Omron.OmronFinsNet omronFinsNet = null; /// /// 是否链接PLC /// @@ -198,6 +200,10 @@ namespace PLCCommunication InitializeComponent(); omronCipNet = new OmronCipNet(); omronCipNet.ConnectTimeOut = 2000; + + omronFinsNet = new OmronFinsNet(); + omronFinsNet.ConnectTimeOut = 2000; + PanelTest.Enabled = false; } @@ -336,6 +342,11 @@ namespace PLCCommunication omronCipNet.Port = port; omronCipNet.Slot = solt; omronCipNet.ConnectClose(); + + omronFinsNet.IpAddress = address.ToString(); + omronFinsNet.Port = 9600; + omronFinsNet.ConnectClose(); + try { omronCipNet.ConnectTimeOut = 2000; @@ -355,7 +366,10 @@ namespace PLCCommunication str = StringResources.Language.ConnectedFailed; AddLog(lstRecv,1, StringResources.Language.ConnectedFailed); } - + + + omronFinsNet.ConnectTimeOut = 2000; + OperateResult connectFins = omronFinsNet.ConnectServer(); } catch (Exception ex) { @@ -939,6 +953,30 @@ namespace PLCCommunication return result; } + public byte[] ReadByteFins(string iAddr, ushort length) + { + byte[] result = null; + try + { + //string type = iAddr.Substring(0, 1); + //if (type != "D" && type != "R") + //{ + // AddLog(lstSend, 2, "暂只支持D,R存储区"); + //} + if (IsConnected) + { + result = omronFinsNet.Read(iAddr, length).Content; + AddLog(lstResWrite, 0, $"{iAddr} --> {result?.ToString()}"); + } + } + catch (Exception ex) + { + AddLog(lstResWrite, 2, $"{iAddr} --> {ex.Message}"); + } + + return result; + } + /// /// 写入byte数组 /// diff --git a/数据库/S1319.sql b/数据库/S1319.sql index e5b7cac627ab962196a72691f8bf000f6d2440ef..30188f8e6da5129c2e4d8953a1e566f73de5ca2d 100644 GIT binary patch literal 11 ScmYdFPfaXJ%`3?)sRRHT>I9zv literal 23022 zcmeHP%Whjm7@lspRN@6#nN<>0n%cRwNR{IHl3GpdG4R{Myu;B#|8x{zJ1VX^~&G_Wpee5|-HIhfs$vHkV|I9!0&3~CW^Ur_(Zi>1n ziHz96Ju7lzN!$>-;vI2StcaSt^LbXh@A=Ch<$?HIw8ft2i4Q@Y5e?D8yAIy5tbIH` zK{?m)dIU&g$~7ifI zbSE-rPn?0SJ%%zHVhwG%GmxKXZffA62Sg6VMz}KM7^v}t3Q^gY4z*X zA5U56_R;IzfIOc<);o}DMSUF7SkVZP^0CxcN3r$N62=d&a&jGiE>MVUWVgW zu-qvAI97?BLd%PV^3Rgez5W~fxP(?^AR*6iUB`8TT3fL3wDM0e65ANJeBMV2N7o6S zyLkT$RLe+fN&9&l98IBB#DjMJ)Z@Dyg6bHlL~yz9O`IW*qIvg4{lyegR4P5ib6g#a zbJoGyR6dTGyWo~1k7X?*kDJ%ehw?L>8r^)^K$)&T7A!FvXjz;@gzLx!>forPWUR>^ z^7EYw)Iu4al9FK>O6~hUebG9&^3)=wM&lsg*h~cfwg~!kRnlz4OcW`Df9?EuWaUuF zp)>z86D`WzpY1!Z-eb5=jh zMDP2$MbGOQ2R%$@1=Q_i{2Jix3bpT^v%+hzFaaIvz)~&0<)V&V>V|oi@@xb(U{F!%px%3*Jm?l zb01XKtVP30lKA~b(Q4H zgWnFgTcw8G4zu{GU&5Xb`;{OXLsQpEaU(de1FR`SpDw;KE^XTQm* z@2cKCj%Iq5Z*Kq6v1qwyIr~b@MC)obQ~R!aG|%6S|ExIqs6yi6rvc?OpWk4%Ui-(Ny}e30xUWADb}F zxPrJbkdc14jVe&m#hviOM-?RP_fJaqu0akX{fx!%(xlO%J;Z}D+JKRuUBnSk2Grj$ zv7aXD&tbJ;xaF6j2lE#_yMm~oL)a@v%Zw6Pw2t_N0!HM%)OM$c?a(R3<%Kb%jD=!k zi5rtO3P=937@d-iqeef{M5mNG+Q8AP7fV_~AM9({4z~}ScpDw=-BMILh>A`*j)$yh z<6_;C;?BZSVJ(AxyjhawPf8!JmVYE86TAH=GNp+oN!N$l?`r%q;=Ys@IgIS_9D=B* z{xag@82#DpOR!f8<7n2An-TpL=%KLeCQ+&V{KL~Vpj}QiH05x5BizGjw1*!P6|?G| zpy2Q8NsVYt(jZCc(!wZHc5IR~Ot}57hIxqDJ5OHW9Mh{8f@gHBOJAmi z+$yd&jXny;&mTvekPscwKAgmdTbxGXquOpIn`Z)y9%X(xlHI}BrTyTjoJ7fX+wV&D znzY}Hm>-ACM#%tIr3TH;;=KgUi(29%Tpjo&dNYeOT7;)2ZNlSp&h;5}jczn81S8P~K6Ykl|(lxZ;lXX5%(rhIuecV1z5bMdE*TnaPt5@7r>d`boy!S%QGOG6x zS6U685Z9@@@Y2ruUpo9Vu_#Jit>7Ige(!yh^Sa`C)cP4__!(;D?hL+04