串口設備數據的接收和處理_第1頁
串口設備數據的接收和處理_第2頁
串口設備數據的接收和處理_第3頁
串口設備數據的接收和處理_第4頁
串口設備數據的接收和處理_第5頁
已閱讀5頁,還剩32頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、工控程序設計工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理3工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理2.2.1 2.2.1 學習要點學習要點 1.知識點:SerialPort類實例的構造,接收串口數據的方法,接收超時異常處理,HSDZC電能綜合測試儀的數據格式,數據幀片段的緩存方法 2.技能點:應用程序項目和SerialPort對象的創建,串口數據接收,接收數據的緩存和數據幀的提取2.2.2 2.2.2 任務描述任務描述 某些串口設備能夠定時、主動地向上位機發送數據,處于上位機端的工業控制程序,需

2、要獲取串口收到的數據并進行分析和處理。利用.NET Framework 2.0及更高版本提供的SerialPort類可以比較方便地在C#應用程序中實現串口通信功能。從編程的角度看,串口數據的接收就是利用SerialPort對象的Read或ReadByte方法將操作系統存放在串口輸入緩沖區中的數據讀入到一個字節數組中。 該教學情景通過串口數據接收、接收數據的緩存、數據幀的提取、浮點數解碼這幾個實施步驟,達到使用SerialPort對象接收單個串口設備(下位機)數據的目的。 4工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理2.2.3 2.2.3 相關知

3、識相關知識 1 SerialPort類實例的構造 SerialPort類是從.NET Framework 2.0版本開始提供的一個串口控制類,該類包含在System.IO.Ports命名空間中,使用該類的實例可以打開串口,并發送數據。 通過構造函數可以產生SerialPort類的實例,SerialPort類的構造函數在定義時進行了重載,表2.2.1中列出了這些重載構造函數的接口定義: 表2.2.1 SerialPort類的構造函數定義表2.2.1 SerialPort類的構造函數定義構造函數的接口定義功能說明public SerialPort();使用默認屬性值創建SerialPort類的新實

4、例,其中數據位數的默認值為 8,校驗位的默認值為 None,停止位的默認值為 1,默認端口名稱為 COM1。5工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理public SerialPort(string portName); 使用指定的端口名稱初始化 SerialPort 類的新實例,其它參數采用默認值 public SerialPort(string portName, int baudRate); 使用指定的端口名稱和波特率初始化 SerialPort 類的新實例,其它參數采用默認值 public SerialPort(string port

5、Name, int baudRate, Parity parity); 使用指定的端口名稱、波特率和奇偶校驗位初始化 SerialPort 類的新實例,其它參數采用默認值 public SerialPort(string portName, int baudRate, Parity parity, int dataBits); 使用指定的端口名稱、波特率、校驗位和數據位初始化 SerialPort 類的新實例,其它參數采用默認值 public SerialPort(string portName, int baudRate, Parity parity, int dataBits, StopB

6、its stopBits); 使用指定的端口名稱、波特率、奇偶校驗位、數據位和停止位初始化SerialPort 類的新實例 6工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 除了在構造SerialPort類實例的時候可以對端口名稱、波特率、奇偶校驗位、數據位和停止位進行設置外,構造好SerialPort類實例后,還可以通過PortName、BaudRate、Parity、DataBits、StopBits屬性對這些參數進行修改,因此構造SerialPort類實例的程序書寫形式比較靈活。 2 2 串口的打開和關閉串口的打開和關閉SerialPort類

7、中與串口打開和關閉相關的成員如下: (1)Open方法Open方法打開新的串口連接,該方法不帶參數,接口定義如下:public void Open() (2)Close方法Close方法關閉已經打開的串口連接,該方法不帶參數,接口定義如下:public void Close()7工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 (3)IsOpen屬性通過IsOpen屬性可以獲知串口當前是否為打開狀態,返回一個bool類型的值,該屬性只讀,接口定義如下: public bool IsOpen get; 串口不能重復進行打開和關閉操作,在打開或關閉串口前

