串口通讯随笔

之前了做了个串口通讯的项目,主要用到 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)
原文地址:https://www.cnblogs.com/hdsong/p/4800748.html