【问题标题】:Methods to use the serial port in multiple forms多种形式使用串口的方法
【发布时间】:2017-06-06 12:14:51
【问题描述】:

我正在设计一个 Windows 用户窗体以通过串行端口与微控制器交互。

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

Form1: Start.vb Form2: Shield1.vb

1) 我可以在启动用户表单中将串口声明为:

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

并以其他形式使用它?

2) 第一种选择:使用模块声明一个新的串行端口

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) 第二种选择:在开始表单中构造串行端口,然后将数据传递给本文中提到的其他表单:Alternate Solution 1

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 2

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

对于初学者,推荐的解决方案是什么?如果您有其他建议或更正,请用小代码写出来吗?

对于任何歧义或错误使用的术语,我提前道歉。

谢谢!

【问题讨论】:

  • 这取决于你如何构建你的程序,如果你真的把函数放在适当的类和模块中并且只保留你的表单来启动这些函数/子你可以简单地将它作为参数传递,如果你的代码不是'如果结构最好,那么使用模块方法可能会更好
  • 这实际上是我在 VB 网络中的第一个项目,我也在尝试用最好的结构来学习最佳实践技巧。所以我在课堂上尝试。我的大问题实际上是解决方案的实施,因为我似乎在一些初学者的困境中很欣赏它。你能看看我在上一个答案中转换的单例类吗?谢谢!

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


【解决方案1】:

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

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 多年前的设计模式,当您只需要一个对象的一个​​副本时,它仍然非常有效。

【讨论】:

  • 感谢您的回复。是的,sigleton 类解决方案似乎是最好的。我是初学者所以谢谢你的信息。请看我的下一篇文章,在那里我找到了一个 C# 类的示例并使用代码转换器将其转换为 VB.net?你能告诉我代码是否正确吗?谢谢!
  • 如果你愿意,让我们先完成这个问题,然后再开始另一个问题。或者只是编辑这个,因为我可能无法轻松找到您的下一个问题。
  • 哦,我的意思是这是同一个问题。我只是在这里发布它作为第二个答案和建议。
  • 这是您建议的一种实现。只有我在 C# 中找到它,尽管它与 VB 很相似,但我很确定我会把翻译弄得一团糟……
【解决方案2】:

我发现这个非常有用的用于串行端口的 sigleton C# 类示例: C# Singleton Example

作为初学者,我使用了一个代码转换器在 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

【讨论】:

  • 好吧,我不能为你复习或测试这个,但乍一看,你似乎已经正确翻译了 Singleton 的东西。我认为根据我的建议,您现在走在正确的轨道上,只需进行测试即可。
猜你喜欢
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
相关资源
最近更新 更多