8、,都要使用該屬性檢查串口是否已經處于打開或已經處于關閉狀態,以免引發異常。 3 3 接收串口數據的方法接收串口數據的方法 (1)ReadByte方法 SerialPort類的ReadByte方法可以從串口接收緩沖區中讀取一個字節,該方 法的接口定義是: public int ReadByte(); 該方法從串口接收緩沖區中讀取一個字節,要和ReadTimeout屬性配合使用。當調用ReadByte方法時,如果接收緩沖區中沒有數據,則程序被阻塞,直到緩沖區中有數據或到達ReadTimeout屬性指定讀取數據超時的毫秒數,程序才能繼續運行。8工控程序設計學習情景學習情景2.2 2.2 串口設備數據

9、的接收和處理串口設備數據的接收和處理 ReadByte方法返回一個int類型的值,在實際應用時,要將返回值強制轉換為byte類型。 (2)Read方法Read方法從串口接收緩沖區中讀取多個字節,該方法的接口定義是: public int Read(byte buffer, int offset, int count); 該方法試圖從接收緩沖區中讀取count個字節,并寫入字節數組buffer中,寫入的起始位置是offset,執行后返回實際讀取的字節數。例如,現在接收緩沖區中只有6個字節,但count參數值為10,則返回值為6。 在實際應用時,通常先通過SerialPort對象的BytesToR

10、ead屬性獲得接收緩沖區中已有的字節數,并根據該屬性值來設置count參數。和ReadByte方法不同的是,調用Read方法時,不管接收緩沖區中有無數據,都不會對應用程序的當前線程造成阻塞。9工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理4 4 接收超時異常處理接收超時異常處理 當使用ReadByte方法從接收緩沖區中讀取一個字節時,如果下位機發送過來的數據沒有在ReadTimeout規定的時間內到達,則會引發TimeoutException,應用程序可以捕獲該異常,并作相應處理。下面的測試程序說明了超時異常處理的方法:SerialPort sp;

11、private void btnStart_Click (object sender, EventArgs e) byte firstByte; sp.ReadExisting(); /清空接收緩沖區,準備接收數據 sp.ReadTimeout = 10000; /10秒內沒有收到回復數據,將捕獲到異常 try firstByte = (byte)sp.ReadByte(); /同步讀取(程序在此被阻塞) t1.Text = firstByte.ToString(X2); /顯示在文本框t1中 catch (TimeoutException ex) /捕獲到接收超時異常 t1.Text = e

12、x.Message; /在t1中顯示異常信息 10工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 圖2.2.1 接收超時異常測試 如上圖所示,在點擊“開始”按鈕后,程序被阻塞,此時窗口對鼠標和鍵盤的輸入都不響應。為了有足夠操作時間,SerialPort對象sp的ReadTimeout屬性為10000毫秒(10秒)。在10秒時間內,測試者可以通過串口測試程序發送一個或多個字節過來,此時程序結束阻塞狀態繼續運行,并在文本框中顯示接收到的第1個字節;如果10秒內沒有數據到達,則引發TimeoutException。 若上位機程序要一直等待,可以把Read

13、Timeout屬性的值設置為-1,但在實際應用中一般不這樣做。11工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理5 HSDZC5 HSDZC電能綜合測試儀的數據格式電能綜合測試儀的數據格式 HSDZC電能綜合測試儀在鉆機性能測試系統中用于輸入功率、輸出功率以及功率因素(參見引言介紹)。該設備提供兩種電腦測量方式,在儀表提示“測量方式”時,可以分別按“顯示1”和“顯示2”進入。 在測量方式1的情況下測試儀每秒通過RS-232接口發送1組數據,長度46字節。信號格式:開始4字節均為FFH,后續每三個字節構成一個浮點數值,分別表示I1、U1、I2、U2、

14、I3、U3,以及功率因數、視在功率、效率、輸入功率、無功功率、負載率、輸出功率、轉速,共14個數據。 在測量方式2的情況下測試儀也是每秒通過RS-232接口發送1組數據,長度30字節。信號格式:開始3字節均為12H、34H、56H,后續每三個字節構成一個浮點數值,分別表示I1、U1、P1、I2、U2、P2、I3、U3、P3,共9個數據。 上位機在和HSDZC電能綜合測試儀進行通信時,不需要向設備寫入數據,而是被動地讀取設備發送過來的數據。下面的相關知識將進一步介紹對已接收到數據的存儲和處理方法。12工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理構成

15、浮點數值的3個字節含義是:第1字節(B1)為尾數低位,第2字節(B2)為尾數高位,第3字節(B3)為階碼指數。其中階碼指數各位的含義如表2.2.2所示: 表2.2.2 階碼指數字節中各位的含義D7 D6 D5-D0 數值符號:0為正,1為負 階碼符號:0為正,1為負 階碼數值 13工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 尾數B的值在0到1之間,計算公式是: 下面的HexToFloat函數描述了將3個字節轉換為浮點數的算法:private float HexToFloat(byte B1, byte B2, byte B3) float f,

16、 B, n; /B:尾數 n:階碼指數 B = (B2 * 256 + B1) / 65536F; if (B3 & 0 x80) != 0) /如果D7為1,等價于 if(B3=128) B = -B; B3 = (byte)(B3 & 0 x7F); /等價于B3=(byte)(B3-128) if (B3 & 0 x40) != 0) /如果D6為1 B3 = (byte)(B3 & 0 xBF); n = -B3; else n = B3; f = B * (float)Math.Pow(2, n); /B乘以2的n次方 return f;6553612

17、562BBB14工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理6 6 數據幀片段的緩存方法數據幀片段的緩存方法 (1)使用集合類存儲接收數據 在通信過程中,數據幀表示由多個字節構成的,具有一定格式,表示完整語意的一組數據。例如,在和HSDZC電能綜合測試儀進行通信時,如果測試儀工作在測量方式1,則一幀數據的長度為46個字節(包含起始標志和14個數值)。 在系統實際運行中,下位機向上位機發送數據時,可能會將數據幀分為幾個片段依次發送,或者在一次接收到的數據中包含了不止一幀數據。上位機必須提供一個字節的集合來對接收到的數據進行緩存(暫存),在確認接收完

18、畢一幀數據后,再進行進一步的分析和處理。 .NET Framework 2.0以上版本提供了List類來實現集合元素管理。List類支持泛型,在存取byte類型的集合元素時無需進行“裝箱”和“拆箱”操作,比使用ArrayList效率高。15工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 List類提供了豐富的方法來對集合中的元素進行操作,表2.2.3列出了List類的常用方法,表中的示例建立在如下定義的基礎上: byte b; byte ba; List li = new List(); /創建List類的實例li,元素類型為byte 表2.2.3

19、 List類的常用方法方法的接口定義 功能說明 示 例 public void Add(T item); 在集合末尾添加元素item li.Add(b); 16工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理public void AddRange( IEnumerable collection); 在集合末尾添加另一個集合collection li.AddRange(ba); public void Insert(int index, T item); 在index位置插入元素item li.Insert(0,b) public void Inse

20、rtRange(int index, IEnumerable collection); 在index位置插入另一個集合collection li.InsertRange(0,ba) public void RemoveAt(int index); 刪除下標位置index處的元素 li.RemoveAt(2); public void RemoveRange(int index, int count); 刪除從下標位置index開始的count個元素 li.RemoveRange(2,3); public void Clear(); 刪除集合中的所有元素 li.Clear(); 17工控程序設計

21、學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理public T thisint index get; set; 獲取或設置下標為index的元素值 li3=b;b=li3; public int IndexOf(T item); 自左向右查找值為item的第一個元素,返回其下標 idx=li.IndexOf(0 x7F); public int IndexOf(T item, int index); 從下標位置index開始,自左向右查找值為item的第一個元素,返回其下標 idx=li.IndexOf(0 x7F,3); public int LastInd

22、exOf(T item);自右向左查找值為item的第一個元素,返回其下標 idx=li.LastIndexOf (0 x7F);public int LastIndexOf (T item, int index); 從下標位置index開始,自右向左查找值為item的第一個元素,返回其下標 idx=li.LastIndexOf (0 x7F,3); 18工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 (2)集合大小的設置 為了保證集合中任何時候能容納一個完整的數據幀,集合中能容納的字節數量應為數據幀長度的兩倍。集合中的數據采取隊列形式進行處理,新

23、來的數據從隊尾進,如果原有數據字節數加上新接收字節數超過集合的最大容量,則將隊首的部份數據刪除。圖2.2.2展示數據入隊和出隊的過程: L-隊列總容量 N-原有字節數 M-新接收字節數 (1)隊列剩余空間能容納新接收數據 L-隊列總容量 N-原有字節數 M-新接收字節數 (2)隊列剩余空間能容納新接收數據 圖2.2.2 新接收數據的緩存19工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理2.2.4 任務實施任務實施 1應用程序項目的創建應用程序項目的創建 串口通信應用程序的開發在Visual Studio集成開發環境中進行,首先創建一個基于C#語言的

24、“Windows應用程序”項目,名為“ReceiveData”,并存放在工作目錄“F:SerialPort”下,如圖2.2.3所示:20工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 2 2 SerialPortSerialPort對象的創建對象的創建 創建SerialPort對象可以通過添加控件和編寫代碼兩種方式,添加控件的方式相對簡單,適合初學者練習;編寫代碼的方式具有較強的靈活性,可以把SerialPort對象對串口的操作細節隱藏起來,與數據編碼、解碼等功能一起封裝為一個功能完整的串口通信模塊。 (1)通過添加控件創建SerialPort對象

25、在“工具箱”中展開“組件”選項卡,選擇“SerialPort”組件(如圖 2.2.4),用鼠標拖動到設計視圖中的窗口上。由于SerialPort是不可見組件,所以不直接出現在窗體上,而是出現在窗口下方,如圖2.2.5所示。該操作的實質是在窗體設計器的源代碼(文件名Form1.Designer.cs)中添加了如下代碼:private System.IO.Ports.SerialPort serialPort1;this.serialPort1 = new System.IO.Ports.SerialPort(ponents);實質上是定義并實例化了一個名為serialPort1的SerialPo

26、rt對象。 21工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 (2)編寫代碼創建SerialPort對象 切換到代碼視圖,在Form1.cs中編寫上述代碼同樣可以創建SerialPort對象。首先在最前面引入System.IO.Ports命名空間: using System.IO.Ports; 然后定義SerialPort類的對象sp,作為Form1類的私有成員: private SerialPort sp; 最后在Form1類的構造函數中創建對象: public Form1() InitializeComponent(); sp = new S

27、erialPort(); 22工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 2.2.4 選擇SerialPort組件23工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 2.2.5 將SerialPort組件加入窗體中當然,工程實踐中,SerialPort對象不一定在窗體類中定義。如果項目代碼量大,可以專門建立一個負責串口通信和調度的類,在里面定義一個或多個SerialPort對象作為該類的成員。24工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理3 3 串口

28、數據的接收串口數據的接收 在下面的程序中,當點擊“開始接收”按鈕時,程序調用SerialPort對象的ReadByte方法,阻塞當前線程,并開始接收下位機發送的數據。如果在10秒內接收到數據,則將接收到的數據以十六進制方式顯示在文本框中,否則在文本框中顯示“操作超時”異常提示。 在編寫程序之前,先在系統中安裝虛擬串口對COM1和COM2,本程序連接COM1,串口測試程序連接COM2。程序界面如下圖: 圖2.2.6 串口數據的接收25工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理其中文本框名字為t1,按鈕名字為btnStart,對應的后臺代碼如下:p

29、rivate SerialPort sp;private void Form1_Load(object sender, EventArgs e) sp = new SerialPort(COM1, 9600, Parity.None, 8, StopBits.One); sp.Open();private void Form1_FormClosing(object sender, FormClosingEventArgs e) if (sp != null & sp.IsOpen) sp.Close(); /關閉串口private void btnStart_Click(object

30、sender, EventArgs e) byte first; byte tmp; sp.ReadTimeout = 10000; /10秒內沒有收到回復數據,將捕獲到異常 try26工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 first = (byte)sp.ReadByte(); /同步讀取(程序在此被阻塞) tmp = new bytesp.BytesToRead + 1; tmp0 = first; sp.Read(tmp, 1, tmp.Length - 1); /讀取剩余字節到tmp數組中 /接收的數據以十六進制形式顯示在文本框t

31、1中 t1.Text = CCheck.BinaryToHexString(tmp); catch (TimeoutException ex) t1.Text = ex.Message; /在文本框t1中顯示異常信息 27工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理/以下代碼包含在CCheck類中:public class CCheck /字節數組轉換為十六進制字符串 public static string BinaryToHexString(byte buff) StringBuilder tmp = new StringBuilder();

32、 for (int i = 0; i buff.Length; i+) tmp.Append(buffi.ToString(X2) + ); return tmp.ToString().Trim(); 28工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 該程序在點擊“開始接收”按鈕后會停止對用戶輸入的響應,這是因為調用ReadByte方法造成當前線程被阻塞,直到下位機發送的數據到達,或接收超時才解除阻塞。 實際操作時,先運行該程序,再打開串口測試工具,并連接COM2,在測試工具中輸入一些數據,做好發送的準備工作。在程序點擊“開始接收”按鈕后,立即切

33、換到串口測試工具,并點擊“發送”按鈕,就可以在程序中看到發送過來的數據。“發送”操作要在10秒內完成,否則會引起“接收超時”異常。4 4接收數據的緩存和數據幀的提取接收數據的緩存和數據幀的提取 (1)創建數據接收隊列 CRecvBuf是一個用于緩存接收數據的類,利用List類來實現。在創建該類的實例時,要指定參數maxLength,表示隊列的總容量(即圖2.2.1中的參數L)。每當接收到一段數據,就調用Add方法將收到的數據添加到隊列中,Add方法中判斷添加數據后字節數是否超過maxLength,并將超出部份從隊首刪除。29工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串

34、口設備數據的接收和處理class CRecvBuf public List li; public int maxLength; public CRecvBuf(int maxLength) li = new List(); this.maxLength = maxLength; public void Add(byte b) if (b.Length maxLength) throw new Exception(接收到的數據量超出緩沖區長度); li.AddRange(b); if (li.Count maxLength) li.RemoveRange(0, li.Count - maxLen

35、gth); 30工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理(2) 使用數據接收隊列 當HSDZC電能綜合測試儀工作在“測量方式2”的情況下,使用下面的程序可以接收數據,并使用前面設計的CRecvBuf類的實例緩存接收到的數據,再從中提取出一個完整數據幀。程序運行界面如圖2.2.7: 2.2.7 利用隊列緩存接收數據31工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 當按下“開始”按鈕時,上位機準備接收數據,等待時間為10秒,此時通過串口測試程序按HSDZC電能綜合測試儀工作在“測量方式2”時的數據格

36、式,向上位機發送一個數據片段。上位機采用3個步驟處理接收數據:第1步接收到下位機發送的數據;第2步將接收的數據添加到隊列中;第3步從隊列中根據起始標志和約定數據長度提取出一個完整的數據幀,后臺代碼如下:private SerialPort sp;private CRecvBuf recvBuf;private void btnStart_Click(object sender, EventArgs e) byte firstByte; byte tmp; sp.ReadTimeout = 10000; /10秒內沒有收到回復數據,將捕獲到異常 try firstByte = (byte)sp.

37、ReadByte(); /讀取第1個回復字節(程序在此被阻塞)32工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 tmp = new bytesp.BytesToRead + 1; tmp0 = firstByte; sp.Read(tmp, 1, tmp.Length - 1); /讀取剩余字節到tmp數組中 t1.Text = CCheck.BinaryToHexString(tmp); /接收數據顯示在文本框t1中 recvBuf.Add(tmp); /添加接收數據到隊列中 /顯示隊列中的全部數據 t2.Text = CCheck.BinaryToHexString(recvBuf.getAllData(); /提取一個完整的數據幀 tmp = getBlock(recvBuf.li); if (tmp != null) t3.Text = CCheck.BinaryToHexString(tmp); /顯示在文本框t3中 else t3.Text = ; 33工控程序設計學習情景學習情景2.2 2.2 串口設備數據的接收和處理串口設備數據的接收和處理 catch (TimeoutException ex) t1.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論