C# SerialPort的 DataReceived事件,可能是存在問題,使用時,數據丟失,造成數據不完整。
解決方法思路:
使用獨立線程讀取數據,把串口緩沖區的數據,讀取到程序中。拋開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,自定義方法,串口讀取狀態輸出】
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的參數配置和資源釋放,就先不寫了。這個一般情況下都會。