Results 1 to 27 of 27

Thread: problem in handling multiple Bytes received using Serial Port

Hybrid View

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    problem in handling multiple Bytes received using Serial Port

    Hello All,

    I'am Developing an application in VB.Net in which I need to receive 8 Bytes from Microcontroller at once and then process those 8 bytes to plot a graph of those values using drawline function.

    Then again next set of 8 Bytes are received & processed and plotting continues. For testing purpose I'am sending a sine wave from freq generator and need to plot the same on vb application.

    Ia'm receiving 8 Bytes because my application needs to send four ADC Input Pins data which is of 12 Bits. So to send the complete data i need to break the data into two bytes per one channel input and then again OR(with Bit shifting) the received 2 Bytes to get it back to 12 Bits on the PC side.

    My UART Speed is 115200 Bps.

    First I send a single channel data ( 2 bytes from the microcontroller )and tried receiving it via below code
    Code:
    Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    
            Dim numberOfBytesToRead As Integer
    
            numberOfBytesToRead = SerialPort1.BytesToRead
    
            ' Create a byte array large enough to hold the bytes to be read.
            Dim newReceivedData(numberOfBytesToRead - 1) As Byte
            ' Read the bytes into the byte array.
            SerialPort1.Read(newReceivedData, 0, numberOfBytesToRead)
    Me.Invoke(New EventHandler(AddressOf Graph2Delegate))
    My problem is I'am not able to handle the received buffer properly.

    How to retrieve the data in delegate function and clear the buffer again to receive new Bytes?

    kindly guide me.

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,299

    Re: problem in handling multiple Bytes received using Serial Port

    Is that call to Read populating the array correctly? If you want to actually pass the array to your graphing method then you need to declare that method with a parameter of that type and then Invoke it with delegate with a matching signature, e.g.
    vb.net Code:
    1. Private Sub DrawGraph(data As Byte())
    vb.net Code:
    1. Me.Invoke(New Action(Of Byte())(AddressOf DrawGraph), newReceivedData)
    Notice that the method doesn't have "Delegate" in the name, which doesn't make sense for a delegate, never mind a method. Also, I do hope that you're not actually drawing on the form or another control in that method. Drawing on an Image and displaying that would be OK but if you're drawing on a control then you need to be doing that in its Paint event handler.

  3. #3
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: problem in handling multiple Bytes received using Serial Port

    You can't assume that one DataReceived event will contain all of the bytes sent. The following code accumulates the bytes received. See the note in the code about what your protocol message length is. I did not address the issues JMC brought up in post#2. A combo of his code and mine should help.

    Code:
        Private buffer As New List(Of Byte)
        Private Sub SerialPort1_DataReceived(sender As Object,
                                             e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    
            Dim BytesRead As Integer = 0
    
            Dim numberOfBytesToRead As Integer = SerialPort1.BytesToRead
            ' Create a byte array large enough to hold the bytes to be read.
            Dim newReceivedData(numberOfBytesToRead - 1) As Byte
            ' Read the bytes into the byte array.
            BytesRead = SerialPort1.Read(newReceivedData, 0, numberOfBytesToRead)
            If BytesRead > 0 Then
                If BytesRead <> numberOfBytesToRead Then
                    Array.Resize(newReceivedData, BytesRead)
                End If
                buffer.AddRange(newReceivedData) 'accumulate in buffer
            End If
    
            'this assumes that you are looking for 8 bytes total in a message
            'if not change it to represent message length
            Const protoMessLen As Integer = 8
    
            Dim messBuf As List(Of Byte)
            Do While buffer.Count >= protoMessLen
                messBuf = buffer.GetRange(0, protoMessLen) 'get complete message
                buffer.RemoveRange(0, protoMessLen) 'remove from buffer
                ' messBuf.ToArray 'converts list to array
    
                '
                'put code to process messBuf here
                '
            Loop
        End Sub
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  4. #4

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    Hello All,

    I changed the code of serial data received event handler to SerialPort1.ReadLine so that i do not have to convert back my data to 12 Bits. Below is the code. My data is coming and getting plotted on the picturebox but I feel that the plotting speed of data is slow. I mean I need maximum plotting speed of 100mm/sec . My per pixel size is 0.26mm so for 100 mm I need to cover 411 pixels approx in 1 Sec . How to achieve this speed? my picture box is 879 pixels wide.


    Code:
    Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    
    
            Try
    
                While SerialPort1.BytesToRead > 0
                    
                    inData1 = SerialPort1.ReadLine
    
                    inData2 = SerialPort1.ReadLine
                    inData3 = SerialPort1.ReadLine
                    inData4 = SerialPort1.ReadLine
    
                    Me.BeginInvoke((New MyDelegate(AddressOf Graph2Delegate)), inData1, inData2, inData3, inData4)
    
                End While
    
    
            Catch ex As Exception
            End Try
            
        End Sub
    
    Private Sub Graph2Delegate()
    
    
    
             analogData1Queue.Enqueue(indata1)
             analogData2Queue.Enqueue(indata2)
             analogData3Queue.Enqueue(indata3)
             analogData4Queue.Enqueue(indata4)
    
            dataenter = True
    
            PrintX(inData1, inData2, inData3, inData4)
    
     End Sub
    
    Public Function PrintX(ByVal Xvalue1 As UInt32, ByVal Xvalue2 As UInt32, ByVal Xvalue3 As UInt32, ByVal Xvalue4 As UInt32) As Object
    
    Try
    
                x_start = 1
                y_start1 = graph.Height - 100
                y_start2 = graph.Height - 200
                y_start3 = graph.Height - 300
                y_start4 = graph.Height
                mygraphics = graph.CreateGraphics           
                mygraphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
    
    If dataenter = True Then
    
    mygraphics.DrawLine(p2, x_start + k, y_start1 - temp_ahead1, x_start + (k + 1), y_start1 - Xvalue1)
                        temp_ahead1 = Xvalue1
    mygraphics.DrawLine(p3, x_start + k, y_start2 - temp_ahead2, x_start + (k + 1), y_start2 - Xvalue2)
                        temp_ahead2 = Xvalue2
    
                        mygraphics.DrawLine(p4, x_start + k, y_start3 - temp_ahead3, x_start + (k + 1), y_start3 - Xvalue3)
                        temp_ahead3 = Xvalue3
    
    mygraphics.DrawLine(p5, x_start + k, y_start4 - temp_ahead4, x_start + (k + 1), y_start4 - Xvalue4)
                                temp_ahead4 = Xvalue2
    
    dataenter = False
                        k = k + 1
    
                        If k = graph.Width Then
                            k = 0
                            mygraphics.Clear(Color.White)
                            
                        End If
     End If
    
    
            Catch ex As Exception
            End Try
    
        End Function
    I'am sure there is a possibility to increase speed of plotting.

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    Hello All,

    I tried using the picture box paint event and kept calling it in my delegate using invalidate function, But it keeps refreshing . I mean I want the old data to remain on the picture box just like an oscilloscope !

    Can anybody help me in using paint event to handle graph plotting!

  6. #6
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: problem in handling multiple Bytes received using Serial Port

    This feels like a moving target. In post #1 you said the device was sending 8 bytes which I provided code for. Now it looks like it is sending 4 lines.

    If your handler receives one byte it is going to block until it receives 4 lines. Why is reading strings a better approach than reading numbers(bytes)?
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    Hello dbasnett,

    I just used readline method so that I dont have to break the data in 16 bits and sending it a packet of 2 BYTES. Both receiving and sending code will be reduced. But Anyways, I will go with which ever way is better . if I send data with out breaking at the controller END it looks like

    printf("%d\n %d\n %d\n %d\n", DATA1,DATA2,DATA3,DATA4)

    if I break it the MCU is sending the data as

    UARTCharPut(Uart4,AH)
    UARTCharPut(Uart4,AL)
    UARTCharPut(Uart4,BH)
    UARTCharPut(Uart4,BL)
    UARTCharPut(Uart4,CH)
    UARTCharPut(Uart4,CL)
    UARTCharPut(Uart4,DH)
    UARTCharPut(Uart4,DL)

    Is there any difference in receiving Bytes rather than receiving Strings?

  8. #8
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,754

    Re: problem in handling multiple Bytes received using Serial Port

    Quote Originally Posted by sumit11 View Post
    ...Is there any difference in receiving Bytes rather than receiving Strings?
    Yes. If you are working with string methods the bytes are decoded based on the encoder chosen.

    Both ends should agree, string data or byte data.

    If it were me I would send and receive bytes if the data is numeric, which it seems to be in this case.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  9. #9
    Addicted Member
    Join Date
    Nov 2011
    Posts
    229

    Re: problem in handling multiple Bytes received using Serial Port

    what else could be the way to plot the graph?

    MS Chart tool may work, this guy has a couple of C# examples that look pretty good https://www.youtube.com/watch?v=HlDwVUR71yI

    Plus there are neat features like scroll and zoom that can be added

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    I've seen MS Chart control and it plots the signal really fast. However not much tutorial stuff is available regarding MS Chart on the net! specially the linegraph or spline graph feature.
    I mean i'am trying to find how to display time in seconds in X-axis with MS Chart tool but no luck till now!!

    This youtube link says kaychart. Is kaychart different from MS Chart??

  11. #11
    Addicted Member
    Join Date
    Nov 2011
    Posts
    229

    Re: problem in handling multiple Bytes received using Serial Port

    kayChart is a library for charting https://www.nuget.org/packages/kayChart.dll/

    I have not used kayChart but I have used MS Chart, nothing at the speed that guys does but still ok for my purpose and uses the same techniques as kayChart.

    As for the X axis unless you are transmitting the frequency value I don't see how that can accurately be gained from a serial connection, just changing the baud rate would alter your figures or a delay in buffering data. But I may be wrong on that and there may be a way of doing it that I am unaware of and a lot depends on the frequency you are trying to measure. People on this forum can probably give more input on that

  12. #12
    Addicted Member
    Join Date
    Nov 2011
    Posts
    229

    Re: problem in handling multiple Bytes received using Serial Port

    It's fairly easy to get started with an example, here is one that just requires a Form with a MSChart and a Timer.

    Make sure the timer is enabled or nothing will happen, try zooming and scrolling

    Code:
    Imports System.Windows.Forms.DataVisualization.Charting
    
    Public Class Form1
        Dim chartdata As Double
      
        Dim flipflop As Boolean = False
    
        Private Sub updatechart()
    
            Chart1.Series("Series1").Points.Add(chartdata)
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    
    
            If flipflop Then
                flipflop = False
                chartdata = 22
            ElseIf flipflop = False Then
                flipflop = True
                chartdata = 45
            End If
    
            updatechart()
    
        End Sub
    
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
    
            Chart1.Series("Series1").ChartType = SeriesChartType.Spline
    
            With Chart1.ChartAreas(0).AxisX
    
                .Minimum = 0
                .Maximum = 2000
                .MajorGrid.Interval = 5
                .MajorTickMark.Enabled = True
                .MajorTickMark.Interval = 5
                .MajorTickMark.Size = 5
                .LabelStyle.Enabled = True
                .LabelStyle.Interval = 5
    
            End With
    
    
            Chart1.ChartAreas(0).CursorX.IsUserEnabled = True
            Chart1.ChartAreas(0).CursorX.IsUserSelectionEnabled = True
            Chart1.ChartAreas(0).AxisX.ScaleView.Zoomable = True
            Chart1.ChartAreas(0).AxisX.ScrollBar.IsPositionedInside = True
            Chart1.ChartAreas(0).AxisX.ScaleView.Zoom(0, 200)
    
        End Sub
    
    End Class

  13. #13

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    hello Mc_Vb

    I followed your example code and Tried running it. I came up with my code to use MS chart. below is the same.
    I'am just wondering when should I update my graph with new data. Should I do it with Timer tick OR in the delegate function where Iam receiving new data from serial port. I tried plotting the graph with below code but it is too fast. Can't really figure out anything. plotting graph with random number using rand function inTimer tick is a different thing.
    But plotting with Real time Serial Port data is the thing I just cant figure out.

    Code:
    Imports System.IO.Ports
    Imports System.Threading
    Imports System.Text
    Imports System.Windows.Forms.DataVisualization.Charting
    
    Public Class Form1
    
    
    
        Dim result1, result2, result3, result4, result5, result6, result7, result8 As UInt32
        Dim indata1, indata2, indata3, indata4, indata5, indata6, indata7, indata8 As UInt32
        Dim rcvddata(4000) As UInt32
        
        Dim j As Integer
        Public counter As Integer = 0
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Try
                SerialPort1.PortName = ComboBox1.SelectedItem
    
                If SerialPort1.IsOpen() = False Then
                    SerialPort1.Open()
                End If
    
                SerialPort1.Write("a")
    
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            SerialPort1.Write("b")
    
            If SerialPort1.IsOpen() Then
    
                SerialPort1.Close()
    
            End If
        End Sub
    
        ' Dim indata1, indata2, indata3, indata4 As Byte
        Public Delegate Sub MyDelegate(ByVal data As Byte)
        Private buffer As New List(Of Byte)
        Dim messBuf As List(Of Byte)
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            For Each Port As String In SerialPort.GetPortNames()
                ComboBox1.Items.Add(Port)
    
            Next Port
    
            If ComboBox1.Items.Count > 0 Then
                ComboBox1.SelectedIndex = 0
            End If
    
           
    
    
            SerialPort1.RtsEnable = True
            SerialPort1.BaudRate = "115200"
            SerialPort1.Parity = Parity.None
            SerialPort1.DataBits = 8
            SerialPort1.StopBits = StopBits.One
            SerialPort1.Encoding = Encoding.ASCII
    
            Chart1.Titles.Add("Sin Wave Example")
            Chart1.Titles(0).Font = New Font("Arial", 10, FontStyle.Bold)
    
            With Chart1.ChartAreas(0)
                .AxisX.Title = "Counter"
                .AxisX.MajorGrid.Enabled = False
                .AxisX.MajorGrid.LineColor = Color.LightGray
                .AxisX.Interval = 50
                .AxisX.IsLabelAutoFit = False
                .AxisX.LabelStyle.Font = New Font("Arial", 10, FontStyle.Regular)
                .AxisX.LabelStyle.Angle = -90
                .AxisX.LabelStyle.IsStaggered = False
                .AxisX.LabelStyle.Enabled = True
    
                .AxisY.Title = "Values"
                .AxisY.MajorGrid.LineColor = Color.LightGray
                .AxisY.IsInterlaced = True
                .AxisY.InterlacedColor = Color.FloralWhite
    
                .BackColor = Color.FloralWhite
                .BackSecondaryColor = Color.White
                .BackGradientStyle = GradientStyle.HorizontalCenter
                .BorderColor = Color.Blue
                .BorderDashStyle = ChartDashStyle.Solid
                .BorderWidth = 1
                .ShadowOffset = 2
            End With
        End Sub
    
        Private Sub SerialPort1_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            Dim BytesRead As Integer = 0
    
            Dim numberOfBytesToRead As Integer = SerialPort1.BytesToRead
            ' Create a byte array large enough to hold the bytes to be read.
            Dim newReceivedData(numberOfBytesToRead - 1) As Byte
            ' Read the bytes into the byte array.
            BytesRead = SerialPort1.Read(newReceivedData, 0, numberOfBytesToRead)
            If BytesRead > 0 Then
                If BytesRead <> numberOfBytesToRead Then
                    Array.Resize(newReceivedData, BytesRead)
                End If
                buffer.AddRange(newReceivedData) 'accumulate in buffer
            End If
    
            'this assumes that you are looking for 8 bytes total in a message
            'if not change it to represent message length
            Const protoMessLen As Integer = 8
    
            Dim messBuf As List(Of Byte)
    
            Dim rcvBuf As Byte()
            Do While buffer.Count >= protoMessLen
                messBuf = buffer.GetRange(0, protoMessLen) 'get complete message
                buffer.RemoveRange(0, protoMessLen) 'remove from buffer
                rcvBuf = messBuf.ToArray() 'converts list to array
                Me.BeginInvoke(New Action(Of Byte())(AddressOf DrawGraph), rcvBuf)
            Loop
           
        End Sub
    
        Structure DataPointType
            Public x As UInt32
            Public y As UInt32
    
        End Structure
    
        Private Sub DrawGraph(Data() As Byte)
    
            result1 = Data(0)
            result2 = Data(1)
            'result3 = Data(2)
            'result4 = Data(3)
            'result5 = Data(4)
            'result6 = Data(5)
            'result7 = Data(6)
            'result8 = Data(7)
    
            indata1 = result1 Or (result2 << 8)
            'indata2 = result3 Or (result4 << 8)
            'indata3 = result5 Or (result6 << 8)
            'indata4 = result7 Or (result8 << 8)
    
            
            GetDataPoint()
    
            Chart1.Series.Clear()
            Chart1.Series.Add("Line Type")
            Chart1.Series(0).IsVisibleInLegend = False
            Chart1.Series(0).Color = Color.Red
            Chart1.Series(0).ChartType = DataVisualization.Charting.SeriesChartType.Spline
    
            Chart1.ChartAreas(0).AxisX.Minimum = ChartDataList(0).x
            Chart1.ChartAreas(0).AxisX.Maximum = Chart1.ChartAreas(0).AxisX.Minimum + 360
    
            For i = 0 To ChartDataList.Count - 1
                Chart1.Series(0).Points.AddXY(ChartDataList(i).x, ChartDataList(i).y)
            Next
    
    
    
    
        End Sub
    
        Private ChartDataList As New List(Of DataPointType)
    
        Private Sub GetDataPoint()
            'remove a point
            If ChartDataList.Count > 512 Then
                ChartDataList.Remove(ChartDataList(0))
            End If
    
            'add next point
            Dim thisDataPoint As DataPointType
    
            thisDataPoint.x = counter
            thisDataPoint.y = indata1
    
            ChartDataList.Add(thisDataPoint)
    
            counter += 20
    
        End Sub
    End Class

  14. #14

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    this is the reference and what I need to do

    https://www.youtube.com/watch?v=nvBzT660gY4

  15. #15
    Addicted Member
    Join Date
    Nov 2011
    Posts
    229

    Re: problem in handling multiple Bytes received using Serial Port

    Hi, the timer was just to display an example and in your case I would use fixed values for the X axis. The data received event would take the place of the timer and update the chart.

    You said in an earlier post that you were sampling at 256 samples per second so I would make my major grid interval 256.

    I would make my minor grid interval 1 and leave it disabled initially, each sample would leave a data point on the minor tick marks and there would be 256 minor tick/grid marks per second ( just under 4 mSec a sample )

    The reason I would leave the minor grid/tick disabled initially would be clarity, I would perhaps use a button or checkbox to "switch" the minor grid on and off whenever I zoomed into the chart, here is a sample

    Code:
    Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
    
            If CheckBox1.Checked Then
    
                With Chart1.ChartAreas(0).AxisX
                    .MinorGrid.Enabled = True
                    .MinorTickMark.Enabled = True
                    .MinorGrid.Interval = 1
                    .MinorTickMark.Interval = 1
                    .MinorTickMark.Size = 5
                End With
    
            Else
    
                With Chart1.ChartAreas(0).AxisX
                    .MinorGrid.Enabled = False
                    .MinorTickMark.Enabled = False
                End With
    
            End If
    
    
        End Sub
    I would also adjust the initial scale of the chart.

    Code:
     Chart1.ChartAreas(0).AxisX.ScaleView.Zoom(0, 600)
    Looking at the progress you have made with MSChart you probably have more knowledge of it than I do, what I say is not set in stone they are just the thoughts I might have if I were to tackle the same problem.

  16. #16

    Thread Starter
    Lively Member
    Join Date
    Jul 2017
    Posts
    73

    Re: problem in handling multiple Bytes received using Serial Port

    Hello All,

    Finally I've been able to plot the graph with different sweep speeds . Thanks to dbasnett for helping me out!!
    I didn't use MS Chart for now because learning would take me long time and I have my project deadline in July!

    Cheers !!!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width