以多种形式使用串行端口的方法

时间:2017-06-06 12:14:52

标签: vb.net serial-port multiple-forms

我正在设计一个windows userform,通过串口与微控制器进行交互。

GUI包含多个用户表单,这些用户表单将使用相同的串行端口。我研究了如何做到这一点,我发现了不同的想法。有些我不知道它是否适用于其他我不知道如何在代码中实现它。假设我有

Form1:Start.vb Form2:Shield1.vb

1)我可以将start userform中的串口声明为:

Public Shared SerialPort1 As New System.IO.Ports.SerialPort

并以其他形式使用它?

2)第一种选择:使用模块声明新的Serialport

Module Module1
Public WithEvents mySerialPort1 As New IO.Ports.SerialPort

Private Sub mySerialPort1_DataReceived(sender As Object, _
                                       e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                   Handles mySerialPort1.DataReceived
End Sub
End Module

这种方法对吗?如果是,我如何在表格代码中使用它?如何在表单代码中包含DataReceived事件?

3)第二种选择:在开始表单中使用Serialport的构造函数,然后将数据传递给本文中提到的其他表单:Screenshot of the error

private void OnSetup(object sender, EventArgs e)
{
this.port = new SerialPort(...);
// TODO: initialize port

Form2 f2 = new Form2(this.port);
f2.Show();
Form3 f3 = new Form3(this.port);
f3.Show();
Form4 f4 = new Form4(this.port);
f4.Show();

}

那么活动还包括在内吗?我该如何使用它们?

4)第三种选择:使用类似于此解决方案中完成的静态类: Alternate Solution 1

用C#写的代码在这里吗?我正在VB.net中编写我的程序,但我可以将其作为参考。

对于初学者,推荐哪种解决方案?如果您有其他建议或更正,可以用小码编写吗?

我提前为任何歧义或错误使用的条款道歉。

谢谢!

2 个答案:

答案 0 :(得分:1)

我会遵循“Singleton”设计模式,这样可以确保只创建一个类的一个实例。这是一个广为接受的类这样的模板:

Public NotInheritable Class MySerial
Private Shared ReadOnly _instance As New Lazy(Of MySerial)(Function() New
    MySerial(), System.Threading.LazyThreadSafetyMode.ExecutionAndPublication)

Private Sub New()
End Sub

Public Shared ReadOnly Property Instance() As MySerial
    Get
        Return _instance.Value
    End Get
End Property

结束班

New()方法中,您应该根据需要设置串口。然后,无论您在何处使用该端口,都可以引用实例:

Dim singletonSerial As MySerial = MySerial.Instance

这是规范模式,用于确保您只有一个对象副本而无需使用静态类。这是一种可以追溯到20多年的设计模式,当您只需要一个对象的副本时,它仍然可以很好地工作。

答案 1 :(得分:0)

我发现这是一个非常有用的串口C#类的示例: C# Singleton Example

作为一名初学者,我使用了Code转换器在VB.Net中使用它。如果结果代码正确并且我可以使用它,你能告诉我吗?非常感谢!!

Imports System
Imports System.IO
Imports System.IO.Ports
Imports System.Threading

Namespace HeiswayiNrird.Singleton

