據(jù)采集Demo用C#實現(xiàn)全流程詳解:EZSocket通信與宏變量讀取)
簡介C#數(shù)據(jù)采集Demo面向三菱CNC系統(tǒng)專為機床自動化工程師、上位機開發(fā)者和工業(yè)物聯(lián)網從業(yè)者設計旨在解決機床實時監(jiān)控、加工參數(shù)讀取、設備狀態(tài)追蹤及故障日志獲取等工業(yè)數(shù)據(jù)采集難題。壓縮包約3.52MB內部包含PDF格式的參考手冊和三菱CNC模擬環(huán)境SimCNC的源碼目錄參考手冊用于查詢通訊協(xié)議、寄存器地址與數(shù)據(jù)格式SimCNC則支持在無實體機床的情況下搭建仿真調試環(huán)境方便反復驗證采集邏輯。Demo源碼演示了配合A2.exe通訊軟件與CNC建立連接通過C#實現(xiàn)對多種型號三菱機臺的數(shù)據(jù)讀取并將采集功能封裝為獨立軟件或插件可靈活接入現(xiàn)有產線信息化系統(tǒng)。整體代碼結構清晰包含連接建立、數(shù)據(jù)解析、異常處理等關鍵模塊是學習工業(yè)通訊編程的良好范本。已有620人學習下載適合需要快速落地三菱CNC數(shù)采項目或進行技術預研的開發(fā)者參考能顯著縮短環(huán)境搭建與排錯時間。1. 三菱CNC數(shù)據(jù)采集Demo先想清楚要采什么別急著開VS車間里一臺三菱加工中心正在跑活操作員盯著控制面板你在辦公室電腦前想看到它主軸轉速、當前坐標、有沒有報警——這就是三菱CNC數(shù)據(jù)采集Demo附C#源碼這個標題真正要解決的事。它不靠串口線不靠人抄屏而是走CNC自帶的以太網口用C#把宏變量、坐標、報警號實時拉回來。反直覺的地方在于新手最想要的往往是能把數(shù)讀出來的激動感但真正決定這活兒成不成的是動手之前先想清楚要采哪幾個地址、用什么協(xié)議、幀怎么解析。常見做法是走三菱的EZSocket中間件DLL一引C#里P/Invoke一調十幾行代碼就能連上但參數(shù)不對時一個Open函數(shù)能卡你一下午。這個方向適合做設備聯(lián)網、MES對接、機加工自動化的工程師也適合剛入行想拿一臺真設備練手的同學??赐赀@篇文章你至少能把這套Demo跑通并且知道坑在哪。2. 準備工作三菱CNC數(shù)據(jù)采集Demo的網絡前提與協(xié)議選型2.1 網口通信是前提串口方案到了Demo階段就該放棄很多老工程師的第一反應是“CNC后面不是有RS232口嗎直接串口讀不就行了”。這個思路在二十年前沒問題但現(xiàn)在做數(shù)據(jù)采集串口的三個短板非常明顯一是傳輸速度慢115200波特率下刷新一次狀態(tài)要幾百毫秒別說做高頻采集二是好多老舊串口方案只能單向輸出想寫宏變量回機臺很難三是串口線超過15米信號就開始飄車間現(xiàn)場拉線很不現(xiàn)實。所以這個Demo的正確起點是以太網口。三菱的中高端系統(tǒng)比如M70、M700、M80系列標準配置里都帶以太網口參數(shù)里面設好IP地址、子網掩碼之后上位機直接用網線連交換機就能訪問。通信鏈路的示意圖其實很簡單C#程序通過TCP協(xié)議發(fā)一個ASCII字符串命令幀給CNCCNC回一個帶數(shù)據(jù)的響應幀程序把幀解析出來就完事了。這里有個關鍵選型點直接用TCP發(fā)MC協(xié)議幀雖然可行但工程上沒人這么干因為幀頭、校驗、分包都得自己拼出錯率太高。業(yè)界通用做法是安裝三菱的EZSocket通信庫它本質上是把MC協(xié)議封裝成了C風格函數(shù)提供固定接口往上位機這邊暴露動態(tài)鏈接庫C#項目里聲明一下就能調用。Demo階段選它省掉的是協(xié)議拼幀的麻煩留下的是數(shù)據(jù)解析的核心邏輯。2.2 訪問對象A/B/C/DDemo該用哪一個通道EZSocket里有一個概念叫“訪問對象”英文叫Access Target官方分為A、B、C、D四種。A類走的是三菱PLC的MC協(xié)議用來讀PLC軟元件B類是Windows下和PC內部數(shù)據(jù)交換用的C類是訪問CNC數(shù)值數(shù)據(jù)的通道宏變量、坐標、刀補、報警都歸它管D類是訪問機床側的PLC數(shù)據(jù)比如IO信號、繼電器狀態(tài)。寫成表格更直觀訪問對象面向的數(shù)據(jù)Demo里有沒有用APLC軟元件D、M、Y等一般不用BWindows環(huán)境內部通信不用CCNC數(shù)值數(shù)據(jù)宏變量、坐標、報警核心通道D機床側PLC數(shù)據(jù)IO、繼電器按需C#做CNC采集絕大多數(shù)需求都集中在C類上。你在MES里看到的主軸轉速當前X軸坐標報警號全部通過C類讀出來。有些車間還想看機床門有沒有關、紅燈有沒有亮這些信號在D類里但那是后話Demo階段先把C類吃透。有個細節(jié)要注意EZSocket的DLL同時支持A類訪問所以如果你這臺CNC的PLC里存了工件計數(shù)之類的數(shù)據(jù)也可以用同一套代碼去讀只需要把打開連接時的訪問對象類型改一下。Demo階段不建議一上來就通吃先把C類讀通再往D類擴展。2.3 CNC側參數(shù)核對IP、端口、系統(tǒng)版本差異連不上CNC的時候八成不是代碼的問題而是CNC側的網絡參數(shù)沒核對。三菱系統(tǒng)里以太網參數(shù)一般在維護菜單的以太網設定或者網絡設定頁面里。需要確認四項參數(shù)典型值說明IP地址192.168.1.50和上位機在同一網段子網掩碼255.255.255.0不跨網段就夠用端口號6000不同系統(tǒng)版本可能有差異通信協(xié)議TCP打開對應通道端口號是個血淚高發(fā)區(qū)。部分老系統(tǒng)默認用6000部分系統(tǒng)在參數(shù)里單獨開了一個端口還有的系統(tǒng)要同時開UDP和TCP兩個通道。我一般會在CNC旁邊先用筆記本電腦ping一下IP通了再跑Demoping不通就別折騰代碼先查網線和IP段。還有兩個前置條件容易被忽略一是EZSocket服務器端程序要和系統(tǒng)匹配二是CNC側參數(shù)里的傳輸協(xié)議要選成允許外部設備訪問。某些系統(tǒng)出廠時默認關閉了外部訪問需要到維護模式里打開。這些操作需要操作員權限做Demo之前最好和車間師傅打個招呼別自己偷摸改參數(shù)改完機臺報警就麻煩了。3. 核心代碼C#讀三菱CNC宏變量、坐標與報警3.1 創(chuàng)建一個控制臺Demo把EZSocket.dll引進來拿到三菱EZSocket安裝包之后安裝目錄下會有一個動態(tài)鏈接庫名字一般是EZSocket.dll。C#這邊不能直接添加引用因為它是C風格導出函數(shù)不是托管DLL正確做法是用DllImport聲明外部函數(shù)。先建一個控制臺項目平臺目標改成x86然后寫一個靜態(tài)類來包裝接口using System; using System.Runtime.InteropServices; public static class EZSocketWrapper { // 聲明三個核心函數(shù)打開、讀取、關閉 [DllImport(EZSocket.dll, EntryPoint EZSocket_Open)] public static extern int Open( IntPtr[, ,] pCNC, // 連接句柄三維數(shù)組 int nType, // 訪問對象類型2表示C類CNC數(shù)據(jù) int nOpen, // 通信方式1表示TCP string pIPAddr, // CN C的IP地址 string pPort, // 端口號 int nTimeOut); // 超時時間毫秒 [DllImport(EZSocket.dll, EntryPoint EZSocket_Read)] public static extern int Read( IntPtr[, ,] pCNC, // 連接句柄 int nType, // 訪問對象類型 string pReadBuf, // 讀命令幀 ref string pRetBuf, // 返回數(shù)據(jù)緩沖區(qū) string pErrMsg); // 錯誤信息輸出 [DllImport(EZSocket.dll, EntryPoint EZSocket_Close)] public static extern int Close( IntPtr[, ,] pCNC, int nType); }這段聲明里最容易栽跟頭的是句柄類型。EZSocket的手冊上寫的是三維指針數(shù)組C#這邊的對應寫法就是IntPtr的三維數(shù)組初始化時每個維度給3就夠了。nType傳2代表C類訪問nOpen傳1代表走TCP。端口參數(shù)是字符串不是整數(shù)這是很多人第一次調用時報錯的原因。超時時間建議給3000毫秒太短在車間網絡抖動時容易誤報失敗太長則程序卡死在那里。注意DLL的位數(shù)必須和編譯目標一致。EZSocket.dll在多數(shù)版本里是32位的所以項目平臺目標一定要選x86否則運行到Open那行就拋BadImageFormatException這個在第5章避坑里展開。3.2 連接到CNCOpen和Close的寫法連接這塊的套路是固定的先創(chuàng)建句柄數(shù)組調Open判斷返回值用完調Close。下面是完整的最小連接代碼static void Main(string[] args) { // 連接句柄三維數(shù)組結構 IntPtr[,,] pCNC new IntPtr[3, 3, 3]; // 打開C類訪問TCP方式連192.168.1.50的6000端口 int ret EZSocketWrapper.Open( pCNC, 2, 1, 192.168.1.50, 6000, 3000); if (ret 0) { Console.WriteLine(連接成功); // 在這里執(zhí)行讀取操作 // ... EZSocketWrapper.Close(pCNC, 2); } else { Console.WriteLine(連接失敗錯誤碼 ret); } }返回值ret為0表示成功非0為失敗。這一步很多人第一次跑通后會特別興奮但別高興太早——連接成功只代表TCP鏈路通了真正讀數(shù)據(jù)時的幀格式錯一丁點Read照樣返回失敗。另外Close操作不能省有的現(xiàn)場出現(xiàn)過程序崩潰后CNC側連接資源沒釋放導致后續(xù)無法再次連接的情況雖然重啟機臺能恢復但車間里重啟設備你可得等操作員排完當前工件。3.3 讀宏變量#100的實時值怎么取回來三菱系統(tǒng)的宏變量是機臺邏輯里最常用的數(shù)據(jù)區(qū)比如把當前工件計數(shù)寫到#100把主軸倍率寫到#101MES要的就是這些。讀取宏變量用到EZSocket_Read命令幀格式我一般按R地址長度來拼static void ReadMacro(IntPtr[,,] pCNC, int macroNum, out float value) { // 拼讀命令幀讀#100就填 R0,100,1 string cmd R0, macroNum ,1; string retBuf ; string errMsg ; int ret EZSocketWrapper.Read(pCNC, 2, cmd, ref retBuf, ref errMsg); if (ret 0) { // 返回數(shù)據(jù)從第6個字符開始是有效數(shù)據(jù)區(qū) string hexData retBuf.Substring(5); // 三菱返回的是倒序十六進制字符串要反轉字節(jié)再轉float byte[] bytes HexToBytes(hexData); Array.Reverse(bytes); value BitConverter.ToSingle(bytes, 0); Console.WriteLine(# macroNum value); } else { Console.WriteLine(讀取失敗 errMsg); value 0f; } } static byte[] HexToBytes(string hex) { int length hex.Length / 2; byte[] result new byte[length]; for (int i 0; i length; i) result[i] Convert.ToByte(hex.Substring(i * 2, 2), 16); return result; }這里有個工藝問題CNC讀回來的數(shù)據(jù)是十六進制字符串而且是倒序字節(jié)序。比如浮點數(shù)1.5在內存里是3F C0 00 00三菱回包里往往是0000C03F必須反轉之后用BitConverter轉float。這個字節(jié)序坑每一臺新機型都得試一次建議把轉出來的值和面板上顯示的值對一下對不上就交換一下高低字節(jié)順序。宏變量號本身也有講究公共變量#100到#149一般默認為空變量區(qū)可以隨便用#150到#199在某些系統(tǒng)里是模擬輸入通道數(shù)據(jù)#500到#999是保持型變量斷電不丟。讀#500之前先確認一下機床廠有沒有把這部分區(qū)域分配給專屬功能避免讀到無意義數(shù)據(jù)還當成寶貝存進數(shù)據(jù)庫。3.4 讀坐標和報警把機臺狀態(tài)拼出來宏變量能解決數(shù)據(jù)交換但MES上層更關心的是坐標和報警。讀取絕對坐標和報警號用到的命令幀前綴分別是E和A下面是讀絕對坐標和報警的核心片段static void ReadPositionAndAlarm(IntPtr[,,] pCNC) { string posBuf ; string almBuf ; string errMsg ; // 讀絕對坐標 int posRet EZSocketWrapper.Read(pCNC, 2, E, ref posBuf, ref errMsg); if (posRet 0 posBuf.Length 61) { // 第1~3位是附加信息每個坐標占6個字節(jié) string xHex posBuf.Substring(6, 12); string yHex posBuf.Substring(18, 12); string zHex posBuf.Substring(30, 12); // 轉字節(jié)再反轉再轉float邏輯同上 float x ConvertHexToFloat(xHex); float y ConvertHexToFloat(yHex); float z ConvertHexToFloat(zHex); Console.WriteLine($X:{x:F3} Y:{y:F3} Z:{z:F3}); } // 讀報警號 int almRet EZSocketWrapper.Read(pCNC, 2, A, ref almBuf, ref errMsg); if (almRet 0 almBuf.Length 9) { // 報警號也是倒序轉int string alarmHex almBuf.Substring(5, 4); byte[] bytes HexToBytes(alarmHex); Array.Reverse(bytes); int alarmCode BitConverter.ToInt16(bytes, 0); if (alarmCode ! 0) Console.WriteLine(當前報警號 alarmCode); else Console.WriteLine(無報警); } }坐標讀取返回的幀長度是固定的每個軸占6個字節(jié)十六進制排列順序是X、Y、Z有些系統(tǒng)還帶A軸、B軸長度就不一樣解析前先判斷返回幀長度能省不少麻煩。報警讀取時要注意報警碼按有符號短整型解析負號代表報警級別。讀報警還分NC報警和機床報警A命令返回的是系統(tǒng)報警機床報警走D類訪問做Demo時別把兩者混在一起。一個實用技巧是把坐標和宏變量的讀取放在同一個循環(huán)里每隔200到500毫秒刷一次屏。刷新太快沒必要太慢又看不出實時效果車間里大部分采集需求到500毫秒級別的刷新率已經足夠。4. 參數(shù)與內存映射宏變量、公共變量和回復幀的邊界4.1 三菱宏變量的分區(qū)公共變量、保持型變量和刀補拿到一套Demo代碼之后最先要問的問題是我該讀哪些地址。三菱CNC的宏變量地址分布有規(guī)律可循但不同系統(tǒng)之間有一點差異常用分區(qū)是這樣的變量號范圍類型Demo應用場景#100 ~ #149空公共變量跨程序傳遞數(shù)據(jù)#150 ~ #199部分系統(tǒng)為模擬量輸入讀主軸電流等模擬量#500 ~ #999保持型變量工件計數(shù)、生產統(tǒng)計#2000 ~ #2199刀補變量部分系統(tǒng)刀具磨損管理#3000 ~ #3999系統(tǒng)設定相關一般不碰Demo階段建議優(yōu)先讀#100區(qū)間和#500區(qū)間。#100區(qū)間斷電會清零適合讀當班產量這類臨時數(shù)據(jù)#500區(qū)間是斷電保持的適合存班長累計數(shù)。很多工廠的做法是讓PLC在換班時把#500里的值搬運到另一個地址上位機只負責讀不負責寫。刀補的地址范圍需要重點提示不同系統(tǒng)版本對#2000系列的映射并不一致有的系統(tǒng)里#2001對應1號刀的X向刀補有的系統(tǒng)里卻跳過了部分保留段。讀取刀補之前找操作員確認一下機床廠的宏變量分配表或者干脆用機臺面板手動改一個已知值再讀出來驗證——這是最樸素的測試方法。4.2 回復幀的字節(jié)對齊和大小端坑EZSocket返回的數(shù)據(jù)區(qū)是十六進制字符串規(guī)則是所有數(shù)據(jù)都按字倒序。這里說的字倒序不是字節(jié)倒序而是兩個字節(jié)一組顛倒。舉例說明數(shù)據(jù)區(qū)里如果收到3412實際值應該是0x1234。浮點數(shù)則四個字節(jié)整體反轉前面代碼里用了Array.Reverse其實就是把大小端問題用最簡單的方式抹平了。解析時的另一層坑在于命令幀和數(shù)據(jù)幀之間可能帶空格或控制符。不同版本EZSocket返回的幀長度有細微差異有的帶起始符有的不帶。我建議在寫解析邏輯之前先做一步打印裸包操作// 調試用把Read返回的原始幀原樣打印出來 Console.WriteLine(RAW:[ retBuf ] len retBuf.Length);把這行加到Demo里跑一次對照三菱手冊里的幀結構看一遍再寫Substring的截取邏輯比對著網上抄解析代碼靠譜得多。不同系統(tǒng)的返回幀長度不一樣在M70上試好的偏移量拿到M80上可能就得加一位。還有一個小提醒全部用Substring截取十六進制字符串看起來簡單但在解析多個軸坐標時容易數(shù)錯位數(shù)。碰到解析結果數(shù)值怪異的情況先數(shù)一下每個字符的下標用調試器逐幀看不要靠猜。4.3 采集頻率與系統(tǒng)負荷別把Demo寫成死循環(huán)數(shù)據(jù)采集最常見的失控寫法是while(true)里不加延時CPU占滿不說CNC側的EZSocket服務也會被高頻請求拖累。三菱官方對采集頻率沒有硬性指標但業(yè)界經驗是狀態(tài)數(shù)據(jù)坐標、轉速500毫秒刷一次報警數(shù)據(jù)可以做到200毫秒甚至事件觸發(fā)產量數(shù)據(jù)按分鐘或按工件觸發(fā)即可。一個推薦的安全采集框架是這樣的// 用定時器代替死循環(huán)避免阻塞UI線程 System.Timers.Timer timer new System.Timers.Timer(); timer.Interval 500; // 500毫秒刷一次 timer.Elapsed (sender, e) { ReadPositionAndAlarm(pCNC); ReadMacro(pCNC, 100, out float count); }; timer.Start();注意這里有個隱患Timer觸發(fā)的事件如果在上一輪讀取還沒結束時又進來就會導致消息堆積。保險做法是加一個bool鎖標志讀取中則跳過本次觸發(fā)。Demo階段可以不考慮并發(fā)但往生產走這一步是必須的。另外不要同一時間開多個線程去調EZSocket_ReadDLL內部不是線程安全的。多個采集線程同時調用同一個連接句柄輕則返回數(shù)據(jù)錯亂重則直接讓連接斷掉。需要采集多組數(shù)據(jù)時串行讀別并行讀。5. 三菱CNC采集Demo的常見踩坑現(xiàn)象、原因與解決5.1 Open返回失敗但Ping得通CNC現(xiàn)象上位機能ping通CNC的IP但EZSocket_Open返回非0讀取完全無法進行。原因TCP鏈路通不代表CNC側的EZSocket服務在監(jiān)聽。最常見的情況有三種CNC系統(tǒng)參數(shù)里沒打開外部訪問權限端口號和實際監(jiān)聽端口不一致訪問對象類型選錯了類型比如C類通道沒開但A類通道是好的。解決登錄CNC維護畫面檢查以太網設定里的端口和訪問許可。先把訪問對象類型換成A類試一次如果能連上說明C類通道沒開如果A類也連不上檢查端口號。還有一招是看防火墻Windows自帶的防火墻經常攔截TCP入站連接臨時關掉再測一下就能定位。5.2 調用DLL時拋BadImageFormatException現(xiàn)象代碼編譯通過一運行到Open函數(shù)就拋出BadImageFormatException異常信息里通常寫著32位還是64位不匹配。原因EZSocket.dll是32位動態(tài)庫而Visual Studio里新建的.NET項目默認平臺目標是AnyCPU在64位系統(tǒng)上運行時會用64位進程加載32位DLL直接崩。解決打開項目屬性找到生成選項卡把平臺目標改成x86。改完重新生成問題消失。這個坑幾乎每個第一次接觸EZSocket的C#開發(fā)者都會遇到網上搜相關報錯一搜一大片但知道原理之后十秒鐘就能解決。5.3 讀到的宏變量是全零或者NaN現(xiàn)象Read調用返回成功但解析出的變量值要么全是0要么是NaN。原因三菱宏變量分為數(shù)值型和邏輯型而數(shù)值型里又有整型和浮點型之分。系統(tǒng)默認按雙字節(jié)整數(shù)返回時你用float解析就會得到詭異值。另外宏變量所在的地址區(qū)間可能根本沒被寫入有效數(shù)據(jù)空變量區(qū)讀出0是正常現(xiàn)象。解決先在CNC面板上手動給#100賦一個已知值比如12.34然后跑Demo讀一次。讀到12.34說明解析邏輯正確讀到0說明地址區(qū)間為空換個變量號測試讀到一堆亂碼說明數(shù)據(jù)類型解析錯了——嘗試把BitConverter.ToSingle換成ToInt16或者反過來。用已知值校準是排查這類問題最有效的手段。5.4 程序跑一會兒后連接自己斷開現(xiàn)象Demo運行幾分鐘后Read開始返回錯誤重試也無效只有重啟程序才能恢復連接。原因EZSocket服務端對空閑連接有超時回收機制超時時間從幾秒到幾分鐘不等。程序長時間不發(fā)命令服務端主動斷開連接。還有一種情況是網絡里有廣播風暴TCP連接被干擾。解決在采集循環(huán)里加入周期重連機制。常見做法是每次Read失敗時自動執(zhí)行一次重連先Close再Open。更溫和的做法是縮短Timer間隔把心跳維持在一秒一次以內避免空閑超時。注意重連時要釋放舊句柄否則句柄會越積越多最終系統(tǒng)資源耗盡只能重啟。另外排查一下網絡里有沒有人在跑大流量傳輸車間里的監(jiān)控系統(tǒng)回傳視頻有時會占滿交換機帶寬把CNC和上位機挪到同一個交換機下或者劃分獨立VLAN能有效緩解。5.5 報警號讀出來和面板顯示不一致現(xiàn)象報警命令讀出的編號和機臺面板上顯示的報警號對不上有的差個幾千有的完全不在一個數(shù)量級。原因報警命令讀出的是內部報警指針不等于面板顯示的報警號。面板顯示的是格式化后的報警文本內部編號需要對照報警表映射。另外一個常見干擾是機床廠在標準系統(tǒng)上疊加了自己的PMC報警這些報警由D類訪問對象負責C類讀不到。解決先確認讀的是NC報警還是PMC報警。NC報警用A命令讀內部編號再查系統(tǒng)報警表映射成面板報警號PMC報警要切換到D類訪問對象讀取。Demo階段建議直接在CNC上觸發(fā)一個已知報警比如急?;蛘唛T開關然后對比讀回來的編號和面板值把對應關系記錄下來寫進配置表里。這個工作看起來笨但做完以后對接MES報警模塊就順暢多了。6. 讓Demo往生產方向走數(shù)據(jù)落庫、心跳重連與MES橋接Demo跑通了接下來要做的三件事決定了它在生產環(huán)境里能不能站住腳數(shù)據(jù)落庫、斷線自動重連、給上層系統(tǒng)留接口。數(shù)據(jù)落庫最省事的方案是SQLite不需要額外裝數(shù)據(jù)庫服務一個文件搞定。把每次讀到的坐標、宏變量、報警號連同時間戳寫進一張表里粒度控制在秒級就夠保留最近90天數(shù)據(jù)。注意寫入操作要和采集操作解耦采集線程只負責讀寫庫交給獨立線程或后臺任務避免磁盤慢的時候拖垮采集循環(huán)。斷線自動重連是生產環(huán)境剛需。做法是把Open、Read、Close封裝成一個類內部記錄連接狀態(tài)每次Read失敗時觸發(fā)重連重連次數(shù)達到上限后向上拋出異常由上層決定是告警還繼續(xù)重試。關鍵細節(jié)是重連之前必須Close舊句柄很多重連幾次之后徹底連不上的問題都出在句柄泄漏上。給MES橋接的方式有兩種簡單一點是Demo里直接提供HTTP接口MES通過網頁接口拉數(shù)據(jù)更穩(wěn)妥的是把采集到的數(shù)據(jù)推給消息隊列由消費端去落庫和展示。Demo階段不用做太復雜把采集類寫干凈數(shù)據(jù)格式定義成統(tǒng)一的JSON結構后續(xù)擴展就順理成章。最后說一個我在車間里淌過的教訓有一回為了趕進度我把采集循環(huán)直接寫進窗體Timer里刷新間隔壓到50毫秒結果一臺老款系統(tǒng)被高頻請求打到以太網模塊卡死操作員停機重啟才恢復。后來我養(yǎng)成了兩個習慣任何采集代碼先量化頻率再上線任何外掛程序都加總開關和限速。做設備采集慢一點不會出事快過頭一定出事。希望幫到你。本文還有配套的精品資源點擊獲取