日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

c#实现上位机数据采集的项目总结

發(fā)布時間:2024/3/24 C# 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c#实现上位机数据采集的项目总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

功能要求

  • 采集來自PLC的生產(chǎn)數(shù)據(jù)和報警信息
  • 采集來自測試儀的測試數(shù)據(jù)
  • 可以分機種保存一些參數(shù)
  • 將采集的數(shù)據(jù)寫入Excel,供MES系統(tǒng)查詢和現(xiàn)場查看
  • 項目實現(xiàn)

    1、采集PLC數(shù)據(jù)

    硬件采用RS232串口,通訊協(xié)議使用ModusbusRTU。以前跟PLC通訊,為求簡單,一般直接使用無協(xié)議,使用倒沒問題,但偶爾出現(xiàn)數(shù)據(jù)丟失也是煩人,要確保對方接收到數(shù)據(jù)還要雙方寫返回數(shù)據(jù)。使用modbus協(xié)議,PLC基本不用寫通訊程序,而上位機可以直接自己確認對方是否收到數(shù)據(jù),再確認是否給對方重發(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ù)合成一條接收,要進行一些處理判斷很是麻煩。這次發(fā)現(xiàn)Serial自帶的讀取功能很全面(可以在Serialport這個類下找到)。于是我直接采用了下面這個函數(shù),再也不用擔心老是讀錯數(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、分機種保存參數(shù)

    這個之前有用過讀寫TXT文本,有讀寫過配置文件,也用過自帶的應(yīng)用程序設(shè)置。這次使用的是當前機種存在應(yīng)用程序設(shè)置中,具體機種數(shù)據(jù)則存在ini文件中。應(yīng)用程序設(shè)置只要配置一下讀取和保存,很簡單。ini文件的讀寫麻煩些,將機種名設(shè)為Section,將具體的參數(shù)作為key的值。

    /// <summary>/// 讀取機種參數(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("未找到配置文件,將使用默認配置");}}/// <summary>/// 寫入機種參數(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,功能也很強大,遂決定采用。通過參考案例,發(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();//獲取擴展名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();}}

    ?當時測試其它開源工具的時候,發(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和后期查問題都很有用。
    • 多次使用了開源工具,比如界面圖標用了Sunny.UI,讀Excel用了NPOI,讀ini文件用了IniRW,讓開發(fā)簡單了很多?,F(xiàn)在才發(fā)現(xiàn)NuGet這個神器真的不應(yīng)該,對于一些常見的功能實現(xiàn),使用開源工具可以大幅提高工作效率,而且好的工具也更能保證穩(wěn)定性。不過對于使用的開源工具遵循怎樣的開源協(xié)議,不是很明白,有些工具都沒找到要遵守什么協(xié)議,網(wǎng)上查了也不是很明白。關(guān)于這個有解釋清晰的資料的,請留言給我,不勝感激。
    • 再次熟悉了委托的使用,因為涉及到多線程的運行信息都顯示到界面上,現(xiàn)在控件自帶了Invoke方法,使用起來比以前更簡單了:
    private delegate void ExecuteWork(string str);private void test(){this.textReceive.Invoke(new ExecuteWork(RecRunData), "運行異常");}private void RecRunData(string reda){if (reda != lastData&&reda.Length>0){string tim = DateTime.Now.ToLongTimeString() + "." + DateTime.Now.Millisecond.ToString() + "--";textReceive.Text = tim + reda + "\n" + textReceive.Text;lastData = reda;}}

    ????????而且還一種更簡單的,甚至不用先聲明委托方法,直接一行就可以搞定:

    this.textYield.Invoke(new Action<string>(s => { this.textYield.Text = s; }), "運行情況");

    努力方向

  • 了解開源工具的使用規(guī)范,對工具的使用有清晰明確地把握
  • 繼續(xù)學(xué)習(xí)c#的編程知識,并將學(xué)到的東西在項目中應(yīng)用起來
  • 多閱讀開源工具的源代碼,提升自己的編程思維
  • 參考文章

    • 第三章——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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。