c#实现上位机数据采集的项目总结
功能要求
項目實現(xiàn)
1、采集PLC數(shù)據(jù)
硬件采用RS232串口,通訊協(xié)議使用ModusbusRTU。以前跟PLC通訊,為求簡單,一般直接使用無協(xié)議,使用倒沒問題,但偶爾出現(xiàn)數(shù)據(jù)丟失也是煩人,要確保對方接收到數(shù)據(jù)還要雙方寫返回數(shù)據(jù)。使用modbus協(xié)議,PLC基本不用寫通訊程序,而上位機(jī)可以直接自己確認(rèn)對方是否收到數(shù)據(jù),再確認(rèn)是否給對方重發(fā)一次。這個項目只要求采集數(shù)據(jù),因為讀取的頻率高于數(shù)據(jù)變化,所以偶爾讀不到都不影響,使用modbus就更合適了。
/// <summary>/// 通過Modbus讀取PLC,獲取相應(yīng)數(shù)據(jù)/// </summary>private void ScanPLC(){//創(chuàng)建字節(jié)數(shù)組byte[] result = null;//從站號ushort DevAdd = 1;//起始地址ushort Address = 100;//長度ushort Length = 5;while (running){if (plcConnected){result = objModbus.ReadKeepReg(DevAdd, Address, Length);DataProcessing(result, Length);}else{try{objModbus.OpenMyCom(9600, comName1, 8, Parity.Odd, StopBits.One);//objModbus.ReadTimeOut = 500;plcConnected = true;textReceive.Invoke(new ExecuteWork(RecRunData), "重連PLC成功");}catch (Exception ex){textReceive.Invoke(new ExecuteWork(RecRunData), "重連PLC失敗:" + ex.Message);plcConnected = false;}}Thread.Sleep(1000);}}?2、采集測試儀數(shù)據(jù)
硬件也是采用RS232串口,因為測試儀的說明書不完善,modbus協(xié)議沒有測試成功,而無協(xié)議測試成功了,所以直接采用無協(xié)議接收數(shù)據(jù)。采取的采集數(shù)據(jù)模式是,測試儀有測試數(shù)據(jù)馬上主動通過串口發(fā)送,而我的程序只要一直處于接收狀態(tài),有數(shù)據(jù)就記下。所以建了一個線程一直掃描串口數(shù)據(jù)。
關(guān)于串口無協(xié)議通訊,以前也有個煩惱。就是接收數(shù)據(jù)有時會把一條數(shù)據(jù)拆成兩條或者兩條數(shù)據(jù)合成一條接收,要進(jìn)行一些處理判斷很是麻煩。這次發(fā)現(xiàn)Serial自帶的讀取功能很全面(可以在Serialport這個類下找到)。于是我直接采用了下面這個函數(shù),再也不用擔(dān)心老是讀錯數(shù)據(jù)了~
//// 摘要:// 一直讀取到輸入緩沖區(qū)中的指定 value 的字符串。//// 參數(shù):// value:// 指示讀取操作停止位置的值。//// 返回結(jié)果:// 輸入緩沖區(qū)中直到指定 value 的內(nèi)容。//// 異常:// T:System.ArgumentException:// 長度 value 參數(shù)為 0。//// T:System.ArgumentNullException:// value 參數(shù)為 null。//// T:System.InvalidOperationException:// 指定的端口未打開。//// T:System.TimeoutException:// 該操作未完成之前超時期限已結(jié)束。public string ReadTo(string value);3、分機(jī)種保存參數(shù)
這個之前有用過讀寫TXT文本,有讀寫過配置文件,也用過自帶的應(yīng)用程序設(shè)置。這次使用的是當(dāng)前機(jī)種存在應(yīng)用程序設(shè)置中,具體機(jī)種數(shù)據(jù)則存在ini文件中。應(yīng)用程序設(shè)置只要配置一下讀取和保存,很簡單。ini文件的讀寫麻煩些,將機(jī)種名設(shè)為Section,將具體的參數(shù)作為key的值。
/// <summary>/// 讀取機(jī)種參數(shù)/// </summary>public void ReadFiles(){try{IniHelper iniHelp = new IniHelper(@".\config.ini", JiZhong);GongDan = iniHelp.ReadIniData(JiZhong, "GongDan" );LiHao = iniHelp.ReadIniData(JiZhong, "LiHao" );LiHaoZhouQi = iniHelp.ReadIniData(JiZhong,"LiHaoZhouQi");DianRongGuiGe = iniHelp.ReadIniData(JiZhong,"DianRongGuiGe");WeiZhi = iniHelp.ReadIniData(JiZhong,"WeiZhi");PiLiang = iniHelp.ReadIniData(JiZhong,"PiLiang");YiChangCiShu = iniHelp.ReadIniData(JiZhong,"YiChangCiShu");ChanLiang = iniHelp.ReadIniData(JiZhong, "ChanLiang");JiZhongs = iniHelp.ReadIniData("JiZhongMing", "JiZhongs");}catch (Exception){MessageBox.Show("未找到配置文件,將使用默認(rèn)配置");}}/// <summary>/// 寫入機(jī)種參數(shù)/// </summary>public void SaveFiles(){string path = @".\config.ini";if(!File.Exists(path)){FileStream fs = new FileStream(path, FileMode.CreateNew);fs.Close();}IniHelper iniHelp = new IniHelper(path, JiZhong);iniHelp.WriteIniData("GongDan" , GongDan);iniHelp.WriteIniData( "LiHao" , LiHao );iniHelp.WriteIniData("LiHaoZhouQi", LiHaoZhouQi );iniHelp.WriteIniData("DianRongGuiGe", DianRongGuiGe);iniHelp.WriteIniData("WeiZhi", WeiZhi );iniHelp.WriteIniData("PiLiang", PiLiang );iniHelp.WriteIniData("YiChangCiShu", YiChangCiShu );iniHelp.WriteIniData( "ChanLiang" , ChanLiang );IniHelper iniHelp1 = new IniHelper(path, "JiZhongMing");iniHelp1.WriteIniData( "JiZhongs", JiZhongs );}4、將數(shù)據(jù)寫入Excel
這涉及到Excel的讀寫,之前了解過,但沒使用過。網(wǎng)上找到了好幾種方案,有使用Office自帶庫的,有使用各種開源軟件的。測試了幾種開源工具,都不得其法,后來看用NPOI的很多,而且不需要安裝Office,功能也很強(qiáng)大,遂決定采用。通過參考案例,發(fā)現(xiàn)還是比較容易使用的。
/// <summary>/// 向Excel中插入行/// </summary>/// <param name="n">在第幾行插入</param>/// <param name="filePath">文件路徑</param>/// <param name="RecordData">插入的數(shù)據(jù)<一維數(shù)組></param>public void InsertRow(int n = 1, string filePath = "D:\\RunData\\test.xlsx", string[] RecordData =null){string fileExt = Path.GetExtension(filePath).ToLower();//獲取擴(kuò)展名IWorkbook workbook;using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)){if (fileExt == ".xlsx") { workbook = new XSSFWorkbook(fs); } else if (fileExt == ".xls") { workbook = new HSSFWorkbook(fs); } else { workbook = null; }if (workbook == null) { return; }ISheet sheet = workbook.GetSheetAt(0);IRow row = sheet.GetRow(n);//獲取第一行if (row != null)//檢查是否有數(shù)據(jù),有數(shù)據(jù)就下移,沒有就直接賦值{//將表格內(nèi)容整體下移sheet.ShiftRows(n, sheet.LastRowNum, 1);}var newrow = sheet.CreateRow(n);int i = 0;foreach (string v in RecordData){ICell cell = newrow.GetCell(i);if (cell == null){cell = newrow.CreateCell(i);}cell.SetCellValue(v);i++;}FileStream out2 = new FileStream(filePath, FileMode.Create);workbook.Write(out2);out2.Close();}}?當(dāng)時測試其它開源工具的時候,發(fā)現(xiàn)往數(shù)據(jù)后面添加行很容易,但想把最新數(shù)據(jù)插入第一行卻不容易,后面才轉(zhuǎn)入NPOI的懷抱,因為它有下面這個函數(shù),很合適。
// 摘要:// Shifts rows between startRow and endRow n number of rows. If you use a negative// number, it will shift rows up. Code ensures that rows don't wrap around. Calls// shiftRows(startRow, endRow, n, false, false); Additionally shifts merged regions// that are completely defined in these rows (ie. merged 2 cells on a row to be// shifted).//// 參數(shù):// startRow:// the row to start shifting//// endRow:// the row to end shifting//// n:// the number of rows to shiftvoid ShiftRows(int startRow, int endRow, int n);總結(jié)
這個項目雖然不大,但相比我以前做的項目,我在盡可能將代碼寫得規(guī)范容易理解。
- 將兩種通訊協(xié)議和讀寫文件的功能都寫成獨立的類,使用的時候?qū)嵗瘜?yīng)類,再調(diào)用方法。
- 將嵌套過多的程序再提取出獨立的方法,讓程序更容易理解,vs中的快速操作和重構(gòu)真的好用。
- 將運行信息和報錯信息,盡可能顯示在界面的信息窗口上(因為總信息量不大,所以在界面上顯示,要不然就直接存為日志了),對前期查BUG和后期查問題都很有用。
- 多次使用了開源工具,比如界面圖標(biāo)用了Sunny.UI,讀Excel用了NPOI,讀ini文件用了IniRW,讓開發(fā)簡單了很多。現(xiàn)在才發(fā)現(xiàn)NuGet這個神器真的不應(yīng)該,對于一些常見的功能實現(xiàn),使用開源工具可以大幅提高工作效率,而且好的工具也更能保證穩(wěn)定性。不過對于使用的開源工具遵循怎樣的開源協(xié)議,不是很明白,有些工具都沒找到要遵守什么協(xié)議,網(wǎng)上查了也不是很明白。關(guān)于這個有解釋清晰的資料的,請留言給我,不勝感激。
- 再次熟悉了委托的使用,因為涉及到多線程的運行信息都顯示到界面上,現(xiàn)在控件自帶了Invoke方法,使用起來比以前更簡單了:
????????而且還一種更簡單的,甚至不用先聲明委托方法,直接一行就可以搞定:
this.textYield.Invoke(new Action<string>(s => { this.textYield.Text = s; }), "運行情況");努力方向
參考文章
- 第三章——NPOI創(chuàng)建/讀取Excel簡單案例https://blog.csdn.net/qq_39541254/article/details/107841535
- SunnyUI的幫助文檔https://gitee.com/yhuse/SunnyUI/wikis/pages
- C# this.Invoke()的作用與用法https://www.cnblogs.com/yunmengyunxi/p/6066262.html
- 使用NPOI實現(xiàn)在Excel第一行插入文字https://blog.csdn.net/yindi0712/article/details/107410929
- ……
總結(jié)
以上是生活随笔為你收集整理的c#实现上位机数据采集的项目总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软超融合服务器,微软推出超融合系统Az
- 下一篇: 前端开发规范参考