dcsimg
Results 1 to 23 of 23
  1. #1

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    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
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    98,681

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Pointless Forest 38.517,-92.023
    Posts
    9,008

    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
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    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
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    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
    Pointless Forest 38.517,-92.023
    Posts
    9,008

    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
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    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
    Pointless Forest 38.517,-92.023
    Posts
    9,008

    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

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    Re: problem in handling multiple Bytes received using Serial Port

    Ok, Then I will go with sending and receiving Bytes . However, What I doubt is that will I be Able to achieve the plotting speed which I require Using PaintEvent of a control.

    My ADC sampling Rate is 256 samples/Second . Basically I want the sweep speed till 100mm/Sec in my case. It can be greater ofcourse But will I be able to achieve it?

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,410

    Re: problem in handling multiple Bytes received using Serial Port

    I do that type of thing regularly.
    I have data coming in from multiple sources at relatively fast frequency.
    I update the GUI at 10hz, based on a timer tick.
    The information coming in is stored in an area that the GUI can see it, so it updates the GUI with the latest data available for all items received, as necessary.

    What I was thinking when you first posted, is that I would simply push whatever bytes were received into a concurrent queue, and that would take care of the RS-232 receiving side. It wouldn't do any pre-processing, it would just be responsible for receiving bytes as fast as they come in and push them on to a concurrent queue which would be available from both threads, with the control handshaking taken care of automatically.

    Then, when the 10hz GUI timer tick occurs, the GUI code would pull the data from the queue in 8-byte chunks. If there were less than 8-bytes left in the queue, it would leave those there and pick them up the next tick.
    You would then process all the chunks you've pulled from the queue, and update the display. If you want to update the GUI faster than 10hz, then you should be able to do that. The GUI updates should not hangup the serial data processing, and vice versa.

    You would be updating the graph, not one data point at a time (256 hz), but several data points at a time. For instance, since the screen can't really refresh faster than 60 hz, if you used a timer firing at 15ms, it should end up firing at 64hz, so you would be updating 4 points in your plot per update.
    As long as you're plotting all 256 points received per second, it probably would look fine even if you updated at 30hz or 20hz since the user will see all the points forming the wave shape in a reasonable approximation of real-time update.
    Last edited by passel; May 21st, 2018 at 09:23 AM.

  11. #11
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Pointless Forest 38.517,-92.023
    Posts
    9,008

    Re: problem in handling multiple Bytes received using Serial Port

    Quote Originally Posted by sumit11 View Post
    Ok, Then I will go with sending and receiving Bytes . However, What I doubt is that will I be Able to achieve the plotting speed which I require Using PaintEvent of a control.

    My ADC sampling Rate is 256 samples/Second . Basically I want the sweep speed till 100mm/Sec in my case. It can be greater ofcourse But will I be able to achieve it?
    If each sample is 8 bytes sent that equates to 16Kbps, so the serial port will not have a problem with that. Paint wise I don't know, but it seems reasonable.
    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

  12. #12

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    Re: problem in handling multiple Bytes received using Serial Port

    Hello Passel,

    Whoa! That's a long explanation. I was able to understand the bottom line of your explanation that I will have to plot multiple points at a time.

    I tried to implement the code given by dbasnett , However I'am not sure if I'am passing the data correctly using delegate.

    How to break the data from the buffer into individual Bytes?

    Code:
    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.Invoke(New Action(Of Byte())(AddressOf DrawGraph), rcvBuf)
            Loop
        End Sub
    
        Private Sub DrawGraph(data As Byte())
    
            Dim result1, result2, result3, result4, result5, result6, result7, result8 As UInt32
            Dim indata1, indata2, indata3, indata4 As UInt32
            
    
            result1 = data(0)
            result3 = data(2)
            result2 = data(1)
            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)
    
    
        End Sub

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,410

    Re: problem in handling multiple Bytes received using Serial Port

    Well, the code looks like it should work technically.
    The code is simply saying
    Code:
      While there are 8 or more bytes in the received list of bytes.
          Transfer 8 bytes from the received list to the msgBuf List {get first 8 bytes from received list and store in msgBuf list, remove the 8 bytes from the received list}
          Copy the bytes (8 of them) from msgBuf to rcvBuf.
          Invoke the DrawGraph sub on the Gui thread, passing the 8 byte array (rcvBuf) to DrawGraph.
       Loop back to see if we have 8 or more bytes still in the received list
    As for how to break the data from the buffer into individual Bytes, you've already done that, essentially. rcvBuf is a byte array so the first byte is in rcvBuf(0), the second byte in rcvBuf(1), etc...

    But I don't know why you're asking about accessing the individual bytes at this point.

    As for needing to draw multiple points at a time, it may not be absolutely necessary, but a lot depends on how you're doing the drawing. Is the Wave suppose to scroll, or will the wave draw from left to right, then start over at the left again. How efficient is the drawing, etc...

    The main drawbacks I see with this approach is that DrawGraph will be called for each data point (i.e. 8 bytes), so you will need to redraw the graph for each set of 8 bytes received, unless you implement some kind of arbitrary point counter in DrawGraph that will collect the information from the messages and only actually draw the graph when it has received a number of points.

    The other drawback is because you're using Invoke, the code will pause at that point, suspending in the DataReceived thread until the DrawGraph routine has finished doing whatever it is going to do. You could try using BeginInvoke instead. That will allow the code in the loop to continue and for your DataReceived event to finish without waiting for the DrawGraph call to complete. This means you will be processing the Data Received in parallel to the DrawGraph code running on the GUI thread. Because the messBuf bytes are copied into a local array and sent, perhaps the local array will not be clobbered by successive messages before being processed on the GUI thread, but I'm not sure.

    Since what you have seems like it should work, have you tried it and not seen it work.
    Since you added the invoke line, I'll assume it is expecting an array of bytes to be passed to it. If you put a breakpoint in the DrawGraph method, are you getting there and does the array passed have the 8 bytes you expect in it?
    Are you trying to draw?

    p.s. The code is also assuming that you are synchronized had haven't lost any bytes in the transfer so you're reading the 8 bytes that belong together, rather than some number of bytes from one message and the rest from the next.
    For instance, the mouse protocol (back when mice were mostly serial) would usually be a 3 to 5 byte message, and the most significant bit of the first byte (which could be bit 7 for an 8n1 protocol, or bit 6 for a 7e1 or 7n1 protocol) would be set, but that bit would never be set in any of the other 2 to 4 bytes of data that made up the message. This allowed the reading software to identify what byte was the first in the sequence, and that when it saw that bit set again (the start of the next message) it could verify whether it collected the number of bytes it expected for a valid message. You might want to consider something like that if you have a known bit that won't be used for anything else in your data, or perhaps adding an extra byte with a set pattern that is sent first to sync up the receiver, so each transfer would be 9 bytes, with 8 bytes being your data, and the 1st byte just a synchronization character.
    Last edited by passel; May 23rd, 2018 at 11:16 AM.

  14. #14

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    Re: problem in handling multiple Bytes received using Serial Port

    Hello Passel,

    I need to draw the graph from left to right, then start over at left again.
    So, Suppose If I connect a sine wave analog signal on my four different ADC Input Channels(Pins), then My application need to plot the four individual sinewave's .
    Since My ADC Data is 12 Bits so I need to break each pin output into two Bytes on sending end and then receive the two Bytes and "OR" them again to make 12 Bits(original Data) . So four channels means I've to send and receive total 8 Bytes. So every 8 Bytes means 4 original samples.

    Also , I need to control the plotting speed(sweep) with different options like 5mm/Sec,10mm/Sec,25mm/Sec,50mm/Sec and 100mm/Sec.
    So If I select 100mm/Sec, the graph plot should scroll upto 100mm in one Second.

    The code which I've written with help of dbasnett (Thanks to him) till now is working. I checked by putting breakpoint in drawgraph function and also I used a richtextbox to display the incoming values. the incoming values match the ADC data.

    indata1 value is equivalent to value of first pin of ADC

    indata2 value is equivalent to value of second pin of ADC

    indata3 value is equivalent to value of third pin of ADC

    indata4 value is equivalent to value of fourth pin of ADC


    Now My next step is to draw the graph. I've read that I should not use picturebox for my application since picturebox is designed to hold a single image. Then should I use a panel?

    how to go about plotting the graph from here? I've not used paint handlers before .

  15. #15
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Pointless Forest 38.517,-92.023
    Posts
    9,008

    Re: problem in handling multiple Bytes received using Serial Port

    I can help with some of this

    First, repalce
    Code:
    Me.Invoke(New Action(Of Byte())(AddressOf DrawGraph), rcvBuf)
    with
    Code:
    DrawGraph(rcvBuf)
    Then your existing DrawGraph should look like this. There is a 'Stop' statement where your drawing code can go. The first part is to make sure that the code runs on the UI and that the buffer from serial port can't be overwritten

    Code:
        Private Sub DrawGraph(buf() As Byte)
            Static bufLock As New Threading.AutoResetEvent(True)
            bufLock.WaitOne()
            Me.BeginInvoke(Sub()
                               'make a copy of buf
                               Dim bufCpy() As Byte = DirectCast(buf.Clone, Byte())
                               bufLock.Set() 'unlock the door for other calls
    
                               Dim indata1 As Integer = 0
                               Dim indata2 As Integer = 0
                               Dim indata3 As Integer = 0
                               Dim indata4 As Integer = 0
    
                               ''create indata's from bufCpy
                               Const shftVal As Integer = 8
                               ''long version
                               'indata1 = bufCpy(0)
                               'indata1 = indata1 << shftVal 'shift 8
                               'indata1 = indata1 Or bufCpy(1) 'or in second byte
    
                               'short version
                               indata1 = (CInt(bufCpy(0))) << shftVal Or bufCpy(1)
                               indata2 = (CInt(bufCpy(2))) << shftVal Or bufCpy(3)
                               indata3 = (CInt(bufCpy(4))) << shftVal Or bufCpy(5)
                               indata4 = (CInt(bufCpy(6))) << shftVal Or bufCpy(7)
    
                               Stop 'replace the Stop with your graph drawing code
    
                           End Sub)
    
        End Sub
    There is an assumption in this about how the twelve bits of data was sent from the external device, so the code may need to be tweaked to reflect the actual format.
    Last edited by dbasnett; May 24th, 2018 at 10:20 AM.
    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

  16. #16

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    Re: problem in handling multiple Bytes received using Serial Port

    Hello dbasnett,

    Thanks for the edits in the code. Yes, It is also working.

    I tried plotting the graph with below code but the plotting speed is still a concern.

    Code:
     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
               
    
                DrawGraph(rcvBuf)
            Loop
                 
        End Sub
    
    
        Private Sub DrawGraph(buf() As Byte)
            Static bufLock As New Threading.AutoResetEvent(True)
            bufLock.WaitOne()
            Me.BeginInvoke(Sub()
                               'make a copy of buf
                               Dim bufCpy() As Byte = DirectCast(buf.Clone, Byte())
                               bufLock.Set() 'unlock the door for other calls
    
                               Dim indata1 As Integer = 0
                               Dim indata2 As Integer = 0
                               Dim indata3 As Integer = 0
                               Dim indata4 As Integer = 0
    
                               ''create indata's from bufCpy
                               Const shftVal As Integer = 8
                               ''long version
                               'indata1 = bufCpy(0)
                               'indata1 = indata1 << shftVal 'shift 8
                               'indata1 = indata1 Or bufCpy(1) 'or in second byte
    
                               'short version
                               indata1 = (CInt(bufCpy(0))) Or (bufCpy(1) << shftVal)
                               indata2 = (CInt(bufCpy(2))) Or (bufCpy(3) << shftVal)
                               indata3 = (CInt(bufCpy(4))) Or (bufCpy(5) << shftVal)
                               indata4 = (CInt(bufCpy(6))) Or (bufCpy(7) << shftVal)
                           
                               PrintX(indata1)
                              
                           End Sub)
    
        End Sub
    
    Public Function PrintX(ByVal Xvalue1 As UInt32) As Object
    
            Try
    
                x_start = 1
                y_start1 = PictureBox1.Height - 10
                mygraphics = PictureBox1.CreateGraphics
                mygraphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
    
                mygraphics.DrawLine(p2, x_start + k, y_start1 - temp_ahead1, x_start + (k + 1), y_start1 - Xvalue1)
                temp_ahead1 = Xvalue1
    
                k = k + 1
                If k = PictureBox1.Width Then
                    k = 0
                    PictureBox1.Refresh()
                End If
    
            Catch ex As Exception
            End Try
    
    
        End Function

  17. #17

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    Re: problem in handling multiple Bytes received using Serial Port

    what else could be the way to plot the graph?
    Last edited by sumit11; Yesterday at 03:35 AM.

  18. #18
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Pointless Forest 38.517,-92.023
    Posts
    9,008

    Re: problem in handling multiple Bytes received using Serial Port

    Quote Originally Posted by sumit11 View Post
    what else could be the way to plot the graph?
    So seeing a little more I changed the approach slightly.

    DrawGraph converts the data and adds it to a queue of a structure. It also starts a task to service the queue. The actual code for ALL drawing should go in GraphThem (I copied your code there).

    With this the data reception and the actual drawing are no longer coupled. PrintX is gone. The actual graphics code will have to be done by someone else, not my strong point.

    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)
    
            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
                DrawGraph(rcvBuf)
            Loop
    
        End Sub
    
        Private Structure InData
            Public indata1 As Integer
            Public indata2 As Integer
            Public indata3 As Integer
            Public indata4 As Integer
        End Structure
    
        Private Sub DrawGraph(buf() As Byte)
            '>>>>
            '
            Static DoPrint As Task
            If DoPrint Is Nothing Then
                DoPrint = Task.Run(Sub()
                                       GraphThem()
                                   End Sub)
            End If
            '
            '<<<<
    
            Static bufLock As New Threading.AutoResetEvent(True)
            bufLock.WaitOne()
            'make a copy of buf
            Dim bufCpy() As Byte = DirectCast(buf.Clone, Byte())
            bufLock.Set() 'unlock the door for other calls
    
            Dim rcvData As New InData
            ''create indata's from bufCpy
            Const shftVal As Integer = 8
    
            'short version
            rcvData.indata1 = (CInt(bufCpy(0))) Or (bufCpy(1) << shftVal)
            rcvData.indata2 = (CInt(bufCpy(2))) Or (bufCpy(3) << shftVal)
            rcvData.indata3 = (CInt(bufCpy(4))) Or (bufCpy(5) << shftVal)
            rcvData.indata4 = (CInt(bufCpy(6))) Or (bufCpy(7) << shftVal)
    
            InDataQ.Enqueue(rcvData)
            InDataQHasNew.Set()
        End Sub
    
        Private InDataQ As New Concurrent.ConcurrentQueue(Of InData)
        Private InDataQHasNew As New Threading.AutoResetEvent(False)
    
        Public Sub GraphThem()
            Do
                InDataQHasNew.WaitOne() 'wait for signal
                Do While InDataQ.Count > 0
                    Dim rcvData As InData
                    If InDataQ.TryDequeue(rcvData) Then
                        'got queue entry
                        Me.BeginInvoke(Sub()
                                           Try
                                               'inData1 - rcvData.indata1
                                               x_start = 1
                                               y_start1 = PictureBox1.Height - 10
                                               mygraphics = PictureBox1.CreateGraphics
                                               mygraphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
    
                                               mygraphics.DrawLine(p2, x_start + k, y_start1 - temp_ahead1, x_start + (k + 1), y_start1 - rcvData.indata1)
                                               temp_ahead1 = rcvData.indata1
    
                                               k = k + 1
                                               If k = PictureBox1.Width Then
                                                   k = 0
                                                   PictureBox1.Refresh()
                                               End If
    
                                               'indata2 - rcvData.indata2 etc.
    
                                           Catch ex As Exception
                                           End Try
    
                                       End Sub)
                    Else
                        'get  queue entry failed
                        Threading.Thread.Sleep(10) 'wait then try again
                    End If
                Loop
            Loop
        End Sub
    I have no way to test this but other than the drawing the code looks like it should work.

    edit: You changed how the two bytes were combined to create one value. It seemed odd but I did not change it.
    Last edited by dbasnett; Yesterday at 09:30 AM.
    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

  19. #19
    Addicted Member
    Join Date
    Nov 2011
    Posts
    161

    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

  20. #20

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    Re: problem in handling multiple Bytes received using Serial Port

    Hello dbasnett,

    Well , I didnt try to understand your latest edited code , just copied and pasted for the moment, but still the same result.
    wave plotting speed is same as it was using printx function!

    I've seen MS Chart control and it plots the signal really fast. However not much tutorial stuff is available regarding MS Chart online!
    specially the linegraph or spline graph feature.

  21. #21

    Thread Starter
    Junior Member
    Join Date
    Jul 2017
    Posts
    29

    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??

  22. #22
    Addicted Member
    Join Date
    Nov 2011
    Posts
    161

    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

  23. #23
    Addicted Member
    Join Date
    Nov 2011
    Posts
    161

    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

Posting Permissions

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



Featured


Click Here to Expand Forum to Full Width


×
We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.