串口數據的讀取與顯示


串口數據的讀取與顯示

 

假設有一個一邊,不斷的通過端口發送數據,每八位算作一組,其中有一位的ASCII碼對應字符為“=”,現在要將它顯示到TextBox控件上

現在面臨兩個問題,如何讀取串口數據,如何將串口數據顯示在TextBox上。

為了能夠簡要的說明問題,這里並沒有對接收的數據做特殊處理而只是直接顯示在TextBox控件上。

 

1.串口數據的讀取

讀取串口數據是通過串口控件進行的,在工具箱中選擇SerialPort,將它拖放到窗口控件上就可以了,此時,在串口下端,會顯示串口控件的實例名稱,本例為serialPort1:

SerialPort控件2

 

有了SerialPort控件實例之后,要對它的一些屬性進行設置,但是設置之前首先判斷端口是否打開,如果打開,則先關閉端口,然后才能進行設置,設置完畢后再打開端口。這個過程中用到了SerialPort的下面兩個方法:

  • Open       打開一個新的串行端口連接。
  • Close       關閉端口連接,將 IsOpen 屬性設置為 false,並釋放內部 Stream 對象。

其中有幾個比較重要的屬性:

  • PortName  獲取或設置通信端口,包括但不限於所有可用的 COM 端口。
  • BaudRate  獲取或設置串行波特率。
  • IsOpen      獲取一個值,該值指示 SerialPort 對象的打開或關閉狀態。
  • ReceivedBytesThreshold  獲取或設置 DataReceived 事件發生前內部輸入緩沖區中的字節數。

對應程序如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if  (serialPort1.IsOpen)
{
     serialPort1.Close();
}
//設置波特率為1200
serialPort1.BaudRate = 1200;
//設置端口號,這里使用COM1端口
   serialPort1.PortName = "COM1" ;
//設置 DataReceived 事件發生前內部輸入緩沖區中的字節數為8
serialPort1.ReceivedBytesThreshold = 8;
 
//textChanged += new UpdateTextEventHandler(ChangeText);
 
try
{
     serialPort1.Open();
}
catch  (System.Exception ex)
{
     MessageBox.Show( "未能打開端口,請檢查是否已經連接串口.\n"  + ex.Message);
}

現在已經對SerialPort控件做了一些設置,設置完畢之后,這時如果端口有數據發來,那么就會觸發DataRecieved事件,通過監聽這個事件,就可以對發送過來的數據進行接收。雙擊屬性頁的DataRecieved即可,如圖:

SerialPort控件3事件這樣就會自動添加DataRecieved事件處理函數:

