-
May 17th, 2018, 07:06 AM
#1
Thread Starter
Lively Member
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.
-
May 17th, 2018, 07:23 AM
#2
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:
Private Sub DrawGraph(data As Byte())
vb.net Code:
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.
-
May 17th, 2018, 09:03 AM
#3
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
-
May 19th, 2018, 04:30 AM
#4
Thread Starter
Lively Member
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.
-
May 21st, 2018, 02:12 AM
#5
Thread Starter
Lively Member
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!
-
May 21st, 2018, 08:13 AM
#6
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)?
-
May 21st, 2018, 08:27 AM
#7
Thread Starter
Lively Member
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?
-
May 21st, 2018, 08:41 AM
#8
Re: problem in handling multiple Bytes received using Serial Port
Originally Posted by sumit11
...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.
-
May 25th, 2018, 09:17 AM
#9
Addicted Member
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
-
May 25th, 2018, 09:52 AM
#10
Thread Starter
Lively Member
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??
-
May 25th, 2018, 11:32 AM
#11
Addicted Member
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
-
May 25th, 2018, 11:58 AM
#12
Addicted Member
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
-
May 28th, 2018, 09:15 AM
#13
Thread Starter
Lively Member
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
-
May 28th, 2018, 09:18 AM
#14
Thread Starter
Lively Member
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
-
May 28th, 2018, 11:15 AM
#15
Addicted Member
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.
-
May 30th, 2018, 04:06 AM
#16
Thread Starter
Lively Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|