C# SerialPort的 DataReceived事件,多是存在問題,使用時,數據丟失,形成數據不完整。ui
解決方法思路:spa
使用獨立線程讀取數據,把串口緩衝區的數據,讀取到程序中。拋開DataReceived事件。線程
使用其它線程獲取「串口中讀取的數據」再進行解析。對象
客戶程序由被動觸發,改成主動獲取。隊列
相關變量、對象事件
C# Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/// <summary> /// 保持讀取開關 /// </summary> bool _keepReading; /// <summary> /// 檢測頻率【檢測等待時間,毫秒】【按行讀取,能夠不用】 /// </summary> int _jcpl = 1 ; /// <summary> /// 串口 /// </summary> SerialPort _sp = new SerialPort(); /// <summary> /// 字符串隊列【.NET Framework 4.0以上】 /// </summary> ConcurrentQueue< string > _cq = new ConcurrentQueue< string >(); /// <summary> /// 字節數據隊列 /// </summary> ConcurrentQueue< byte []> _cqBZ = new ConcurrentQueue< byte []>(); |
串口讀取方法【ViewCommStatus,自定義方法,串口讀取狀態輸出】ci
C# Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
/// <summary> /// 串口讀取方法 /// </summary> void SerialPortRead() { while (_keepReading) { if (_jcpl > 0 ) //按行讀取能夠省略 { Thread.Sleep(_jcpl); } if (_sp == null ) { ViewCommStatus( false , "串口對象未實例化!" ); Thread.Sleep( 3000 ); //3秒後從新檢測 continue ; } if (!_sp.IsOpen) { ViewCommStatus( false , "串口未打開" ); Thread.Sleep( 3000 ); continue ; } try { #region 按行讀取 string buffer = _sp.ReadLine(); if (! string .IsNullOrEmpty(buffer)) //能夠不加判斷,容許添加null值,數據解析時,再作判斷。 { _cq.Enqueue(buffer); } #endregion //#region 字節讀取 //byte[] readBuffer = new byte[_sp.ReadBufferSize + 1]; //int count = _sp.Read(readBuffer, 0, _sp.ReadBufferSize); //if (count != 0) //{ // _cqBZ.Enqueue(readBuffer); //} //#endregion ViewCommStatus( true , "串口通訊正常" ); } catch (TimeoutException) //注意超時時間的定義 { ViewCommStatus( false , "串口讀取超時!" ); } catch (Exception ex) //排除隱患後能夠去掉。 { ViewCommStatus( false , "串口讀取異常:" + ex.Message); } } } |
數據解析方法資源
C# Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/// <summary> /// 數據解析 /// </summary> void DataAnalysis() { while ( true ) { Thread.Sleep( 10 ); if (_cq.IsEmpty) { continue ; } #region 按行讀取 for ( int i = 0 ; i < _cq.Count; i++) { string strTmp = "" ; _cq.TryDequeue( out strTmp); //解析strTmp //解析strTmp //解析strTmp } #endregion #region 按字節讀取 //StringBuilder sb = new StringBuilder(); //for (int i = 0; i < _cq.Count; i++) //{ // byte[] bt = null; // _cqBZ.TryDequeue(out bt); // string strTmp = System.Text.Encoding.ASCII.GetString(bt); // sb.Append(strTmp); //} ////解析sb ////解析sb ////解析sb #endregion } } |
調用示例字符串
C# Code
1
2 3 4 5 6 7 8 9 10 11 |
void
StartRead() { _keepReading = true ; Thread trdRead = new Thread(SerialPortRead); trdRead.Start(); Thread trdDataAnalysis = new Thread(DataAnalysis); trdDataAnalysis.Start(); } |
SerialPort的參數配置和資源釋放,就先不寫了。這個通常狀況下都會。string