Search code examples
vb.netserial-portscaletrim

Vb.Net Weight Scale Reading


Good evening everyone, I've been developing an app to read balances through serial port for a long time, after a long time just trying to read the data, I happily got the results, but the data is not synchronized, it takes an indefinite time to change the weight and when processing the data has the process of removing unwanted characters because the scale sends the data as follows: ww0000.00kg, after some changes I managed to make it change to 00.00kg. The weight has to sync in real time: It should work in the following way, when placing a weight the scale must be its value eg 13.75kg and print and then remove the weight and return to normal (00.00kg) in less than 3 seconds.

Code:

Dim decWeightReading As Decimal, strScaleCommand As String
    Dim strSerialData As String
    Dim strSerialDataNew As String
    Dim strFirstData As String
    Dim cnt As Integer
    Dim diffDate As TimeSpan    
    Dim initRunning As Integer
    Dim IntWeightReading As Integer
    Dim DecWeightReadingLast As Decimal
    Dim datetime1 As Date, datetime2 As Date

Form Load:

Private Sub Menufrm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        SerialPort1.Open()
        Timer1.Start()
    End Sub

TickTimer:

Private Sub TickTimer2()
    decWeightReading = CDec("0.000")
    strScaleCommand = "IP" + vbCrLf
    strFirstData = ""
    SerialPort1.WriteLine(strScaleCommand)
    strSerialData = SerialPort1.ReadLine
    strSerialDataNew = ""
    cnt = 0
    Do Until cnt = 10
        SerialPort1.WriteLine(strScaleCommand)
        strSerialDataNew = SerialPort1.ReadLine
        If strSerialDataNew = strSerialData Then
            cnt = cnt + 1
        Else
            strSerialData = strSerialDataNew
            strSerialDataNew = ""
            cnt = 0
        End If
        datetime2 = DateTime.Now
        diffDate = datetime2.Subtract(datetime1)
    Loop

End Sub

Time Tick and Trim the ww00:

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
TickTimer2()
Dim header As String = strSerialData
strSerialData = (header)
Weight.Text = (strSerialData)
strSerialData.Trim({"w"c, "w"c, "0"c})
Weight.Text = (header.Trim({"w"c, "w"c, "0"c}))

End Sub

And another difficulty I'm facing is that when reading the data from the balance to print in the TextBox the process gets very slow, it's even difficult to click a button or see the list of values in a ComboBox.

If anyone have any help I would appreciate it


Solution

  • The following shows how to read data using SerialPort - it subscribes to the DataReceived event. In VB.NET there are two different options to subscribe to an event.

    Option 1 (WithEvents)

    Private WithEvents Port As SerialPort = Nothing
    
    Public Function Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud9600) As String
        
        Dim result As String = String.Empty
    
        If Port Is Nothing Then
    
            'create new instance
            Port = New SerialPort(comPort)
    
        End If
                       ...
    
        Return result
    
    End Function
    

    To subscribe to the Port.DataReceived event:

    Private Sub Port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles Port.DataReceived
    
    End Sub
    

    Option 2 (AddHandler)

    Private Port As SerialPort = Nothing
    
    Public Function Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud9600) As String
        
        Dim result As String = String.Empty
    
        If Port Is Nothing Then
    
            'create new instance
            Port = New SerialPort(comPort)
    
            'subscribe to events (add event handlers)
            AddHandler Port.DataReceived, AddressOf Port_DataReceived
            AddHandler Port.ErrorReceived, AddressOf Port_ErrorReceived
    
        End If
                       ...
    
        Return result
    
    End Function
    

    To subscribe to the Port.DataReceived event:

    Private Sub Port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
    
    End Sub
    

    Below are the steps to create a new Windows Forms (WinForms) project that uses SerialPort to read data along with the necessary code.

    Create a WinForms project

    VS 2017:

    • Open Visual Studio
    • Click File
    • Select New
    • Select Project
    • Expand Installed
    • Expand Visual Basic
    • Click Windows Desktop
    • Select Windows Forms App (.NET Framework)
    • Specify project name (name: ReadSerialPort)
    • Click OK

    VS 2019:

    • Open Visual Studio
    • Click Continue without code
    • Click File
    • Select New
    • Select Project
    • Visual Basic Windows Desktop
    • Click Windows Forms App (.NET Framework)
    • Click Next
    • Specify project name (name: ReadSerialPort)
    • Click Create

    Note: From this point forward, the process is the same for both VS 2017 and VS 2019.

    Add some controls to Form1

    enter image description here

    Open Properties Window

    • In VS menu, select View
    • Select Properties Window

    Open Solution Explorer

    • In VS menu, select View
    • Select Solution Explorer
    • In Solution Explorer, double-click Form1.vb to open the designer.

    Add "Connect" button to Form1

    • In VS menu, select View
    • Select Toolbox
    • Select Button
    • Click on Form1 to add the button to the form
    • In Properties Window, for "button1", set (name): btnConnect; set Text: Connect
    • In Properties Window, click enter image description here (Events). Double-click Click to add event handler to Form1.vb

    Add "Disconnect" button to Form1

    • In VS menu, select View
    • Select Toolbox
    • Select Button
    • Click on Form1 to add the button to the form
    • In Properties Window, for "button1", set (name): btnDisconnect; set Text: Disconnect
    • In Properties Window, click enter image description here (Events). Double-click Click to add event handler to Form1.vb

    Add TextBox to Form1

    • In VS menu, select View
    • Select Toolbox
    • Select TextBox
    • Click on Form1 to add the button to the form

    Add "Load" event handler to Form1

    • In Properties Window, for "Form1"", click enter image description here (Events). Double-click Load to add event handler to Form1.vb

    Add "FormClosing" event handler to Form1

    • In Properties Window, for "Form1"", click enter image description here (Events). Double-click FormClosing to add event handler to Form1.vb

    Add class: HelperSerialPort

    • On VS menu, select Project
    • Select Add Class (name: HelperSerialPort.vb)

    Option 1 (WithEvents)

    HelperSerialPort.vb

    Imports System.IO.Ports
    
    Public Enum PortBaudRate As Integer
        Baud1200 = 1200
        Baud2400 = 2400
        Baud4800 = 4800
        Baud9600 = 9600
        Baud14400 = 14400
        Baud19200 = 19200
        Baud28800 = 28800
        Baud38400 = 38400
        Baud56000 = 56000
        Baud76800 = 76800
        Baud115200 = 115200
    
    End Enum
    
    Public Class HelperSerialPort
        Implements IDisposable
    
        Private WithEvents Port As SerialPort = Nothing
    
        'events that can be subscribed to
        Public Event DataReceived(ByVal sender As Object, ByVal data As String)
        Public Event ErrorReceived(ByVal sender As Object, ByVal errMsg As String)
    
        Sub New()
    
        End Sub
    
        Public Function Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud9600) As String
            Dim errMsg As String = String.Empty
            Dim portName As String = String.Empty
            Dim result As String = String.Empty
    
            If String.IsNullOrEmpty(comPort) Then
                errMsg = "COM port not selected"
                Throw New Exception(errMsg)
            End If
    
            Try
                If Port Is Nothing Then
    
                    'create new instance
                    Port = New SerialPort(comPort)
    
                End If
    
                If Not Port.IsOpen Then
    
                    'set properties
                    Port.BaudRate = baudRate
                    Port.Handshake = Handshake.None
    
                    'if parity is even or odd, then set DataBits = 7
                    'if parity is none, set DataBits = 8
                    Port.Parity = Parity.Even 'Even, None, Odd 
                    Port.DataBits = 7
    
                    Port.StopBits = StopBits.One
                    Port.ReadTimeout = 200
                    Port.WriteTimeout = 50
                    Port.DtrEnable = True 'enable Data Terminal Ready
                    Port.RtsEnable = True 'enable Request to Send
    
                    'open port
                    Port.Open()
    
                    result = "Status: Connected"
                Else
                    result = "Status: Already Connected"
                End If
    
            Catch ex As Exception
                errMsg = "Error: " & ex.Message
                result = errMsg 'set value
                Debug.WriteLine(errMsg)
                Throw ex
            End Try
    
            Debug.WriteLine(result)
    
            Return result
        End Function
    
        Public Sub Disconnect()
            Dispose()
        End Sub
    
        Public Sub Dispose() Implements System.IDisposable.Dispose
            If Port IsNot Nothing Then
    
                Port.Dispose()
                Port = Nothing
            End If
        End Sub
    
        Private Sub Port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles Port.DataReceived
            'read SerialPort data
            Dim data As String = String.Empty
    
            data = Port.ReadExisting()
            'data = Port.ReadLine
    
            Debug.WriteLine("Data: " & data)
    
            'raise event
            RaiseEvent DataReceived(Me, data)
        End Sub
    
        Private Sub Port_ErrorReceived(ByVal sender As Object, ByVal e As SerialErrorReceivedEventArgs) Handles Port.ErrorReceived
            Dim errMsg As String = e.EventType.ToString()
    
            Debug.WriteLine("Error: " & errMsg)
    
            'raise event
            RaiseEvent ErrorReceived(Me, errMsg)
        End Sub
    
        Public Sub WriteToSerialPort(ByVal data As String)
            Dim errMsg As String = String.Empty
    
            Try
                If Port.IsOpen Then
    
                    'convert string to Byte array
                    Dim hexArr As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
    
                    For Each hexVal As Byte In hexArr
    
                        'convert byte to byte array
                        Dim tempArr As Byte() = New Byte() {hexVal}
    
                        'write 
                        Port.Write(tempArr, 0, 1)
    
                        'add 1 ms delay before writing next byte
                        System.Threading.Thread.Sleep(1)
                    Next
                Else
                    errMsg = "Error: Port is not open. Please open the connection and try again."
                    Debug.WriteLine(errMsg)
                    Throw New Exception(errMsg)
                End If
            Catch ex As Exception
                errMsg = "Error: " & ex.Message
                Debug.WriteLine(errMsg)
                Throw ex
            End Try
    
        End Sub
    End Class
    

    Modify Form1.vb code

    • In Solution Explorer, right-click Form1.vb
    • Select View Code

    Form1.vb

    Imports System.IO.Ports
    
    Public Class Form1
    
        Private WithEvents helper As HelperSerialPort = New HelperSerialPort
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            'get port names
            For Each portName In SerialPort.GetPortNames()
                Debug.WriteLine("portName: " & portName)
            Next
    
        End Sub
    
        Private Sub Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud9600)
            If helper IsNot Nothing Then
                Debug.WriteLine("comPort: " & comPort & " baudRate: " & baudRate.ToString())
                helper.Connect(comPort, baudRate)
            End If
        End Sub
    
        Private Sub Helper_DataReceived(ByVal sender As Object, ByVal data As String) Handles helper.DataReceived
            Debug.WriteLine("Data: " & data)
    
            'set value
            Dim tempData As String = data
    
            If tempData.StartsWith("ww") AndAlso tempData.EndsWith("kg") Then
                tempData = tempData.Substring(2, data.Length - 4)
            End If
    
            'If tempData.StartsWith("ww") Then
            'tempData = tempData.Substring(2)
            'End If
    
            'If tempData.EndsWith("kg") Then
            'tempData = tempData.Substring(0, tempData.IndexOf("kg"))
            'End If
    
            'set text in TextBox
            TextBox1.Invoke(New MethodInvoker(Sub()
                                                  TextBox1.Text = tempData
                                                  TextBox1.Refresh()
                                              End Sub))
    
        End Sub
    
        Private Sub Helper_ErrorReceived(ByVal sender As Object, ByVal errMsg As String) Handles helper.ErrorReceived
            Debug.WriteLine(errMsg)
        End Sub
    
        Private Sub Disconnect()
            If helper IsNot Nothing Then
                helper.Disconnect()
            End If
        End Sub
    
        Private Sub btnConnect_Click(sender As Object, e As EventArgs) Handles btnConnect.Click
            Connect("COM1", PortBaudRate.Baud9600)
        End Sub
    
        Private Sub btnDisconnect_Click(sender As Object, e As EventArgs) Handles btnDisconnect.Click
            Disconnect()
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
            'dispose
            If helper IsNot Nothing Then
                helper.Dispose()
            End If
        End Sub
    End Class
    

    Option 2 (AddHandler)

    HelperSerialPort.vb

    Imports System.IO.Ports
    
    Public Enum PortBaudRate As Integer
        Baud1200 = 1200
        Baud2400 = 2400
        Baud4800 = 4800
        Baud9600 = 9600
        Baud14400 = 14400
        Baud19200 = 19200
        Baud28800 = 28800
        Baud38400 = 38400
        Baud56000 = 56000
        Baud76800 = 76800
        Baud115200 = 115200
    
    End Enum
    
    Public Class HelperSerialPort
        Implements IDisposable
    
        Private Port As SerialPort = Nothing
    
        Public Event DataReceived(ByVal sender As Object, ByVal data As String)
        Public Event ErrorReceived(ByVal sender As Object, ByVal errMsg As String)
    
        Sub New()
    
        End Sub
    
        Public Function Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud9600) As String
            Dim errMsg As String = String.Empty
            Dim portName As String = String.Empty
            Dim result As String = String.Empty
    
            If String.IsNullOrEmpty(comPort) Then
                errMsg = "COM port not selected"
                Throw New Exception(errMsg)
            End If
    
    
            Debug.WriteLine("comPort: " & comPort)
    
            Try
                If Port Is Nothing Then
                    Debug.WriteLine("creating new instance of SerialPort")
    
                    'create new instance
                    Port = New SerialPort(comPort)
    
                    'subscribe to events (add event handlers)
                    AddHandler Port.DataReceived, AddressOf Port_DataReceived
                    AddHandler Port.ErrorReceived, AddressOf Port_ErrorReceived
    
                End If
    
                If Not Port.IsOpen Then
    
                    Debug.WriteLine("Port isn't open")
    
                    'set properties
                    Port.BaudRate = baudRate
                    Port.Handshake = Handshake.None
    
                    'if parity is even or odd, then set DataBits = 7
                    'if parity is none, set DataBits = 8
                    Port.Parity = Parity.Even 'Even, None, Odd 
                    Port.DataBits = 7
    
                    Port.StopBits = StopBits.One
                    Port.ReadTimeout = 200
                    Port.WriteTimeout = 50
                    Port.DtrEnable = True 'enable Data Terminal Ready
                    Port.RtsEnable = True 'enable Request to Send
    
                    'open port
                    Port.Open()
    
                    result = "Status: Connected"
                Else
                    result = "Status: Already Connected"
                End If
    
            Catch ex As Exception
                errMsg = "Error: " & ex.Message
                result = errMsg 'set value
                Debug.WriteLine(errMsg)
                Throw ex
            End Try
    
            Debug.WriteLine(result)
    
            Return result
        End Function
    
        Public Sub Disconnect()
            Dispose()
        End Sub
    
        Public Sub Dispose() Implements System.IDisposable.Dispose
            If Port IsNot Nothing Then
    
                'unsubscribe from events (remove event handlers)
                RemoveHandler Port.DataReceived, AddressOf Port_DataReceived
                RemoveHandler Port.ErrorReceived, AddressOf Port_ErrorReceived
    
                Port.Dispose()
                Port = Nothing
            End If
        End Sub
    
        Private Sub Port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
            'read SerialPort data
            Dim data As String = String.Empty
    
            data = Port.ReadExisting()
            'data = Port.ReadLine
    
            Debug.WriteLine("Data: " & data)
    
            'raise event
            RaiseEvent DataReceived(Me, data)
        End Sub
    
        Private Sub Port_ErrorReceived(ByVal sender As Object, ByVal e As SerialErrorReceivedEventArgs)
            Dim errMsg As String = e.EventType.ToString()
    
            Debug.WriteLine("Error: " & errMsg)
    
            'raise event
            RaiseEvent ErrorReceived(Me, errMsg)
        End Sub
    
        Public Sub WriteToSerialPort(ByVal data As String)
            Dim errMsg As String = String.Empty
    
            Try
                If Port.IsOpen Then
    
                    'convert string to Byte array
                    Dim hexArr As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
    
                    For Each hexVal As Byte In hexArr
    
                        'convert byte to byte array
                        Dim tempArr As Byte() = New Byte() {hexVal}
    
                        'write 
                        Port.Write(tempArr, 0, 1)
    
                        'add 1 ms delay before writing next byte
                        System.Threading.Thread.Sleep(1)
                    Next
                Else
                    errMsg = "Error: Port is not open. Please open the connection and try again."
                    Debug.WriteLine(errMsg)
                    Throw New Exception(errMsg)
                End If
            Catch ex As Exception
                errMsg = "Error: " & ex.Message
                Debug.WriteLine(errMsg)
                Throw ex
            End Try
    
        End Sub
    End Class
    

    Modify Form1.vb code

    • In Solution Explorer, right-click Form1.vb
    • Select View Code

    Form1.vb

    Imports System.IO.Ports
    
    Public Class Form1
    
        Private helper As HelperSerialPort = Nothing
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            'create new instance
            helper = New HelperSerialPort()
    
            'subscribe to events (add event handlers)
            AddHandler helper.DataReceived, AddressOf Helper_DataReceived
            AddHandler helper.ErrorReceived, AddressOf Helper_ErrorReceived
    
            'get port names
            For Each portName In SerialPort.GetPortNames()
                Debug.WriteLine("portName: " & portName)
            Next
    
        End Sub
    
        Private Sub Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud9600)
            If helper IsNot Nothing Then
                Debug.WriteLine("comPort: " & comPort & " baudRate: " & baudRate.ToString())
                helper.Connect(comPort, baudRate)
            End If
        End Sub
    
        Private Sub Helper_DataReceived(ByVal sender As Object, ByVal data As String)
            Debug.WriteLine("Data: " & data)
    
            'set value
            Dim tempData As String = data
    
            If tempData.StartsWith("ww") AndAlso tempData.EndsWith("kg") Then
                tempData = tempData.Substring(2, data.Length - 4)
            End If
    
            'If tempData.StartsWith("ww") Then
            'tempData = tempData.Substring(2)
            'End If
    
            'If tempData.EndsWith("kg") Then
            'tempData = tempData.Substring(0, tempData.IndexOf("kg"))
            'End If
    
            'set text in TextBox
            TextBox1.Invoke(New MethodInvoker(Sub()
                                                  TextBox1.Text = tempData
                                                  TextBox1.Refresh()
                                              End Sub))
    
        End Sub
    
        Private Sub Helper_ErrorReceived(ByVal sender As Object, ByVal errMsg As String)
            Debug.WriteLine(errMsg)
        End Sub
    
        Private Sub Disconnect()
            If helper IsNot Nothing Then
                helper.Disconnect()
            End If
        End Sub
    
        Private Sub btnConnect_Click(sender As Object, e As EventArgs) Handles btnConnect.Click
            Connect("COM1", PortBaudRate.Baud9600)
        End Sub
    
        Private Sub btnDisconnect_Click(sender As Object, e As EventArgs) Handles btnDisconnect.Click
            Disconnect()
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
            'dispose
            If helper IsNot Nothing Then
                helper.Dispose()
            End If
        End Sub
    End Class
    

    Resources: