-
Feb 4th, 2018, 06:53 PM
#1
Thread Starter
Lively Member
[RESOLVED] Slowdown on COM port write after 12k characters
My program communicates with an arduino over a serial port. It sends one byte at a time every 50ms. The arduino can read them much faster than that speed. After about 12,200 bytes are sent there is a dramatic slow down in the transmission rate to about 1 byte every second or so. The bottle neck is the com port write. I have been chasing this for a couple days and now believe it has something to do with the serial port write. If I stop the program and then restart it, the speed is fine until another 12,200 bytes are sent. That figure is + or - about 100 bytes, I couldn't measure it any closer than that.
Is there a limit to how many single bytes can be sent after a single com port open? Is there a requirement on the receiving end to do something other than simply receive the byte? I just don't understand why it slows down. The open routine is called only once and the write routine is called at 50ms intervals.
There are no error messages, the only problem is the slowdown.
Here is the com port configuration and the serialport.write routine.
Code:
Private Sub Start_Com_Port()
Try
SERIALPORT.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
If COMPORT = "" Then
For Each sp As String In My.Computer.Ports.SerialPortNames
fCom_Port.Items.Add(sp)
If fCom_Port.Items.Count > 0 Then
fCom_Port.SelectedIndex = 0
End If
Next
End If
fCom_Port.Items.Add(COMPORT)
fCom_Port.SelectedIndex = 0
With SERIALPORT
Try
SERIALPORT.PortName = fCom_Port.SelectedItem
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
.BaudRate = 115200
.DataBits = 8
.Parity = Parity.None
.StopBits = StopBits.One
.Handshake = Handshake.None
End With
Try
SERIALPORT.Open()
Catch ex As Exception
MsgBox("Port " & SERIALPORT.PortName & vbCrLf & ex.Message)
End Try
End Sub
Private count As Long = 0
Private Sub writeData(dat As Byte)
count += 1
fTotal_Coil_Steps.Text = count
Try
SERIALPORT.Write(dat)
Catch ex As Exception
MessageBox.Show("Serial Port Write Error" & ex.Message)
End Try
End Sub
-
Feb 4th, 2018, 09:44 PM
#2
Re: Slowdown on COM port write after 12k characters
I don't see the code that calls writeData.
You may have recursive code there, we can't tell from here.
-
Feb 4th, 2018, 09:58 PM
#3
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Here is the whole thing:
Code:
Imports System.IO.Ports
Public Class Form1
Private WithEvents T1 As New FastTimer ' High accuracy timer class
' program variables
Private MYCHAR As String ' Buffer for the received serial character
Private PNT As Point ' Point for the location of the coil drawing
Private SETUPFLAG As Boolean = True ' Flag to prevent execution of events until setup is done
Private FORWARD As Boolean = True ' Direction flag for the slide
Private JFORWARD As Boolean ' The jog direction
Private MYINDEX As Integer ' Index to the wire information table
' User inputs
Private COREOD As Single ' Diameter of the finished coil
Private COREID As Single ' Diameter of the coil form ID
Private CORELENGTH As Single ' Length of the coil form
Private WIREGAUGE As Single ' Gauge of the wire
Private TOTALWINDINGS As Single ' Total number of winding in the coil
Private COMPORT As String ' Text of the Comm Port number ie. "COM1"
Private SERIALPORT As New SerialPort ' The io serial port
Private PORTADDRESS As Integer ' Serial port address
Private STEPANGLE As Single ' Angular rotation of one motor step
' Calculated values
Private WIREDIAMETER As Single ' Diameter of the wire from the wire table
Private RESISTANCEPER1000 As Single ' Resistance per 1000 feet of wire from the wire table
Private MAXAMPS As Single ' The maximum coil amps from the wire table
Private INCHPERSTEP As Single ' Distance the slide travels in one step
Private LEADSCREW_TPI As Single ' The threads per inch for both lead screws
Private CURRENTCOILDIAMETER As Single ' The current diameter of the coil for drawing it
Private TOTALSTEPSINCOIL As Long ' Total number of steps in the coil
Private TOTALLAYERSINCOIL As Single ' Total number of layers in the coil
Private TOTALFEETOFWIREINCOIL As Single ' Total feet of wire for the coil
' Step, Rev, Coil and Layer counters
Private WINDSTEPCOUNTER As Long ' Winder step counter
Private WINDERSTEPSPERREV As Integer ' Winder steps for 1 turn
Private WINDSCOUNTED As Integer ' Number of winds finished
Private SLIDESTEPCOUNTER As Integer ' Slide step counter (position of the slide)
Private SLIDESTEPSPERLAYER As Integer ' Slide steps for 1 layer
Private LAYERSCOUNTED As Integer ' Number of layers finished
Private WINDSSPERLAYER As Single ' Number of winds per layer
Private SLIDESTEPRATIO As Integer ' Number of winder steps per slide step
Private CURRENTCOREDIAMETER As Single ' The current diameter of the coil
Private Sub setup()
Read_Registry_Data()
Start_Com_Port()
Initialise_Buttons()
Initialize_Constants()
Process_Screen_Data()
PanelCore.Show()
TOTALSTEPSINCOIL = 0 ' Total number of steps in the coil
SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP * WINDSSPERLAYER
If fWhole_Layer.Checked Then
TOTALWINDINGS = (TOTALLAYERSINCOIL - 1) * WINDSSPERLAYER
fTotal_Windings.Text = TOTALWINDINGS
End If
SETUPFLAG = False
End Sub
' ********************************
' ignore 48 // 0
' set_ratio 49 // 1
' winder_omly 50 // 2
' slide_forward 51 // 3
' slide_reverse 52 // 4
' slide_forward_winder 53 // 5
' slide_reverse_winder 54 // 6
' stop_motors 55 // 7
' ignore all others //
' ********************************
Private Sub Process_Screen_Data()
COREID = fCore_ID.Text ' Diameter of the coil form core
CORELENGTH = fCore_Length.Text ' Length of the coil form core
WIREGAUGE = fWire_Gauge.Text ' The wire gauge
TOTALWINDINGS = fTotal_Windings.Text ' Total number of windings
WINDSTEPCOUNTER = 0 ' Winder step counter
WINDSCOUNTED = 0 ' Number of winds finished
fWind_Count.Text = WINDSCOUNTED
SLIDESTEPCOUNTER = 0 ' Slide step counter (position of the slide)
fSlide_Steps.Text = SLIDESTEPCOUNTER
LAYERSCOUNTED = 0 ' Number of layers finished
fLayer_Count.Text = LAYERSCOUNTED
If fWhole_Layer.Checked Then
TOTALWINDINGS = (TOTALLAYERSINCOIL - 1) * WINDSSPERLAYER
fTotal_Windings.Text = TOTALWINDINGS
End If
Dim WIRE_DATA As Object
' WIRE DATA TAKEN FROM http://www.powerstream.com/Wire_Size.htm
' DIA OHM/kFT AMPS AWG
WIRE_DATA = {
0.032, 10.15, 11, '20
0.0285, 12.8, 9, '21
0.0253, 16.14, 7, '22
0.0226, 20.36, 4.7, '23
0.0201, 25.67, 3.5, '24
0.0179, 32.37, 2.7, '25
0.0159, 40.81, 2.2, '26
0.0142, 51.47, 1.7, '27
0.0126, 64.9, 1.4, '28
0.0113, 81.83, 1.2, '29
0.01, 103.2, 0.86, '30
0.0089, 130.1, 0.7, '31
0.008, 164.1, 0.53, '32
0.0071, 206.9, 0.43, '33
0.0063, 260.9, 0.33, '34
0.0056, 329.0, 0.27, '35
0.005, 414.8, 0.21, '36
0.0045, 523.1, 0.17, '37
0.004, 659.6, 0.13, '38
0.0035, 831.8, 0.11, '39
0.0031, 1049, 0.09 '40
}
WIREGAUGE = CSng(Me.fWire_Gauge.Text)
If WIREGAUGE < 20.0 Then
WIREGAUGE = 20
fWire_Gauge.Text = 20
End If
If WIREGAUGE > 40.0 Then
WIREGAUGE = 40
fWire_Gauge.Text = 40
End If
' Calculate the array index
MYINDEX = (WIREGAUGE - 20) * 3 + 1
' Calculate the wire diameter fron the gauge
WIREDIAMETER = WIRE_DATA(MYINDEX - 1)
RESISTANCEPER1000 = WIRE_DATA(MYINDEX)
MAXAMPS = WIRE_DATA(MYINDEX + 1)
MYINDEX = (WIREGAUGE - 20) * 3 + 1
' Calculate the wire diameter fron the gauge
WIREDIAMETER = WIRE_DATA(MYINDEX - 1)
RESISTANCEPER1000 = WIRE_DATA(MYINDEX)
MAXAMPS = WIRE_DATA(MYINDEX + 1)
WINDSSPERLAYER = CLng(Convert.ToSingle(fCore_Length.Text) / (WIREDIAMETER))
TOTALLAYERSINCOIL = TOTALWINDINGS / WINDSSPERLAYER + 1
SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP
End Sub
Private Sub Initialize_Constants()
STEPANGLE = 1.8 ' Each motor step rotates the shaft this many degrees
LEADSCREW_TPI = 8 ' 8 Thread Per Inch
WINDERSTEPSPERREV = 360 / STEPANGLE ' Number of steps for each turn of the cioil
INCHPERSTEP = 1.0 / LEADSCREW_TPI / WINDERSTEPSPERREV ' Distance the slide moves for each step
End Sub
Private Sub Control_The_Motors() ' turn the winder and carriage
writeData("2") ' 2 = winder step
WINDSTEPCOUNTER += 1
' Have we finished a wind?
If WINDSTEPCOUNTER Mod WINDERSTEPSPERREV = 0 Then
WINDSCOUNTED += 1
fWind_Count.Text = WINDSCOUNTED ' Update the screen
End If
'Do we need to step the slide?
If WINDSTEPCOUNTER Mod SLIDESTEPRATIO = 0 Then
If FORWARD Then
writeData("3") ' 3 = step the slide forward
SLIDESTEPCOUNTER += 1
Else
writeData("4") ' 4 = step the slide backward
SLIDESTEPCOUNTER -= 1
End If
fSlide_Steps.Text = SLIDESTEPCOUNTER ' Update the screen
' reverse the slide direction if we are at either end of travel
If SLIDESTEPCOUNTER Mod SLIDESTEPSPERLAYER = 0 Then
FORWARD = Not (FORWARD) ' reverse it
CURRENTCOILDIAMETER += (WIREDIAMETER * 2) ' increase the current coil diameter
DrawCoil() ' Draw the coil
LAYERSCOUNTED += 1
fLayer_Count.Text = LAYERSCOUNTED
End If
End If
' have we finsihed the coil?
If WINDSTEPCOUNTER = WINDERSTEPSPERREV * TOTALWINDINGS Then
writeData("7") ' turn off the motors
T1.Stop() ' stop the run loop
End If
End Sub
Private Sub Read_Registry_Data()
' Read the registry data
COREID = GetSetting("COILWINDER", "STARTUP", "COREID", "0.25")
CORELENGTH = GetSetting("COILWINDER", "STARTUP", "LENGTH", "0.5")
WIREGAUGE = GetSetting("COILWINDER", "STARTUP", "WIREGAUGE", "20")
TOTALWINDINGS = GetSetting("COILWINDER", "STARTUP", "WINDINGS", "250")
COMPORT = GetSetting("COILWINDER", "STARTUP", "COMPORT", "COM1")
fWhole_Layer.Checked = GetSetting("COILWINDER", "STARTUP", "WHOLELAYER", fWhole_Layer.Checked)
fCore_ID.Text = COREID
fCore_Length.Text = CORELENGTH
fWire_Gauge.Text = WIREGAUGE
fTotal_Windings.Text = TOTALWINDINGS
If fWhole_Layer.Checked Then
fExact_Turns.Checked = False
Else
fExact_Turns.Checked = True
End If
End Sub
Private Sub Save_Registry_Data()
SaveSetting("COILWINDER", "STARTUP", "COREID", fCore_ID.Text)
SaveSetting("COILWINDER", "STARTUP", "LENGTH", fCore_Length.Text)
SaveSetting("COILWINDER", "STARTUP", "WIREGAUGE", fWire_Gauge.Text)
SaveSetting("COILWINDER", "STARTUP", "WINDINGS", fTotal_Windings.Text)
SaveSetting("COILWINDER", "STARTUP", "WholeLayer", fWhole_Layer.Checked)
SaveSetting("COILWINDER", "STARTUP", "COMPORT", COMPORT)
End Sub
Private Sub Start_Com_Port()
Try
SERIALPORT.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
If COMPORT = "" Then
For Each sp As String In My.Computer.Ports.SerialPortNames
fCom_Port.Items.Add(sp)
If fCom_Port.Items.Count > 0 Then
fCom_Port.SelectedIndex = 0
End If
Next
End If
fCom_Port.Items.Add(COMPORT)
fCom_Port.SelectedIndex = 0
With SERIALPORT
Try
SERIALPORT.PortName = fCom_Port.SelectedItem
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
.BaudRate = 115200
.DataBits = 8
.Parity = Parity.None
.StopBits = StopBits.One
.Handshake = Handshake.None
End With
Try
SERIALPORT.Open()
Catch ex As Exception
MsgBox("Port " & SERIALPORT.PortName & vbCrLf & ex.Message)
End Try
End Sub
Private Sub Initialise_Buttons()
fCalculate_Button.Enabled = True
fStart_Button.Enabled = False
fLeft_Button.Enabled = False
fRight_Button.Enabled = False
fPause_Button.Enabled = False
fContinue_Button.Enabled = False
fReset_Button.Enabled = True
End Sub
Private Sub Calculate()
Process_Screen_Data()
fWire_Diameter.Text = WIREDIAMETER
WIREGAUGE = CLng(Me.fWire_Gauge.Text)
' CALCULATE STEP RATIO
SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP
SLIDESTEPRATIO = WINDERSTEPSPERREV / SLIDESTEPSPERLAYER
fStep_Ratio.Text = SLIDESTEPRATIO
' CALCULATE WINDINGS PER LAYER
WINDSSPERLAYER = CLng(Convert.ToSingle(fCore_Length.Text) / (WIREDIAMETER))
fWinds_Per_Layer.Text = WINDSSPERLAYER
' CALCULATE LAYERS
If fExact_Turns.Checked Then
TOTALWINDINGS = fTotal_Windings.Text
Else
TOTALWINDINGS = TOTALLAYERSINCOIL * WINDSSPERLAYER
End If
TOTALLAYERSINCOIL = TOTALWINDINGS / WINDSSPERLAYER + 1
fTotal_Layers.Text = Format(TOTALLAYERSINCOIL, "###.00")
SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP * WINDSSPERLAYER
fSlide_Steps_Per_Layer.Text = SLIDESTEPSPERLAYER
TOTALFEETOFWIREINCOIL = 0
' LOOP THROUGH ALL LAYERS
Dim cd, id, wd As Single
For I = 1 To TOTALLAYERSINCOIL - 1
cd = COREID
id = I - 1
wd = WIREDIAMETER
COREOD = Format(cd + id * wd * 2.0, "000.00")
TOTALFEETOFWIREINCOIL += Format((3.14159265358979 * COREID * WINDSSPERLAYER / 12.0), "000.00")
Next I
TOTALSTEPSINCOIL = TOTALWINDINGS * WINDERSTEPSPERREV ' Total number of steps in the coil
fTotal_Coil_Steps.Text = Format(TOTALSTEPSINCOIL, "###,000")
fTotal_Feet.Text = Format(TOTALFEETOFWIREINCOIL, "##0.00")
fResistance.Text = Format(TOTALFEETOFWIREINCOIL * RESISTANCEPER1000 / 1000.0#, "###0.0")
fMaxVoltage.Text = Format(fResistance.Text * MAXAMPS, "####.0")
fTotal_Feet.Refresh()
fCore_OD.Text = COREOD
fTotal_Windings.Visible = True
fTotal_Windings.Height = CURRENTCOREDIAMETER
CURRENTCOILDIAMETER = COREOD + 2 * WIREDIAMETER
DrawCoil()
fCalculate_Button.Enabled = False
fLeft_Button.Enabled = True
fRight_Button.Enabled = True
fStart_Button.Enabled = True
If fWhole_Layer.Checked Then
TOTALWINDINGS = (TOTALLAYERSINCOIL - 1) * WINDSSPERLAYER
fTotal_Windings.Text = TOTALWINDINGS
End If
End Sub
Private Sub Data_Changed()
fCalculate_Button.Enabled = True
fStart_Button.Enabled = False
PanelCoil.Visible = False
PanelCore.Visible = True
' Process_Screen_Data()
Save_Registry_Data()
End Sub
' CHANGED
Private Sub Port_SelectedIndexChanged(sender As Object, e As EventArgs) Handles fCom_Port.SelectedIndexChanged
If SETUPFLAG Then Exit Sub
COMPORT = fCom_Port.SelectedItem
Save_Registry_Data()
End Sub
Private Sub ExactREVs_CheckedChanged(sender As Object, e As EventArgs) Handles fExact_Turns.CheckedChanged
If SETUPFLAG Then Exit Sub
Data_Changed()
End Sub
Private Sub WholeLayer_CheckedChanged(sender As Object, e As EventArgs) Handles fWhole_Layer.CheckedChanged
If SETUPFLAG Then Exit Sub
Data_Changed()
End Sub
Private Sub fCore_ID_TextChanged(sender As Object, e As EventArgs) Handles fCore_ID.TextChanged
If SETUPFLAG Then Exit Sub
Data_Changed()
End Sub
Private Sub fCore_Length_TextChanged(sender As Object, e As EventArgs) Handles fCore_Length.TextChanged
If SETUPFLAG Then Exit Sub
Data_Changed()
End Sub
Private Sub fWire_Gauge_TextChanged(sender As Object, e As EventArgs) Handles fWire_Gauge.TextChanged
If SETUPFLAG Then Exit Sub
Data_Changed()
End Sub
Private Sub fTotal_Windings_TextChanged(sender As Object, e As EventArgs) Handles fTotal_Windings.TextChanged
If SETUPFLAG Then Exit Sub
Data_Changed()
End Sub
' CLICKED
Private Sub Port_Click(sender As Object, e As EventArgs) Handles fCom_Port.Click
If SETUPFLAG Then Exit Sub
Try
SERIALPORT.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
fCom_Port.Items.Clear()
For Each sp As String In My.Computer.Ports.SerialPortNames
fCom_Port.Items.Add(sp)
If fCom_Port.Items.Count > 0 Then
fCom_Port.SelectedIndex = 0
End If
Next
If fCom_Port.Items.Count > 0 Then
fCom_Port.Items.Add(fCom_Port.SelectedItem)
fCom_Port.SelectedIndex = 0
With SERIALPORT
.PortName = fCom_Port.SelectedItem
.BaudRate = 115200
.DataBits = 8
.Parity = Parity.None
.StopBits = StopBits.One
.Handshake = Handshake.None
End With
Try
SERIALPORT.Open()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Else
MsgBox("No Com Port Exists")
End If
End Sub
Private Sub fStart_Button_Click(sender As Object, e As EventArgs) Handles fStart_Button.Click
If SETUPFLAG Then Exit Sub
'Set the running button status
fStart_Button.Enabled = False
fPause_Button.Enabled = False
fLeft_Button.Enabled = False
fRight_Button.Enabled = False
fPause_Button.Enabled = True
CURRENTCOILDIAMETER = COREID + 2 * WIREDIAMETER ' Set the stert coil diameter
SLIDESTEPCOUNTER = 0 ' Set the start slide position
fSlide_Steps.Text = SLIDESTEPCOUNTER
LAYERSCOUNTED = 1 ' We have a layer as soon as the winding starts
fLayer_Count.Text = LAYERSCOUNTED
DrawCoil()
CURRENTCOILDIAMETER = COREID + (2 * WIREDIAMETER) ' Set the current coil diameter
T1.Start()
End Sub
Private Sub Pause_Button_Click(sender As Object, e As EventArgs) Handles fPause_Button.Click
If SETUPFLAG Then Exit Sub
T1.Stop()
' 7 = MOTORS OFF
writeData("7")
fContinue_Button.Enabled = True
fPause_Button.Enabled = False
End Sub
Private Sub Continue_Button_Click(sender As Object, e As EventArgs) Handles fContinue_Button.Click
If SETUPFLAG Then Exit Sub
fContinue_Button.Enabled = False
fPause_Button.Enabled = True
T1.Start()
End Sub
Private Sub Calculate_Button_Click(sender As Object, e As EventArgs) Handles fCalculate_Button.Click
If SETUPFLAG Then Exit Sub
' THIS ROUTINE CALCULATES PARAMETERS FROM DATA ON INPUT SCREEN.
If SETUPFLAG Then
Exit Sub
End If
Calculate()
End Sub
Private Sub Reset_Button_Click(sender As Object, e As EventArgs) Handles fReset_Button.Click
If SETUPFLAG Then Exit Sub
T1.Stop()
Save_Registry_Data()
PanelCoil.Visible = False
writeData("7")
SLIDESTEPCOUNTER = 0
Try
SERIALPORT.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
fCalculate_Button.Enabled = False
fWire_Gauge.Enabled = True
fTotal_Windings.Enabled = True
fCore_ID.Enabled = True
fCore_Length.Enabled = True
setup()
End Sub
Private Sub Quit_Button_Click(sender As Object, e As EventArgs) Handles fQuit_Button.Click
If SETUPFLAG Then Exit Sub
T1.Stop()
Save_Registry_Data()
Application.Exit()
End Sub
' MOUSEDOWN
Private Sub fLeft_Button_MouseDown(sender As Object, e As MouseEventArgs) Handles fLeft_Button.MouseDown
If SETUPFLAG Then Exit Sub
T1.Stop()
JFORWARD = False
Timer1.Enabled = True
End Sub
Private Sub fRight_Button_MouseDown(sender As Object, e As MouseEventArgs) Handles fRight_Button.MouseDown
If SETUPFLAG Then Exit Sub
T1.Stop()
JFORWARD = True
Timer1.Enabled = True
End Sub
Private Sub fLeft_Button_MouseUp(sender As Object, e As MouseEventArgs) Handles fLeft_Button.MouseUp
If SETUPFLAG Then Exit Sub
T1.Stop()
Timer1.Enabled = False
writeData("7")
End Sub
Private Sub fRight_Button_MouseUp(sender As Object, e As MouseEventArgs) Handles fRight_Button.MouseUp
If SETUPFLAG Then Exit Sub
T1.Stop()
Timer1.Enabled = False
writeData("7")
End Sub
' SUBS
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
If SETUPFLAG Then Exit Sub
T1.Stop()
writeData("7")
Save_Registry_Data()
Try
SERIALPORT.Close()
Catch ex As Exception
' do nothing if there is an error
End Try
Application.Exit()
End Sub
Private Sub DrawCoil()
Dim y As Double
y = CURRENTCOILDIAMETER * 70
PNT.X = Label16.Location.X + 10 ' x position is fixed
PNT.Y = PanelCore.Location.Y - y / 2 + 10 ' y position varies with coil diameter
PanelCoil.Height = y ' the coil height
PanelCoil.Width = 97 ' the width is fixed
PanelCoil.Location = PNT
PanelCore.Hide()
PanelCoil.Show()
End Sub
Private count As Long = 0
Private Sub writeData(dat As Byte)
count += 1
fTotal_Coil_Steps.Text = count
Try
SERIALPORT.Write(dat)
Catch ex As Exception
MessageBox.Show("Serial Port Write Error" & ex.Message)
End Try
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If SETUPFLAG Then Exit Sub
If JFORWARD Then
writeData("3")
SLIDESTEPCOUNTER += 1
fSlide_Steps.Text = SLIDESTEPCOUNTER
Else
writeData("4")
SLIDESTEPCOUNTER -= 1
fSlide_Steps.Text = SLIDESTEPCOUNTER
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
setup()
End Sub
Private Sub T1_Tick(sender As Object, e As EventArgs) Handles T1.Tick
If SETUPFLAG Then Exit Sub
Try
Invoke(New Action(AddressOf Control_The_Motors))
Catch
' do nothing if an error occurs
End Try
End Sub
End Class
-
Feb 5th, 2018, 06:06 AM
#4
Re: Slowdown on COM port write after 12k characters
Are you confident that what you're sending to the arduino is what it expects?
The code for that looks a little suspect.
You have these comments in the code
Code:
' ********************************
' ignore 48 // 0
' set_ratio 49 // 1
' winder_omly 50 // 2
' slide_forward 51 // 3
' slide_reverse 52 // 4
' slide_forward_winder 53 // 5
' slide_reverse_winder 54 // 6
' stop_motors 55 // 7
' ignore all others //
' ********************************
Based on that it might appear, for instance, to send a stop_motors command to the arduino you should be sending the ASCII value for "7", i.e. a byte value of 55.
Your code has the WriteData sub's parameter defined as a Byte but you're passing a string, e.g.
Code:
Private Sub writeData(dat As Byte)
'...
End Sub
writeData("7")
You obviously don't have Option Strict On otherwise that code wouldn't be allowed because of the type missmatch between the argument type passed to the sub and the parameter type it expects.
With Option Strict Off, Visual Basic decide on how to convert the String to a Byte.
In this case, it sees that the string can be converted to a number, i.e. 7 so a byte value of 7 will be received by writeData instead of a byte value of 55.
If you really wanted to send a 7, then you should just send that:
WriteData(7)
If you really wanted to send the ASCII code value for "7", i.e. 55, then you should probably just create an enum to give names to the byte values and use those.
Code:
Private Enum MotorCommand As Byte
ignore = 48 'first command is ASCII zero, each other is 1 more than the previous, e.g. set_ratio is ASCII for "1"
set_ratio
winder_omly
slide_forward
slide_reverse
slide_forward_winder
slide_reverse_winder
stop_motors
End Enum
'and later sends a byte value of 55, i.e. ASCII of "7"
WriteData(MotorCommand.stop_motors)
Now, as for your speed issue, I guess the question is how confident are you that the high accuracy timer is working well in your scenario.
Since you trap any exception in the tick and don't display anything or record a count for information, you don't know if you're getting exceptions or not. That could be slowing things down considerably.
Also, since you Invoke from the tick, that tick is synchronous with the UI, i.e. the tick event won't complete until the Control_The_Motors sub has been scheduled and run on the GUI thread and has returned. If that sub is getting hung up for some reason, I don't know if you may be getting additional ticks and building up multiple invocations waiting on the GUI thread to free up from previous invocations.
One byte every 50ms, i.e. 20 bytes per second is pretty slow so it doesn't seem reasonable that the serial port would not be keeping up.
Have you verified that you are getting ticks at 20hz and not some much faster rate?
-
Feb 5th, 2018, 08:11 AM
#5
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Very good points.
The write routine uses a byte, but while troubleshooting the problem I changed it to a char and used the offset and character count arguments. I changed all the calls to pass "n" to it but that did not help. Obviously I changed the write routine back to normal, but since the passing of "n" instead of a byte still worked, I didn't bother to change them back.
The table for the motor commands shows the byte number on the PC end and the ASCII equivalent the Arduino sees. The motors respond correctly so the interpretation is working okay.
I am very confident the timer is working well because if I comment out just the actual com port write command, the slowdown does not occur. I think that's pretty good evidence the timer is okay and the problem is in the com port write.
I am pretty confident the timer is reasonably accurate because if it was much faster, the stepper motors would skip steps. I have double checked the motors and after 60 rotations of the winder both the winder and the slide are exactly where they are supposed to be. There are no skipped steps.
I also made a simpler program that uses the internal timer1 to continuously send the commands at 50ms intervals. That eliminates the possibility of a problem with my timer. That program also slows down after running for a while.
Based on all the evidence I think it pretty much points to something with the com port writes.
There is one place where two bytes are sent back-to-back without the 50ms. After the winder steps, there is a check to see if the slide needs to step. If it does, the command to step it goes out immediately. To avoid that I will change things so it sends a single command to step both motors when required. I have commands that will step the winder and step the slider in forward or reverse as needed.
I will also turn on option strict and clean up the stuff I changed during troubleshooting.
I need to think about the comments you made on threading. At first blush, the sequence of writing commands is so slow, it's hard to imagine ticks piling up but It is worth checking.
Thanks!
-
Feb 5th, 2018, 08:26 AM
#6
Re: Slowdown on COM port write after 12k characters
We had tons of issues in COM Printers with baud rates. Some worked fine at 115200 some at 9600.
We where experiencing a slowdown at tickets after a period of time. I don't say that it is the same issue but wouldn't mind if you did a test with a lower baud rate.
-
Feb 5th, 2018, 10:39 AM
#7
Re: Slowdown on COM port write after 12k characters
Hiding the exceptions is still potentially an issue. Commenting out the write doesn't rule that out. If nothing else, add a List(of String) and log any exceptions rather than ignoring them. The reason that exceptions can cause an issue is that they are REALLY slow, so if you start throwing them, then your timing may get pretty messed up at that point. Therefore, you really need to know whether or not that is an issue, and logging will tell you....eventually, as you can check the list to see whether anything is piling up.
My usual boring signature: Nothing
-
Feb 5th, 2018, 11:34 AM
#8
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Okay, the change to 9600 baud made no difference except the count is slightly higher when the slow down occurs. It was in the low 13k area.Th really freaky thing about this is my wind counter is always at 61 when this happens.
On to Shaggy Hiker's suggestion of not ignoring any errors.
-
Feb 5th, 2018, 11:59 AM
#9
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Everywhere there was a try, I changed it to post a message instead of ignoring the error. I also added the try-catch and message to the invoke in case there was a problem there. Unfortunately, it slowed down at 13300 +- 50 with no errors being caught and running at 9600 baud.
One other thing was noticed: It ran until it slowed down, then I pressed the pause button which stops the timer. I noted the count and then pressed the continue button and things were still slow. So a pause of 20 or so seconds doesn't change anything. Still looks like a serial port write problem to me.
Any other thoughts on how I might try to isolate this?
-
Feb 5th, 2018, 12:38 PM
#10
Re: Slowdown on COM port write after 12k characters
I would say that you have ruled out an exception being the issue, so that's a step in the right direction.
I can't say that I have a whole lot of experience with serial port communications. When I have used them, I haven't gotten to the 10K mark, or beyond. It was always shorter periods....except for READING. I've done that for very long runs without issue. There was no writing involved in that, though. Still, I agree with the people who say that the write doesn't seem likely to be the culprit. That doesn't 'feel' right to me. A slowdown after a long run of time feels like either a memory issue or some event-issue (like the timer ticks backing up, as has been noted).
The next thing that I'd try, which you may have already tried, cause you talked about some things like this, is to add a Stopwatch object and simply note the elapsed time once every timer tick. I'd just be putting that into a list, or some such, and might ignore the first few thousand to keep the size small. Perhaps look at timer ticks 8000 to slowdown. No matter what, you'd expect to see the slowdown show up as an increased interval. What would be interesting is if you saw the pattern be quite regular up to the slowdown, then irregular afterwards.
My usual boring signature: Nothing
-
Feb 5th, 2018, 02:07 PM
#11
Re: Slowdown on COM port write after 12k characters
We can't rule out that there is some bug in the SerialPort class, I've seen some people complain that it's finicky. Unfortunately to prove that, we have to rule out practically everything else. This is really, really tough to do because there is a lot of "everything else" to try. Ideally, you'd have multiple devices, especially some known "good" one that doesn't do much. And multiple computers, to rule out a bad COM port/driver.
It's especially hard to rule out on my end because I don't have any COM ports, or devices, let alone your specific hardware. So I can't muck around and make something that mimics your device just enough to see if your code has some flaw not apparent from a readthrough.
I think this is why I'm noticing a trend to use ethernet/wifi in lieu of COM ports lately. It's more ubiquitous and the I/O APIs are almost identical. Not to mention debugging HTTP via Wireshark is a heck of a lot easier than trying to see what's happening over the COM wire.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 5th, 2018, 02:59 PM
#12
Re: Slowdown on COM port write after 12k characters
I haven't had any problem sending data regularly over multiple serial ports for months on end, but perhaps I've been lucky.
I took a look at the send routine where I send the same message over two ports, simulating two devices sending regular avionics messages to a flight computer. The message is a 25-byte message, and I believe it is probably intended to send at around 20 hz. The timing isn't critical so I believe a background thread is used with Threading.Sleep so may be sending at 21.333 hz based on the regular 64hz clock behind the timer being divided by 3 as the "true" interval being accomplished.
Anyway, that send looks like this.
Code:
Public Function SendData(ByRef data() As Byte, ByVal messageLength As Integer) As Integer
Dim bytes_sent As Integer
Dim test As Integer
Try
test = 1
_serialPort(0).Write(data, 0, messageLength)
test = 2
_serialPort(1).Write(data, 0, messageLength)
bytes_sent = messageLength
Catch ex As Exception
Console.WriteLine("...error writing to port(s). Failed on Port " + test.ToString)
bytes_sent = -1
End Try
Return bytes_sent
End Function
25 bytes * 21.333 times per second = 533.333 bytes per second over each port. That means I'm sending 32,000 bytes per minute over those ports for as long as the main simulation is being run.
(by the way, I actually had a coworker write this portion of the code and he wasn't familiar with VB so depended a lot on looking stuff up on the web. I wouldn't have specified the ByRef and ByVal modifiers on the parameters myself or use "+" to concatenate strings).
As I said, this software is normally just started by the users in the lab and left running for months on end. The serial is just part of the equipment simulation, there are various Ethernet connections and Avionics bus connections also controlled by this application to simulate various pieces of equipment on an aircraft.
The primary simulation programs just connect with this simulation program whenever they startup, which is why it is usually just left running since the user doesn't normally need to directly interact with the program, unless there is a problem.
Anyway, looking at the SerialPort.Write method again, I think I see how you're getting an ASCII code character on your arduino, even though technically you're trying to send a byte who's value is 0, 1, 2,... not 48, 49, 50,...
The three forms of the Write method are:
Write(String)
Write(Byte(), Int32, Int32)
Write(Char(), Int32, Int32)
Since you are only passing one argument to Write, and because you have Option Strict Off, VB is using the first Write method, and converting your byte value, e.g. 1, into the String "1", and then the serial write will automatically convert the String argument into a series of ASCII characters when it is transmitted across the interface.
I guess since it is a string you want transmitted, you should probably just change the parameter type in your SendData to
Code:
Private Sub writeData(dat As String)
so you don't go through all the implicit conversions your code is going through now.
Another option might be to try using the byte array version of write, and just send that way to see if it makes any difference.
Code:
Private Sub writeData(dat As Byte)
Dim msg(0) As Byte
count += 1
fTotal_Coil_Steps.Text = count
Try
msg(0) = Asc(dat)
SERIALPORT.Write(msg, 0, 1)
Catch ex As Exception
MessageBox.Show("Serial Port Write Error" & ex.Message)
End Try
End Sub
Last edited by passel; Feb 5th, 2018 at 03:16 PM.
-
Feb 5th, 2018, 03:22 PM
#13
Addicted Member
Re: Slowdown on COM port write after 12k characters
My thought was the Arduino buffer getting overwitten or the actual process of commanding and moving a couple of motors was taking 50ms. or greater.
The serial port itself (as you have it configured) should run quite happily at much faster speeds and much more transmitted data all day long.
I would perhaps try reducing the write time and not the baud rate to begin with, maybe 200ms or slower and see what kind of count you get before things slow down.
I would also duplicate the transmitted data in a text box along with the data count so that you could check the count and data value being transmitted when things slow down, append the values so they can all be examined at the end of your run
-
Feb 5th, 2018, 03:42 PM
#14
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Passel, as mentioned previously, I tried changing the write to use SERIALPORT.Write(char, 0, 1) and it didn't help.
I just created a simpler program that writes bytes to the com port at 50 ms intervals but without all the stuff in my original program. This should eliminate anything in my original program as a cause. This one uses the built-in timer set at 50 ms to eliminate any potential problems with my timer. It has an integer counter and a console write to keep track of ticks. It only writes to the console output window so there is no form updates happening.
This too slows down at abut 12k ticks. All I do is comment out line 21 (ComPort.Write(2)) and, not to sound like a Timex commercial, but it then goes well past 15k at normal speed and just keeps on ticking.
Can there be any doubt left about the problem being the .net serial port code or something in my hardware?
I have been testing on a AilenWare laptop so my next test will be to put this on my wife's Dell desktop PC and give it a go there.
Lest I forget, a big thank you to all the folks who help me troubleshoot this.
I'll post the results of the test on the desktop computer when that is done.
Here is the simpler program:
Code:
Imports System.IO.Ports
Public Class Form1
Dim ComPort As New SerialPort
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Start_Com_Port()
run()
End Sub
Private Sub run()
aTimer.AutoReset = True
aTimer.Interval = 50 '50 mseconds
AddHandler aTimer.Elapsed, AddressOf tick
aTimer.Start()
End Sub
Private aTimer As New System.Timers.Timer
Private count As Integer
Private Sub tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
Try
' ComPort.Write(2)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
count += 1
Try
Console.WriteLine("tick " & count)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub Start_Com_Port()
Try
ComPort.Close()
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
With ComPort
Try
ComPort.PortName = "COM3"
Catch ex As Exception
Console.Write(ex.Message)
End Try
.BaudRate = 9600
.DataBits = 8
.Parity = Parity.None
.StopBits = StopBits.One
.Handshake = Handshake.None
End With
Try
ComPort.Open()
Catch ex As Exception
Console.Write("Port " & ComPort.PortName & vbCrLf & ex.Message)
End Try
End Sub
End Class
-
Feb 5th, 2018, 05:49 PM
#15
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Mc_VB suggested I slow the tick interval down to 200ms or slower, but my patience is wearing thin so I went to 100 ms instead and that didn't help. Next I tried one of the other suggestions and wrote the count out to a text file. Lastly, I moved everything over to my wife's desktop computer and that didn't help either. No matter what I try, this thing starts crawling at about 12-13 k steps. If it means anything, a look at the output file shows that and there are no apparent missing step counts.
Unless someone can provide an idea to try something that has not already been tried or eliminated, I am going to stop here and declare this a serial port software issue in .net.
It's time for me to look for another way to connect to the arduino. As you can see in the photo, I am using an Arduino UNO with a Stepper Shield on it. That makes it a little tougher to add a wifi or Bluetooth card to the system but I suspect with a little extra wiring it can be done.
Still open to any new ideas on this.
-
Feb 5th, 2018, 05:50 PM
#16
Re: Slowdown on COM port write after 12k characters
Any chance that the Arduino is sending data to the PC, and you are not consuming it? Any Serial.write()/Serial.print() or equivalent commands in the Arduino code?
I've noticed a slowdown when ComPort.BytesToRead gets to 12290 unread Bytes.
-
Feb 5th, 2018, 06:11 PM
#17
Re: Slowdown on COM port write after 12k characters
That's kind of something I thought of and forgot; if it's got some kind of buffer and you fill it, that might slow things down.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 5th, 2018, 06:37 PM
#18
Addicted Member
Re: Slowdown on COM port write after 12k characters
I tried your console code over a usb to serial connection (no hardware attached) and enabled the Comport.Write(2) line, it ran to 28000 ticks without missing a beat , at that point I closed the app down.
Inferrd mentions the Arduino sending data to the PC , I don't know if the Arduino does that but I do know the Basic Stamp microcontroller used to echo bytes back, that took special handling so something to look at.
Also things could be faster and more reliable with a handshake, in this situation a software handshake would work well. Passel mentioned an array of bytes, I would lean toward this too.
So VB.Net waits for some kind of request "send me some bytes transmits the byte array then waits for the next request while the Arduino consumes the bytes.
-
Feb 5th, 2018, 07:41 PM
#19
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
This problem is fixed. Sprinkled in to some of your comments was the idea the Arduino might be sending data back to the PC and that got me looking at the Arduino end of things. I was pretty sure it was not sending data to the PC, but sure enough, it was. There were 7 Serial.print commands I used while writing and debugging the arduino code. Six (6) of them were commented out but I missed the seventh one which was echoing the '2' command that moves the winder. Every time the winder was told to step, the '2' command was echoed back out on the com port. It never really occurred to me that the debug prints were going out on the same port used to connect the arduino to the PC.
I am retired and do these little projects mostly to have some fun. This particular bug has really stretched the idea that this was "fun".
Still, I did learn a lot about troubleshooting and possibly the biggest lesson is to not focus on just one side of the problem when there are two sides.
FYI: I just stopped the latest test which has been running for a while at 25 ms which is the originally intended speed. It has not slowed down and the count is 63026
Once again, thank you to all respondents for your help getting me through this. It is greatly appreciated.
-
Feb 5th, 2018, 10:07 PM
#20
Re: Slowdown on COM port write after 12k characters
I've had occasion where I received data that I didn't use but didn't have control over the other side so just installed a drain, e.g. add a WithEvents to your serial port declaration, and handle the DataReceived Event.
Code:
Private WithEvents SERIALPORT As New SerialPort ' The io serial port
Private Sub SerialDrain(
sender As Object,
e As SerialDataReceivedEventArgs) Handles SERIALPORT.DataReceived
Dim bitBucket As String = SERIALPORT.ReadExisting()
End Sub
-
Feb 6th, 2018, 11:29 AM
#21
Thread Starter
Lively Member
Re: Slowdown on COM port write after 12k characters
Nice, I bet that would have worked too.
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
|