?
1
2
3
private  void  serialPort1_DataReceived( object  sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{           
}

在事件處理函數中,調用SerialPort的Read方法讀取數據,Read方法如下:

名稱 說明
SerialPort.Read (Byte[], Int32, Int32) 從 SerialPort 輸入緩沖區讀取一些字節並將那些字節寫入字節數組中指定的偏移量處。
SerialPort.Read (Char[], Int32, Int32) 從 SerialPort 輸入緩沖區讀取一些字節並將那些字節寫入到字節數組中指定的偏移量處。
 

本程序中我們聲明了一個Byte數組receivedData用來接收串口發送來的數據。要把Byte[]轉化成String可以使用Encoding.ASCII.GetString()方法,它返回String。然后再清空SerialPort控件的Buffer,以便接收后面發來的數據.

?
1
2
3
serialPort1.Read(receivedData, 0, 8);
string  text = Encoding.ASCII.GetString(receivedData);
serialPort1.DiscardInBuffer();

然后再用這個返回的String設置TextBox的Text屬性,但是不能直接在DataRecieved事件處理函數中設置,因為DataRecieved事件處理函數發生在另一個線程中。這就帶來了第二個問題,如何將數據顯示在TextBox上。

 

2.將串口數據的顯示在TextBox上

上面我們已經得到了串口讀取的數據text,也知道不能直接將它在DataRecieved事件處理方法中設置給TextBox,為了能夠將它傳遞給TextBox,我們需要使用窗口類的Invoke方法

通過調用委托(Delegate),並且將參數以數組的形式(Object[])傳遞給委托,就能使用委托里面的方法。

這里使用了委托的概念,本文不對此做深入介紹,簡單來說就是聲明一個委托,再用委托聲明事件,最后將事件處理方法添加給事件即可,但是要注意,添加的事件處理方法的參數列表必須與委托的參數列表相同:

?
1
2
3
4
5
6
7
8
9
//定義委托
     private  delegate  void  UpdateTextEventHandler( string  text);
     //定義事件
     private  event  UpdateTextEventHandler textChanged;
     //事件處理方法
     private  void  ChangeText( string  text)
     {
         textBox1.Text = text; //設置textBox1的Text
     }
?
1
<font face= "微軟雅黑" >在構造方法中,將事件處理方法添加到事件上:</font>
?
1
2
//將事件處理方法添加到事件中去
textChanged += new  UpdateTextEventHandler(ChangeText);

最后,在DataRecieved事件中通過Invoke調用事件:

?
1
this .Invoke(textChanged, new  string [] { text });

這樣就串口發送的數據就能顯示在TextBox控件上了.

SerialPort運行結果 

?
1
//Form1.cs源碼
?
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
namespace  SerialPortTest
{
     public  partial  class  Form1 : Form
     {
         private  byte [] receivedData = new  byte [8];
         //定義委托
         private  delegate  void  UpdateTextEventHandler( string  text);
         //定義事件
         private  event  UpdateTextEventHandler textChanged;
         //事件處理方法
         private  void  ChangeText( string  text)
         {
             textBox1.Text = text;
         }
         public  Form1()
         {
             InitializeComponent();
             if  (serialPort1.IsOpen)
             {
                 serialPort1.Close();
             }
             //設置波特率為1200
             serialPort1.BaudRate = 1200;
             //設置端口號,這里使用COM1端口
             serialPort1.PortName = "COM1" ;
             //設置 DataReceived 事件發生前內部輸入緩沖區中的字節數為8
             serialPort1.ReceivedBytesThreshold = 8;
 
             //將事件處理方法添加到事件中去
             textChanged += new  UpdateTextEventHandler(ChangeText);
 
             try
             {
                 serialPort1.Open();
             }
             catch  (System.Exception ex)
             {
                 MessageBox.Show( "未能打開端口,請檢查是否已經連接串口.\n"  + ex.Message);
             }
 
         }
 
         private  void  serialPort1_DataReceived( object  sender, System.IO.Ports.SerialDataReceivedEventArgs e)
         {           
                 serialPort1.Read(receivedData, 0, 8);
                 string  text = Encoding.ASCII.GetString(receivedData);
                 serialPort1.DiscardInBuffer();
                 this .Invoke(textChanged, new  string [] { text });
         }
         
     }
}
 
 
分類:  C#
 
綠色通道:  好文要頂  關注我  收藏該文 與我聯系 
1
0
 
(請您對文章做出評價)
 
« 博主上一篇: Python學習筆記——String、Sequences
» 博主下一篇: How to Write an ActiveX Control
posted @  2011-03-08 11:05  在路上的理想 閱讀(3392) 評論( 4編輯  收藏
 

 
#1樓   2012-04-24 16:16  一坨黃色   
我用了你的例子在電腦上試了一下,為什么textbox什么都不顯示呢?
#2樓 [ 樓主2012-06-27 08:29  liulixiang   
@一坨黃色
你沒有連接串口,可以從網上下載一個虛擬串口,然后用串口助手與你的程序進行通信即可
#3樓   2012-07-07 12:36  posaty   
樓主的代碼都可以理解。但有一個問題一直不解:我們用網上下載的串口助手每次都可以接受8個字節以上的數據,但無論是Read(char[],0,n)還是ReadExisting()都一次最多只能讀取8字節,而超過8字節就會再次觸發DataReceived事件。雖然ReadLine()可以對字節數沒有限制,但必須要用換行符做結束標志。所以想和樓主交流下:如何一次最多讀取8字節以上的數據?
#4樓 [ 樓主2012-07-09 12:30  liulixiang   
@posaty
設置ReceivedBytesThreshold屬性,這個屬性定義了當緩沖區接收的數據多大時進行觸發DataReceived事件,比如你把它設置為16,那你每次ReadExisting()至少是16個字


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM