[VB.Net]Serialport 接收溢位 超過127 (7FH) 顯示 "?" 3FH 的錯誤解決方法

最近在寫dsPIC專題使用UART與電腦通訊,在程式上遇到了一個之前沒遇過的問題。
就是一般在通訊使用上接收回來的值都介於00H~7FH,由 80H 到 FFH 共 128 個字元,一般稱為『擴充字元』,這 128 個擴充字元是由 IBM 制定的,並非標準的 ASCII 碼。這些字元是用來表示框線、音標和其他歐洲非英語系的字母。

一般通訊設定Serialport時是不會設定Serialport.Encoding,而使用SerialPort1.ReadExisting()來接收資料。
在這個時候只要超過7FH的值都會被判斷為ASCII的?,解析成16進制就會變成3fH或十進制的63
從前的程式碼如下:

'開啟PORT
Private Sub btnOpenPort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpenPort.Click
      SerialPort1.PortName = cmbPort.SelectedItem.ToString 'COMPORT Name
      SerialPort1.BaudRate = 9600
      SerialPort1.Parity = Parity.None
      SerialPort1.DataBits = 8
      SerialPort1.StopBits = StopBits.One
      SerialPort1.Open()               '開啟串列埠
End Sub


'ASCII轉HEX(另外一篇有說明)
   Public Function AsciiStringToHexString(ByVal asciiString As String) As Array
        Dim ascii() As Byte = System.Text.Encoding.Default.GetBytes(asciiString)
        Dim count As Integer = ascii.Length
        Dim hexArray(count - 1) As String
        For idx As Integer = 0 To count - 1
            hexArray(idx) = ascii(idx).ToString("x2")
        Next
        Return hexArray 'String.Join(" ", hexArray)
    End Function


'時間延遲
 Public Sub TimeDelay(ByVal DT As Integer)
        Dim StartTick As Integer
        StartTick = Environment.TickCount() '開始計數前的Tick
        Do
            If Environment.TickCount() - StartTick >= DT Then Exit Do
            Application.DoEvents()  '處理佇列中的訊息
        Loop
    End Sub

  '********************************************
  '傳送按鈕的Click事件
  '使用Write方法送出資料
  '********************************************
  Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        SerialPort1.ReadExisting()
        Dim aa As String
        Dim bb() As String
        SerialPort1.Write(txtSend.Text)
        TimeDelay(500)
        aa = SerialPort1.ReadExisting()
        bb = AsciiStringToHexString(aa)
        txtReceive.Text = String.Join(",", bb)
  End Sub 


用通訊擷取軟體可以看到傳送出41的命令,回傳01,00,00,00,89,37,A9的值

然後下列是軟體收到的訊息,傳送A的ASCII(41H),結果接收到如下圖01,00,00,00,3f,37,3f
原因在於接受到的倒數第一個和倒數第三個數值都超過了7FH,所以會顯示3f的訊息出來。在程式中顯示的ASCII為?  ,也就是無法辨識(溢位)

問題點就如開頭所講的80H~FFH是非標準的ASCII(擴充字元),所以我們在串列埠要做一些設定。

首先在開啟Serialport前要先設定
SerialPort1.Encoding = System.Text.Encoding.GetEncoding("iso-8859-1")

在ASCII轉HEX
Dim ascii() As Byte = System.Text.Encoding.Default.GetBytes(asciiString)
要改成
Dim ascii() As Byte = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(asciiString)

參考網址(我查到這個指令的網址):
http://www.dreamincode.net/forums/topic/79400-receive-hex-data-through-serial-port/
http://msmvps.com/blogs/peplluis/archive/2008/10/15/system-io-ports-serialport-conversiones-y-codificaciones.aspx

在第一組網址呢是要我們使用System.Text.Encoding.GetEncoding("Windows-1252")
但是後來我去查了一下,這個指令僅支援80H~9FH(http://en.wikipedia.org/wiki/ISO/IEC_8859-1)
所以我們就使用 System.Text.Encoding.GetEncoding("iso-8859-1")


'開啟PORT
Private Sub btnOpenPort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpenPort.Click
      '====設定編碼====
      SerialPort1.Encoding = System.Text.Encoding.GetEncoding("iso-8859-1")

      SerialPort1.PortName = cmbPort.SelectedItem.ToString 'COMPORT Name
      SerialPort1.BaudRate = 9600
      SerialPort1.Parity = Parity.None
      SerialPort1.DataBits = 8
      SerialPort1.StopBits = StopBits.One
      SerialPort1.Open()               '開啟串列埠
End Sub


'ASCII轉HEX(另外一篇有說明)
   Public Function AsciiStringToHexString(ByVal asciiString As String) As Array
        Dim ascii() As Byte = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(asciiString)   '修改後的編碼定義
        Dim count As Integer = ascii.Length
        Dim hexArray(count - 1) As String
        For idx As Integer = 0 To count - 1
            hexArray(idx) = ascii(idx).ToString("x2")
        Next
        Return hexArray 'String.Join(" ", hexArray)
    End Function


'時間延遲
 Public Sub TimeDelay(ByVal DT As Integer)
        Dim StartTick As Integer
        StartTick = Environment.TickCount() '開始計數前的Tick
        Do
            If Environment.TickCount() - StartTick >= DT Then Exit Do
            Application.DoEvents()  '處理佇列中的訊息
        Loop
    End Sub

  '********************************************
  '傳送按鈕的Click事件
  '使用Write方法送出資料
  '********************************************
  Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        SerialPort1.ReadExisting()
        Dim aa As String
        Dim bb() As String
        SerialPort1.Write(txtSend.Text)
        TimeDelay(500)
        aa = SerialPort1.ReadExisting()
        bb = AsciiStringToHexString(aa)
        txtReceive.Text = String.Join(",", bb)
  End Sub 


如此收到的命令,就跟我們再擷取軟體收到的命令是相同的了。


打完收工

留言

張貼留言

這個網誌中的熱門文章

[Excel]將圖片放置於儲存格中

[軟體]AUTOCAD關於開啟圖面時,字型找不到,而要手動指定成 chineset.shx 字型檔問題

[MS SQL]查詢資料庫中每個資料表之列數與資料表大小(容量)資訊。Get size of all tables in database