C# SerialPort串口接收 丟數據 數據不完整的解決方法

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

相關文章
相關標籤/搜索