Public NotInheritable Class SerialPortManager

    Private Shared lazy As Lazy(Of SerialPortManager) = New Lazy(Of SerialPortManager)(() => {  }, New SerialPortManager)

    Public Shared ReadOnly Property Instance As SerialPortManager
        Get
            Return lazy.Value
        End Get
    End Property

    Private _serialPort As SerialPort

    Private _readThread As Thread

    Private _keepReading As Boolean

    Private Sub New()
        MyBase.New
        Me._serialPort = New SerialPort
        Me._readThread = Nothing
        Me._keepReading = false
    End Sub

    ''' <summary>
    ''' Update the serial port status to the event subscriber
    ''' </summary>
    Public Event OnStatusChanged As EventHandler(Of String)

    ''' <summary>
    ''' Update received data from the serial port to the event subscriber
    ''' </summary>
    Public Event OnDataReceived As EventHandler(Of String)

    ''' <summary>
    ''' Update TRUE/FALSE for the serial port connection to the event subscriber
    ''' </summary>
    Public Event OnSerialPortOpened As EventHandler(Of Boolean)

    ''' <summary>
    ''' Return TRUE if the serial port is currently connected
    ''' </summary>
    Public ReadOnly Property IsOpen As Boolean
        Get
            Return Me._serialPort.IsOpen
        End Get
    End Property

    ''' <summary>
    ''' Open the serial port connection using basic serial port settings
    ''' </summary>
    ''' <param name="portname">COM1 / COM3 / COM4 / etc.</param>
    ''' <param name="baudrate">0 / 100 / 300 / 600 / 1200 / 2400 / 4800 / 9600 / 14400 / 19200 / 38400 / 56000 / 57600 / 115200 / 128000 / 256000</param>
    ''' <param name="parity">None / Odd / Even / Mark / Space</param>
    ''' <param name="databits">5 / 6 / 7 / 8</param>
    ''' <param name="stopbits">None / One / Two / OnePointFive</param>
    ''' <param name="handshake">None / XOnXOff / RequestToSend / RequestToSendXOnXOff</param>
    Public Sub Open(Optional ByVal portname As String = "COM1", Optional ByVal baudrate As Integer = 9600, Optional ByVal parity As Parity = Parity.None, Optional ByVal databits As Integer = 8, Optional ByVal stopbits As StopBits = StopBits.One, Optional ByVal handshake As Handshake = Handshake.None)
        Me.Close

        Try 
            Me._serialPort.PortName = portname
            Me._serialPort.BaudRate = baudrate
            Me._serialPort.Parity = parity
            Me._serialPort.DataBits = databits
            Me._serialPort.StopBits = stopbits
            Me._serialPort.Handshake = handshake
            Me._serialPort.ReadTimeout = 50
            Me._serialPort.WriteTimeout = 50
            Me._serialPort.Open
            Me.StartReading

        Catch  As IOException
            If (Not (OnStatusChanged) Is Nothing) Then
                OnStatusChanged(Me, String.Format("{0} does not exist.", portname))
            End If

        Catch  As UnauthorizedAccessException
            If (Not (OnStatusChanged) Is Nothing) Then
                OnStatusChanged(Me, String.Format("{0} already in use.", portname))
            End If

        Catch ex As Exception
            If (Not (OnStatusChanged) Is Nothing) Then
                OnStatusChanged(Me, ("Error: " + ex.Message))
            End If

        End Try

        If Me._serialPort.IsOpen Then
            Dim sb As String = StopBits.None.ToString.Substring(0, 1)
            Select Case (Me._serialPort.StopBits)
                Case StopBits.One
                    sb = "1"
                Case StopBits.OnePointFive
                    sb = "1.5"
                Case StopBits.Two
                    sb = "2"
            End Select

            Dim p As String = Me._serialPort.Parity.ToString.Substring(0, 1)
            Dim hs As String = "No Handshake"
            'TODO: Warning!!!, inline IF is not supported ?
            (Me._serialPort.Handshake = Handshake.None)
            Me._serialPort.Handshake.ToString
            If (Not (OnStatusChanged) Is Nothing) Then
                OnStatusChanged(Me, String.Format("Connected to {0}: {1} bps, {2}{3}{4}, {5}.", Me._serialPort.PortName, Me._serialPort.BaudRate, Me._serialPort.DataBits, p, sb, hs))
            End If

            If (Not (OnSerialPortOpened) Is Nothing) Then
                OnSerialPortOpened(Me, true)
            End If

        Else
            If (Not (OnStatusChanged) Is Nothing) Then
                OnStatusChanged(Me, String.Format("{0} already in use.", portname))
            End If

            If (Not (OnSerialPortOpened) Is Nothing) Then
                OnSerialPortOpened(Me, false)
            End If

        End If

    End Sub

    ''' <summary>
    ''' Close the serial port connection
    ''' </summary>
    Public Sub Close()
        Me.StopReading
        Me._serialPort.Close
        If (Not (OnStatusChanged) Is Nothing) Then
            OnStatusChanged(Me, "Connection closed.")
        End If

        If (Not (OnSerialPortOpened) Is Nothing) Then
            OnSerialPortOpened(Me, false)
        End If

    End Sub

    ''' <summary>
    ''' Send/write string to the serial port
    ''' </summary>
    ''' <param name="message"></param>
    Public Sub SendString(ByVal message As String)
        If Me._serialPort.IsOpen Then
            Try 
                Me._serialPort.Write(message)
                If (Not (OnStatusChanged) Is Nothing) Then
                    OnStatusChanged(Me, String.Format("Message sent: {0}", message))
                End If

            Catch ex As Exception
                If (Not (OnStatusChanged) Is Nothing) Then
                    OnStatusChanged(Me, String.Format("Failed to send string: {0}", ex.Message))
                End If

            End Try

        End If

    End Sub

    Private Sub StartReading()
        If Not Me._keepReading Then
            Me._keepReading = true
            Me._readThread = New Thread(ReadPort)
            Me._readThread.Start
        End If

    End Sub

    Private Sub StopReading()
        If Me._keepReading Then
            Me._keepReading = false
            Me._readThread.Join
            Me._readThread = Nothing
        End If

    End Sub

    Private Sub ReadPort()

        While Me._keepReading
            If Me._serialPort.IsOpen Then
                'byte[] readBuffer = new byte[_serialPort.ReadBufferSize + 1];
                Try 
                    'int count = _serialPort.Read(readBuffer, 0, _serialPort.ReadBufferSize);
                    'string data = Encoding.ASCII.GetString(readBuffer, 0, count);
                    Dim data As String = Me._serialPort.ReadLine
                    If (Not (OnDataReceived) Is Nothing) Then
                        OnDataReceived(Me, data)
                    End If

                Catch  As TimeoutException

                End Try

            Else
                Dim waitTime As TimeSpan = New TimeSpan(0, 0, 0, 0, 50)
                Thread.Sleep(waitTime)
            End If


        End While

    End Sub
End Class
End Namespace