Display graph while viewing graph data in realtime.
I am recieving bytes of data from t he comm port perfoming calculations and displaying the result.
I am new to Vb however in my code i was told I have to use delegates in order to display information the screen.
I also need t o display a graph.. How do I used delegates for the graph. I have only seen example using string pointers.
When I click on the button to generate graph the display reading start freak out...
Also sometime I get an error saying that the graph object already exist and the program crashes
my code below
Imports
Imports
System.IO.PortsImports
System.MathImports
System.Threading.ThreadImports
System.IOImports
System.Timers.TimerImports
System.Drawing.Drawing2D' Imports the System, System.IO.Ports and System.Threading.Thread namespaces so that e.g.
' System.IO.Ports.SerialPort may just be written as SerialPort, and System.EventArgs may just be
' written as EventArgs.
Public
Class MaxiTesterDim XmoveAsInteger = 3Private OldValueAsSingle = 0Private NewValueAsSingle = 0' This variable hold the weight of the car.Dim WeightAsInteger = 0Dim SpeedAsInteger = 0Dim RpmAsInteger = 0Dim PowerAsDouble = 0Dim TorqueAsDouble = 0Dim GforceAsDoubleDim TempOfAirAsSingleDim AtmosPressureAsSingleDim FrontalAreaAsSingleDim DragCoeffAsSingleDim SaeCorrectionAsDoubleDim AirDensityAsDoubleDim AerodynamicDragAsDoubleDim TotalForceAsDoubleDim RoadSpeedAsDoubleDim EngineRpmAsIntegerDim ElapsedTimeAsIntegerDim DutyCycleAsIntegerDim Gforce20AsDouble = 0Dim Gforce19AsDouble = 0Dim Gforce18AsDouble = 0Dim Gforce17AsDouble = 0Dim Gforce16AsDouble = 0Dim Gforce15AsDouble = 0Dim Gforce14AsDouble = 0Dim Gforce13AsDouble = 0Dim Gforce12AsDouble = 0Dim Gforce11AsDouble = 0Dim Gforce10AsDouble = 0Dim Gforce9AsDouble = 0Dim Gforce8AsDouble = 0Dim Gforce7AsDouble = 0Dim Gforce6AsDouble = 0Dim Gforce5AsDouble = 0Dim Gforce4AsDouble = 0Dim Gforce3AsDouble = 0Dim Gforce2AsDouble = 0Dim Gforce1AsDouble = 0Dim T1LowCountAsIntegerDim T1HighCountAsIntegerDim T2LowCountAsIntegerDim T2HighCountAsIntegerDim ZCALAsInteger = 2265Dim BitScaleFactorAsInteger = 180Dim T2CALAsInteger = 4403Dim ZactualAsIntegerDim KAsInteger = 697Dim AccelerationAsDoubleDim WheelPulsesHighAsIntegerDim WheelPulsesLowAsIntegerDim WheelRevolutionsAsDoubleDim DistanceAsDoubleDim GraphValueAsSingleDim GforceTotalAsDoubleDim GforceTotal1AsDoubleDim GforceTotal2AsDoubleDim PinsAsLongDim GforceAverageAsDoubleDim MilliSecondsPassedAsIntegerDim FileRecAsStringDim StartTimeAsDateDim RecordsWrittenAsInteger = 0Dim PinNumberAsInteger' Get a StreamReader class that can be used to read the fileDim objStreamWriterAsNew StreamWriter("c:\test.txt",True)' Declare a type-safe pointer to subroutines, which use one string as argument (like Display).' It is used as a pointer to the subroutine, which should handle a given event with string data (like' a received string, which should be displayed).PublicDelegateSub StringSubPointer(ByVal BufferAsString)DimWithEvents COMPortAsNew SerialPort' Make a new System.IO.Ports.SerialPort instance, which is able to send eventsPrivateSub Receiver(ByVal senderAsObject,ByVal eAs SerialDataReceivedEventArgs)Handles COMPort.DataReceivedDim RXByteAsByteDim RXArray(4)AsCharDim IAsInteger = 0Dim JAsInteger = 0Dim ByteValAsInteger = 0Dim SpeedstrAsStringDim RpmstrAsStringDim PowerstrAsStringDim TorqueStrAsStringDim GforceAverageStrAsStringDim GforceSignStrAsStringDim TiltStrAsStringDim DistanceStrAsStringDim ElapsedTimeStrAsStringDim MilliSecondsPassedStrAsStringDim GsensorPeriodAsIntegerDim GsensorHighPulseAsIntegerDim GsensorLowPulseAsIntegerDim WheelRevolutionsAsIntegerDim GraphValueAsIntegerRXByte = COMPort.ReadByte
While (COMPort.BytesToRead > 0)And (CInt(RXByte) <> 255)RXByte = COMPort.ReadByte
EndWhileWhile (COMPort.BytesToRead > 0)And (I < 9)RXByte = COMPort.ReadByte
ByteVal =
CInt(RXByte)If I = 0ThenSpeed = ByteVal
EndIfIf I = 1ThenRpm = ByteVal
EndIfIf I = 2ThenT1HighCount = ByteVal
EndIfIf I = 3ThenT1LowCount = ByteVal
EndIfIf I = 4ThenT2HighCount = ByteVal
EndIfIf I = 5ThenT2LowCount = ByteVal
EndIfIf I = 6ThenWheelPulsesHigh = ByteVal
EndIfIf I = 7ThenWheelPulsesLow = ByteVal
EndIfI = I + 1
EndWhileGsensorHighPulse = (T1HighCount * 256) + T1LowCount
GsensorLowPulse = (T2HighCount * 256) + T2LowCount
GsensorPeriod = GsensorLowPulse + GsensorHighPulse
WheelRevolutions = ((WheelPulsesHigh * 256) + WheelPulsesLow) / 4
Distance = WheelRevolutions * 1.82
Zactual = ZCAL * GsensorPeriod / T2CAL
Acceleration = K * (GsensorHighPulse - Zactual) / GsensorPeriod
Gforce = Acceleration / 90
If Gforce > 0ThenGforceSignStr =
"^"ElseGforceSignStr =
"V"EndIfGforce20 = Gforce19
Gforce19 = Gforce18
Gforce18 = Gforce17
Gforce17 = Gforce16
Gforce16 = Gforce15
Gforce15 = Gforce14
Gforce14 = Gforce13
Gforce13 = Gforce12
Gforce12 = Gforce11
Gforce11 = Gforce10
Gforce10 = Gforce9
Gforce9 = Gforce8
Gforce8 = Gforce7
Gforce7 = Gforce6
Gforce6 = Gforce5
Gforce5 = Gforce4
Gforce4 = Gforce3
Gforce3 = Gforce2
Gforce2 = Gforce1
Gforce1 = Gforce
GforceTotal1 = Gforce1 + Gforce2 + Gforce3 + Gforce4 + Gforce5 + Gforce6 + Gforce7 + Gforce8 + Gforce9 + Gforce10
GforceTotal2 = Gforce11 + Gforce12 + Gforce13 + Gforce14 + Gforce15 + Gforce16 + Gforce17 + Gforce18 + Gforce19 + Gforce20
GforceTotal = GforceTotal1 + GforceTotal2
GforceAverage = GforceTotal / 20
If GraphRadioButton.Checked =TrueThenGraphValue = Int(GforceAverage * 90)
'PictureBoxGraph.Image = DisplayGuidelinesAndChart(PictureBoxGraph, 12, 3, GraphValue, 0, 100)PictureBoxGraph.Image = DisplayGuidelinesAndChart(PictureBoxGraph, 10, 3, GraphValue, 0, 100)
EndIfRoadSpeed = (Speed / 4) * 1.8
EngineRpm = Rpm * 60
Rpmstr = EngineRpm
Speedstr = RoadSpeed * 3.6
DistanceStr = Distance
AerodynamicDrag = 0.5 * AirDensity * (RoadSpeed ^ 2) * DragCoeff * FrontalArea
TotalForce = (Weight * GforceAverage * 9.81) + AerodynamicDrag
Power = RoadSpeed * TotalForce * SaeCorrection * 0.001341
Torque = Power * 5252 / EngineRpm
GforceAverageStr = GforceAverage
TiltStr = Int(GforceAverage * 90)
Powerstr = Int(Power)
TorqueStr = Int(Torque)
ElapsedTime = DateDiff(
"s", StartTime, Now())ElapsedTimeStr = ElapsedTime
MilliSecondsPassedStr = MilliSecondsPassed
FileRec = MilliSecondsPassedStr +
" " + Powerstr +" " + TorqueStrDim RxStringAsNewString(GforceAverageStr)Dim SpeedstringAsNewString(Speedstr)Dim PowerstringAsNewString(Powerstr)Dim ElapsedTimeStringAsNewString(ElapsedTimeStr)Dim TorqueStringAsNewString(TorqueStr)Dim RpmStringAsNewString(Rpmstr)Dim GforceSignStringAsNewString(GforceSignStr)Dim TiltStringAsNewString(TiltStr)Dim DistanceStringAsNewString(DistanceStr)' Send RxString to the Display subrotine and return immediately.Received.BeginInvoke(
New StringSubPointer(AddressOf Display), RxString)' Send SpeedString to the Display subrotine and return immediately.SpeedOut.BeginInvoke(
New StringSubPointer(AddressOf Disspeed), Speedstring)' Send PowerString to the Display subrotine and return immediately.PowerOut.BeginInvoke(
New StringSubPointer(AddressOf Dispower), Powerstring)' Send ElapsedTimeString to the Display subrotine and return immediately.ElapsedTimeOut.BeginInvoke(
New StringSubPointer(AddressOf DisTime), ElapsedTimeString)' Send TorqueString to the Display subrotine and return immediately.TorqueOut.BeginInvoke(
New StringSubPointer(AddressOf DisTorque), TorqueString)' Send RpmString to the Display subrotine and return immediately.RpmOut.BeginInvoke(
New StringSubPointer(AddressOf DisRpm), RpmString)' Send GforceSignString to the Display subrotine and return immediately.GforceSignOut.BeginInvoke(
New StringSubPointer(AddressOf DisSign), GforceSignString)' Send TiltString to the Display subrotine and return immediately.TiltOut.BeginInvoke(
New StringSubPointer(AddressOf DisTilt), TiltString)' Send DistanceString to the Display subrotine and return immediately.DistanceOut.BeginInvoke(
New StringSubPointer(AddressOf DisDistance), DistanceString)EndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub Display(ByVal BufferAsString)Received.Text = Buffer
EndSub' This subroutine will fire when the elapsed time event' has been reached.' The label is set to the current time after the' interval has been reached.PrivateSub systemTimer_Elapsed(ByVal senderAs System.Object,ByVal eAs System.Timers.ElapsedEventArgs)Handles Timer1.ElapsedIf RecordsWritten < 20000Then'Write a line of text.objStreamWriter.WriteLine(FileRec)
RecordsWritten = RecordsWritten + 1
MilliSecondsPassed = MilliSecondsPassed + 200
EndIfEndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub Disspeed(ByVal BufferAsString)SpeedOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub Dispower(ByVal BufferAsString)PowerOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub DisTime(ByVal BufferAsString)ElapsedTimeOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub DisTorque(ByVal BufferAsString)TorqueOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Rpm Label form.PrivateSub DisRpm(ByVal BufferAsString)RpmOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Rpm Label form.PrivateSub DisSign(ByVal BufferAsString)GforceSignOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub DisTilt(ByVal BufferAsString)TiltOut.Text = Buffer
EndSub' Text display routine, which displays the received string to any text in the Received TextBox form.PrivateSub DisDistance(ByVal BufferAsString)DistanceOut.Text = Buffer
EndSub' This subroutine handles a change in Baud Rate.PrivateSub BaudRate(ByVal senderAsObject,ByVal eAs EventArgs)Handles BaudRateBox.SelectedIndexChangedCOMPort.BaudRate =
CInt(BaudRateBox.Text)EndSub' This subroutine handles a change of COM ports.PrivateSub COMPortsBox_SelectedIndexChanged(ByVal senderAsObject,ByVal eAs EventArgs)Handles COMPortsBox.SelectedIndexChangedIf COMPort.IsOpenThenCOMPort.RtsEnable =
FalseCOMPort.DtrEnable =
FalseCOMPort.Close()
Application.DoEvents()
' Let all applications finish before the whole process goes to sleep.Sleep(500)
' Wait 0.5 second for port to close as this do not happen immediately.EndIfCOMPort.PortName = COMPortsBox.Text
' Default: 9600 Baud, 8 data bits, no parity, 1 stop bitCOMPort.ReadBufferSize = 40
TryCOMPort.Open()
Catch exAs Exception' MsgBox(ex.Message)EndTryStartTime = Now()
TempTextbox.Text =
"32"PressureTextBox.Text =
"1013"AreaTextBox.Text =
"2"DragTextBox.Text =
"0.45"WeightTextBox.Text =
"920"TempOfAir =
CInt(TempTextbox.Text)AtmosPressure =
CInt(PressureTextBox.Text)FrontalArea =
CInt(AreaTextBox.Text)DragCoeff = DragTextBox.Text
Weight =
CInt(WeightTextBox.Text)SaeCorrection = (1.18 * ((990 / AtmosPressure) * Sqrt((TempOfAir + 273.15) / 298))) - 0.18
AirDensity = 0.0412236 * AtmosPressure / (TempOfAir + 273.15)
Timer1.Start()
If COMPortIsNothingThenBaudRateBox.Text =
""ElseBaudRateBox.Text = COMPort.BaudRate
COMPort.RtsEnable =
FalseCOMPort.DtrEnable =
FalseCOMPort.ReceivedBytesThreshold = 40
EndIfEndSub' This subroutine is activated when the form is loaded. It does all the basic initializations.' RTS/CTS hardware flow control is necessary for Max-i communication. Note that the standard UART 16C550' has no hardware flow control - except for UART's from Texas Instruments.' The minimum FIFO size is calculated on the basis of a 1.4 mS response time, which is the absolute minimum' for Windows applications.PrivateSub MaxiTester_Load(ByVal senderAsObject,ByVal eAs EventArgs)HandlesMyBase.LoadForEach COMStringAsStringInMy.Computer.Ports.SerialPortNames' Load all available COM ports.COMPortsBox.Items.Add(COMString)
NextCOMPortsBox.Sorted =
TrueBaudRateBox.Items.Add(
"9600")BaudRateBox.Items.Add(
"57600")' Add the pin numbers 0 to 15 to cboPinNumberFor Pins = 0To 7ComboBoxPinNumber.Items.Add(
CStr(Pins))Next PinspicValues.Image = DisplayVerticalValues(picValues, 20, 0, 100)
EndSub' This subroutine is activated when the form is closed. It closes the COM port. Without such a close command,' the garbage collector may close the COM port while it is still in use!PrivateSub MaxiTester_Closing(ByVal senderAsObject,ByVal eAs ComponentModel.CancelEventArgs)HandlesMyBase.ClosingIf COMPort.IsOpenThen COMPort.Close()' Close COM port when the form is terminated with [X]'Close the file.objStreamWriter.Close()
Timer1.Stop()
EndSubPrivateSub Button1_Click(ByVal senderAs System.Object,ByVal eAs System.EventArgs)Handles Button1.ClickDim SendByteAsInteger' Get Pin NumberSendByte = PinNumber
COMPort.Write(Chr(SendByte))
' Get Pin StateIf RadioButtonOff.Checked =TrueThenSendByte = 0
EndIfIf RadioButtonOn.Checked =TrueThenSendByte = 1
EndIfCOMPort.Write(Chr(SendByte))
EndSub' This subroutine handles a change in Pin Number.PrivateSub PicPinNumber(ByVal senderAsObject,ByVal eAs EventArgs)Handles ComboBoxPinNumber.SelectedIndexChangedPinNumber =
CInt(ComboBoxPinNumber.Text)EndSubPrivateFunction DisplayGuidelinesAndChart(ByVal PicBoxAs PictureBox,ByVal chunksAsInteger,ByVal XMoveAsInteger,ByVal NewValueAsSingle,ByVal MinAsSingle,ByVal MaxAsSingle)As Bitmap' Step 1' Grab the current image (the latest version of the chart)Dim bmAsNew Bitmap(PicBox.Width, PicBox.Height)Dim grAs Graphics = Graphics.FromImage(bm)' Step 2' Get the total height available and split it into chunksDim totalAsInteger = PicBox.HeightDim chunkAsSingle = total / chunks' Tack missing guidelines to right hand side on the Graphics object.For iAsSingle = chunkTo totalStep chunkgr.DrawLine(Pens.WhiteSmoke, PicBox.Width - XMove, i, PicBox.Width, i)
Next i' Step 3' Draw this grabbed image, placing it XMove pixels to the leftIfNot IsNothing(PicBox.Image)Thengr.DrawImage(PicBox.Image, -XMove, 0)
EndIf' Step 4' Plot the new value.' Calculate the scaling required to make full use of the height of' the PictureBoxDim ValueRangeAsSingle = Max - MinDim vScaleAsSingle = PicBox.Height / ValueRange' Apply the scale to the current valueNewValue *= vScale
' Step 5' Shift start point from top left to bottom left.gr.TranslateTransform(0, PictureBoxGraph.Height)
' Step 6' Draw the next line segment on the Graphics object.' If Min is > 0 then you need to shift the drawing down once again,' this time to put the Min value on the horizontal axisIf Min > 0Then gr.TranslateTransform(0, Min * vScale)gr.DrawLine(Pens.Black, _
PictureBoxGraph.Width - 1 - XMove, -OldValue, _
PictureBoxGraph.Width - 1, -NewValue)
OldValue = NewValue
' Step 7' Return the Bitmap .Return bm' Step 8' All donegr.Dispose()
EndFunctionPrivateFunction DisplayVerticalValues(ByVal PBAs PictureBox,ByVal HowManyChunksAsSingle, _ByVal MinValueAsSingle,ByVal MaxValueAsSingle)As Bitmap' Step 1Dim bmpAsNew Bitmap(PB.Width, PB.Height)Dim gvAs Graphics = Graphics.FromImage(bmp)' Step 2' Draw guidelines on values strip' Get the total height available and split it into chunks' This value represents a number of pixelsDim TotalPixelsAsInteger = PB.HeightDim SingleChunkAsSingle = TotalPixels / HowManyChunksFor iAsSingle = SingleChunkTo TotalPixelsStep SingleChunkgv.DrawLine(Pens.WhiteSmoke, 0, i, PB.Width, i)
Next i' Step 3' Draw Numbers as Text, correctly spaced vertically' Begin with the highest value allowedDim NextMarkerAsInteger = MaxValueDim ValueRangeAsSingle = MaxValue - MinValue' Draw the numbers, decrementing values proportionately each time through the loopFor iAsSingle = 0To TotalPixelsStep SingleChunkgv.DrawString(
CStr(NextMarker),New Font("Verdana", 8, FontStyle.Regular), Brushes.Black, 1, i)NextMarker -= (ValueRange / HowManyChunks)
Next' Step 4Return bmp' Step 5gv.Dispose()
EndFunctionEnd
Class
