亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

.Net?Core的CustomSerialPort()怎么用

發布時間:2022-01-15 16:06:14 來源:億速云 閱讀:154 作者:iii 欄目:開發技術

這篇文章主要介紹“.Net Core的CustomSerialPort()怎么用”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“.Net Core的CustomSerialPort()怎么用”文章能幫助大家解決問題。

    摘要

    在使用SerialPort進行串口協議解析過程中,經常遇到接收單幀協議數據串口接收事件多次觸發,協議解析麻煩的問題。針對此情況,基于開源跨平臺串口類庫SerialPortStrem進行了進一步封裝,實現了一種接收超時響應事件機制,簡化串口通訊的使用。

    引言

    最近,寫了一篇博文《.net core跨平臺應用研究-串口篇》得到了一些園友的好評,文中介紹了在跨平臺應用研究過程中,在dotnet core下使用SerialPort類庫在linux下不能支持的踩坑經歷及解決辦法。

    因網上關于SerialPort類庫使用的相關文章較多,在該文中,對串口類庫的使用,一筆帶過。但在實際使用,使用過SerialPort類庫的同學,可能遇到過在數據接收時,由于數據接收事件的觸發具有不確定性,很多時候,一幀通訊協議數據,會多次觸發,造成程序處理協議數據較為麻煩的問題。

    為簡化串口通訊類庫的使用,筆者結合自己的相關經驗,封裝了一個自定義增強型跨平臺串口類庫,以解決一幀協議數據,多次觸發的問題。

    基礎類庫的選擇

    由于考慮的是跨平臺應用,SerialPort類庫并不支持linux系統(在前一篇文章中已介紹過踩坑經歷),筆者選用了SerialPortStream類庫進行封裝。

    該類庫支持windows系統和Linux系統,但在Linux系統下運行,需要額外編譯目標平臺支持庫并進行相關環境配置。

    相關編譯配置說明在https://github.com/jcurl/SerialPortStream已有介紹,也可參考本人的拙作《.net core跨平臺應用研究-串口篇》

    類庫的實現

    創建跨平臺類庫

    為了支持跨平臺,我們使用Visual Studio 2017創建一個基于.NET Standard的類庫。

    .Net?Core的CustomSerialPort()怎么用

    NET Standard是一項API規范,每一個特定的版本,都定義了必須實現的基類庫。

    .NET Core是一個托管框架,針對構建控制臺、云、ASP.NET Core和UWP應用程序進行了優化。

    每一種托管實現(如.NET Core、.NET Framework或Xamarin)都必須遵循.NET Standard實現基類庫(BCL)。

    關于NET Standard和跨平臺的詳細說明在此:

    //www.mlszssj.com/article/234699.htm

    筆者也不再啰嗦呵。

    實現機制/條件

    通常串口通訊中,發送數據后,會有一段時間用于等待接收方應答,如此一來,兩次數據發送之間,必然會有一定的時間間隔。如ModbusRTU協議就規定,兩次數據報文發送之間,需要等待超過發送4個字節以上的間隔時間。

    筆者在單片機以及實時性較高的嵌入式系統中,為處理串口接收與協議的無關性,通常采用數據幀接收超時來處理數據幀的接收。根據串口通訊的速率計算出兩次通訊之間所需要超時間隔,取兩倍超時間隔時間作為超時參數,每接收到一個字節,將數據放入緩沖區并進行計時,當最后一個字節的接收時間超過超時時間,返回接收數據并清空緩存,一次完整接收完成(DMA接收方式不在此討論)。

    .net core跨平臺實現

    在自定義的串口類中,訂閱基礎串口類數據接收事件,在接收事件每次觸發后,讀出當前可用的緩沖數據到自定義緩沖區,同時,標記最后接收時間Tick為當前系統Tick。判斷是否開啟了接收超時處理線程,如未開啟,則開啟一個接收超時處理線程。

    接收超時處理線程中,以一個較小的時間間隔進行判斷,如果最后接收時間與當前時間之間的間隔小于設置值(默認128ms),休眠一段時間(默認16ms)后循環檢查。如間隔時間大于設定值,觸發外部接收訂閱事件,傳出接收到的數據,退出超時處理線程。

    此處應有流程圖。呵呵,懶得畫了,大家自行腦補吧。 ^_^

    在windows系統或linux系統中,因系統的多任務處理的特性,系統實時性較差,通常50ms以下時間間隔的定時任務,較大程度會出現不可靠的情況(任務執行時間都有可能超過調用間隔時間)。

    因此,默認超時時間間隔設置為128ms。也可根據實際使用情況調整,但最小間隔不宜低于64ms。

    注:此處為個人經驗和理解,如不認同,請直接忽視。

    主要代碼

    串口接收事件代碼:

             protected void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
             {
                 int canReadBytesLen = 0;
                 if (ReceiveTimeoutEnable)
                 {
                     while (sp.BytesToRead > 0)
                     {
                         canReadBytesLen = sp.BytesToRead;
                         if (receiveDatalen + canReadBytesLen > BufSize)
                         {
                             receiveDatalen = 0;
                             throw new Exception("Serial port receives buffer overflow!");
                         }
                         var receiveLen = sp.Read(recviceBuffer, receiveDatalen, canReadBytesLen);
                         if (receiveLen != canReadBytesLen)
                         {
                             receiveDatalen = 0;
                             throw new Exception("Serial port receives exception!");
                         }
                         //Array.Copy(recviceBuffer, 0, receivedBytes, receiveDatalen, receiveLen);
                         receiveDatalen += receiveLen;
                         lastReceiveTick = Environment.TickCount;
                         if (!TimeoutCheckThreadIsWork)
                         {
                             TimeoutCheckThreadIsWork = true;
                             Thread thread = new Thread(ReceiveTimeoutCheckFunc)
                             {
                                 Name = "ComReceiveTimeoutCheckThread"
                             };
                             thread.Start();
                         }
                     }
                 }
                 else
                 {
                     if (ReceivedEvent != null)
                     {
                         // 獲取字節長度
                         int bytesNum = sp.BytesToRead;
                         if (bytesNum == 0)
                             return;
                         // 創建字節數組
                         byte[] resultBuffer = new byte[bytesNum];
     
                         int i = 0;
                         while (i < bytesNum)
                         {
                             // 讀取數據到緩沖區
                             int j = sp.Read(recviceBuffer, i, bytesNum - i);
                             i += j;
                         }
                         Array.Copy(recviceBuffer, 0, resultBuffer, 0, i);
                         ReceivedEvent(this, resultBuffer);
                         //System.Diagnostics.Debug.WriteLine("len " + i.ToString() + " " + ByteToHexStr(resultBuffer));
                     }
                     //Array.Clear (receivedBytes,0,receivedBytes.Length );
                     receiveDatalen = 0;
                 }
             }

    接收超時處理線程代碼:

             /// <summary>
             /// 超時返回數據處理線程方法
             /// </summary>
             protected void ReceiveTimeoutCheckFunc()
             {
                 while (TimeoutCheckThreadIsWork)
                 {
                     if (Environment.TickCount - lastReceiveTick > ReceiveTimeout)
                     {
                         if (ReceivedEvent != null)
                         {
                             byte[] returnBytes = new byte[receiveDatalen];
                             Array.Copy(recviceBuffer, 0, returnBytes, 0, receiveDatalen);
                             ReceivedEvent(this, returnBytes);
                         }
                         //Array.Clear (receivedBytes,0,receivedBytes.Length );
                         receiveDatalen = 0;
                         TimeoutCheckThreadIsWork = false;
                     }
                     else
                         Thread.Sleep(16);
                 }
             }

    創建.net core控制臺程序

    為驗證我們的類庫是否能夠正常工作,我們創建一個使用類庫的.net core控制臺程序。

    為啥選擇dotnet core,原因很簡單,跨平臺。本程序分別需在windows和linux系統下進行運行測試。

    •     顯示系統信息(系統標識、程序標識等)

    •     列舉系統可用串口資源

    •     選擇串口

    •     打開串口/關閉串口

    •     串口測試(打開/發送/關閉)

             static void Main(string[] args)
             {
                 SetLibPath();
                 ShowWelcome();
     
                 GetPortNames();
                 ShowPortNames();
     
                 if (serailports.Length == 0)
                 {
                     Console.WriteLine($"Press any key to exit");
                     Console.ReadKey();
     
                     return;
                 }
     #if RunIsService
                 RunService();
     #endif
     
                 bool quit = false;
                 while (!quit)
                 {
                     Console.WriteLine("\r\nPlease Input command Key\r\n");
                     Console.WriteLine("p:Show SerialPort List");
                     Console.WriteLine($"t:Test Uart:\"{selectedComPort}\"");
                     Console.WriteLine($"o:Open Uart:\"{selectedComPort}\"");
                     Console.WriteLine($"c:Close Uart:\"{selectedComPort}\"");
                     Console.WriteLine("n:select next serial port");
                     Console.WriteLine("q:exit app");
                     Console.WriteLine();
                     var key = Console.ReadKey().KeyChar;
                     Console.WriteLine();
     
                     switch (key)
                     {
                         case (Char)27:
                         case 'q':
                         case 'Q':
                             quit = true;
                             break;
                         case 's':
                             ShowWelcome();
                             break;
                         case 'p':
                             ShowPortNames();
                             break;
                         case 'n':
                             SelectSerialPort();
                             break;
                         case 't':
                             TestUart(selectedComPort);
                             break;
                         case 'w':
                             TestWinUart(selectedComPort);
                             break;
                         case 'o':
                             OpenUart(selectedComPort);
                             break;
                         case 'c':
                             CloseUart();
                             break;
                     }
                 }
             }

    筆者使用類庫是直接引用類庫項目,大家需要使用的話,可在解決方案資源管理器中,項目的依賴項上點擊右鍵

    .Net?Core的CustomSerialPort()怎么用

    在NuGet包管理器中,搜索SerialPort或flyfire即可找到并安裝本類庫。

    .Net?Core的CustomSerialPort()怎么用

    類庫地址

    類庫地址:https://www.nuget.org/packages/flyfire.CustomSerialPort

    .Net?Core的CustomSerialPort()怎么用

    跨平臺測試

    Windows測試輸出界面

    .Net?Core的CustomSerialPort()怎么用

    .Net?Core的CustomSerialPort()怎么用

    ubuntu測試輸出界面

    .Net?Core的CustomSerialPort()怎么用

    關于“.Net Core的CustomSerialPort()怎么用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    登封市| 桂阳县| 色达县| 阳信县| 米脂县| 沙坪坝区| 垦利县| 大名县| 海南省| 岑巩县| 方山县| 梅州市| 镇原县| 依安县| 松溪县| 陆丰市| 嵩明县| 清远市| 瑞金市| 界首市| 射阳县| 泗洪县| 永年县| 渭南市| 田林县| 兰西县| 格尔木市| 洪雅县| 郓城县| 平乡县| 吴忠市| 九江市| 昭苏县| 海伦市| 若尔盖县| 新昌县| 海南省| 临城县| 株洲县| 洱源县| 平塘县|