之前了做了个串口通讯的项目,主要用到 SerialPort类

这里主要说说几个问题

1. 在关闭串口的时候软件容易卡死的问题.

    我们在使用SerialPort类打开串口时候,会开一个接收数据的线程来接收从串口发送过来的数据,也可以开个调用SerialPort类的事件DataReceived (我这里使用后者,自己开启的线程要一直循环接收数据,消耗资源)

   

_serialPort = New SerialPort()
AddHandler _serialPort.DataReceived, AddressOf serialPort_DataReceived  '添加串口接收数据事件
Private Sub serialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)

 '
 '这里写接收数据的处理
 '

End Sub

    在写好接收数据处理的方法后, 我们来看看具体的处理方法

  

private Delegate sub DelShowMessage(Byval msg As String) '定义一个带字符串参数的委托
 Private Sub serialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)

Dim bytestoread As Integer = _serialPort.BytesToRead

    If bytestoread = 0 Then

            Exit Sub

     End If

   '定义字节数组接收数据
     Dim buffer(bytestoread - 1) As Byte

   '读取缓冲区数据到字节数组中
     _serialPort.Read(buffer, 0, bytestoread)

   '把字节转成相应的字符串 (这里只是个Demo 真正的项目接收的字节都是有自己的协议进行转换的)
     Dim messagestr As String = ConvertBuffer(buffer)
  
     '接收数据这个方法是个线程,用委托来处理显示
Me.Invoke(New DelShowMessage(AddressOf ShowMessage),messagestr)
End Sub


‘在文本框中显示字符串
Private Sub ShowMessage(Byval message As String) 
    
  TextBox1.Text=message
End Sub

'字节转换

  Private Function ConvertBuffer(ByVal buffer() As Byte) As String

       Return BitConverter.ToString(buffer)

  End Function

 上段代码将接收到的数据转换成字符串显示到文本框中

 

下面是关闭端口的方法

'关闭端口方法

 Private Sub btnPortClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPortClose.Click
     if _serialPort.IsOpen = True Then
         _serialPort.Close()
    End If
End Sub

 

就是这样直接关闭端口, 有时候软件会卡死

找到原因: 在点击按钮关闭端口的时候, 关闭这个方法在UI线程中运行, 如果串口接收的数据正好也需要用委托UI线程, 这样操作的的时候, 会结束这个接收的方法,如果这个方法同样在操作UI线程,就会造成死锁.

改进的方法:1. 在接收的数据的时候加一个标志说明已经有数据在处理,数据处理结束将此标志恢复, 在点击按钮关闭串口的时候, 等待这个标志恢复,再去关闭这个串口.

                   在点击按钮关闭串口的时候同样加一个标志说明需要关闭串口, 接收数据的时候判断是否有此标志, 有此标志则不进行处理

                2. 是比较简单的方法, 在处理完数据界面显示的用异步委托

 第一种方法:

'关闭端口方法
 Private _bClosing As Boolean = False
 private _bListening As Boolean = False
 Private Sub btnPortClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPortClose.Click
  '添加关闭标志,说明在关闭串口
  _bCloseing = True

 '监听界面是否更新数据
     While (_bListening)

            Application.DoEvents()

End While

   if _serialPort.IsOpen = True Then
_serialPort.Close()
  EndIf
_bCloseing = False
End Sub
Private Sub serialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
     '监听端口是否关闭
     If _bCloing = True Then
       Exit Sub
   End If
Try
_bListening = True
If _serialPort.IsOpen = True Then
                 Dim bytestoRead As Integer = _serialPort.BytesToRead()
                 If bytestoread=0 Then
                      Exit Sub
                 End
'定义字节数组接收数据
                  Dim buffer(bytestoread - 1) As Byte

'读取缓冲区数据到字节数组中
                 _serialPort.Read(buffer, 0, bytestoread)

                '把字节转成相应的字符串 (这里只是个Demo 真正的项目接收的字节都是有自己的协议进行转换的)
                  Dim messagestr As String = ConvertBuffer(buffer)
  
                 '接收数据这个方法是个线程,用委托来处理显示

                  Me.Invoke(New DelShowMessage(AddressOf ShowMessage),messagestr)
End If

         Catch ex As Exception

         Finally

                  _bListening = False

          End Try

End Sub

 

第二种方法:

将委托的那部分用异步委托代替

Me.BeginInvoke(New DelShowMessage(AddressOf ShowMessage),messagestr)