vb.net - how can I delay processing within a loop?
Discussion
My app sends a specific set of frequencies (derived from an array) to an Arduino controlled function generator.
This same app reads data from a USB oscilloscope (see flowchart below).
Now, my oscilloscope is slow to 'settle' at frequencies below 20Hz - so I need to introduce a delay (in the read process) for frequencies below 20Hz.
There is a (very) simplified version of my code below - I think the delay needs to be introduced inside the "Case 5 to 50" statement.
I have tried additional timers, and also "Thread.Sleep()", but thread.sleep just pauses the processing but the Timer continues in the background, so when the 'sleep wakes up' I get a sudden burst of activity (not good!).
I've also tried stopping the timer and restarting it within the loop.
Maybe my entire approach is just wrong...
TIA for any help.
For testing, this code will run as is with a form, button, 4 labels and a rich text box.
In "Dim freqList() As Decimal" below I have had to place brackets, to get around the PH brace "{" issue...

This same app reads data from a USB oscilloscope (see flowchart below).
Now, my oscilloscope is slow to 'settle' at frequencies below 20Hz - so I need to introduce a delay (in the read process) for frequencies below 20Hz.
There is a (very) simplified version of my code below - I think the delay needs to be introduced inside the "Case 5 to 50" statement.
I have tried additional timers, and also "Thread.Sleep()", but thread.sleep just pauses the processing but the Timer continues in the background, so when the 'sleep wakes up' I get a sudden burst of activity (not good!).
I've also tried stopping the timer and restarting it within the loop.
Maybe my entire approach is just wrong...
TIA for any help.
For testing, this code will run as is with a form, button, 4 labels and a rich text box.
In "Dim freqList() As Decimal" below I have had to place brackets, to get around the PH brace "{" issue...
Imports System.Threading
Public Class Form1
Dim timeLoop As Integer = 0
Public timeBase As String = Nothing
Public freq As Decimal
Dim freqList() As Decimal = (10, 15, 20, 25, 30, 50, 100, 500, 1000, 5000, 10000, 50000, 100000) ' <--- change brackets for braces!!!
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub readScope()
Me.RichTextBox1.AppendText(freq)
Me.RichTextBox1.AppendText(Environment.NewLine)
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
' timer 1 delays the loop count
If timeLoop <= 12 Then
freq = freqList(timeLoop)
freq = Math.Round(freq, 2)
Label1.Text = timeLoop
'Label1.Text = freq
'freq = freqs(x)
End If
If timeLoop >= 12 Then
Timer1.Enabled = False
Label1.Text = timeLoop
End If
Select Case freq
Case 5 To 50
If Not timeBase = "3" Then
timeBase = "3"
Label2.Text = timeBase
End If
'SerialPort1.WriteLine("f" & " " & freq) 'fast setting
If freq <= 11 Then
' 'Call readDelay()
Thread.Sleep(6000)
End If
Call readScope()
Case 50 To 500
If Not timeBase = "5" Then
timeBase = "5"
Label2.Text = timeBase
End If
'SerialPort1.WriteLine("f" & " " & freq) 'fast setting
Call readScope()
Case 500 To 5000
If Not timeBase = "8" Then
timeBase = "8"
Label2.Text = timeBase
End If
'SerialPort1.WriteLine("f" & " " & freq)
Call readScope()
Case 5000 To 50000
If Not timeBase = "11" Then
timeBase = "11"
Label2.Text = timeBase
End If
'SerialPort1.WriteLine("f" & " " & freq)
Call readScope()
Case 50000 To 1100000
If Not timeBase = "15" Then
timeBase = "15"
Label2.Text = timeBase
End If
'SerialPort1.WriteLine("f" & " " & freq)
Call readScope()
End Select
timeLoop = timeLoop + 1
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
RichTextBox1.Clear()
freq = freqList(0)
'SerialPort1.WriteLine("f" & " " & freq)
Timer1.Enabled = True
Timer1.Interval = 3000
End Sub
End Class

Edited by TonyRPH on Friday 9th February 10:34
I haven't coded for 20 years so can't answer your question directly (sorry for wasting your time) but back in the 90s I was writing code for the Stewart F1 team and had to introduce a delay as my code was too quick for the radio data transmissions. Instead of an official delay or timer I actually made my loop do an integral count so I could tweak the delay just by changing the integer.
Worked perfectly but probably would upset a lot of purists
Worked perfectly but probably would upset a lot of purists
keirik said:
Stuff.
I believe I already tried this! Great minds think alike! :Pnyt said:
I think that you need: System.Threading.Thread.Sleep(number of milliseconds).
This yields the same behaviour as Thread.Sleep()SystemParanoia said:
Doesn't .NET have "promises" or "callbacks" or the ability to process functions asyncronously?
I am a relative novice at .net - while I've seen reference to 'async' and 'await' during my searches for a solution, I didn't understand their workings.Async processing (if it is what I understand it to be) might well be the answer here though - I shall have to research it a bit more...
I have an idea that callbacks and promises might be c# / c++ only.
TonyRPH said:
Roughly about 0.5 to 1 second - it's quite difficult to time it.
Ok, then you're problem would seem to be the fact your waiting 6 seconds in a 3 second loop.would a Thread.Sleep(1500) not work?
(incidentally if you add the async keyword to you method declaration you could use "await Task.Delay(1500);" for async version of Thread.Sleep)
zippy3x said:
Ok, then you're problem would seem to be the fact your waiting 6 seconds in a 3 second loop.
According to the timings when I run the code above, the rich text box is populated every 3 seconds?zippy3x said:
would a Thread.Sleep(1500) not work?
No - this causes the loop to suddenly catch up when the sleep 'wakes up' and suddenly sends a flood of queued data.zippy3x said:
(incidentally if you add the async keyword to you method declaration you could use "await Task.Delay(1500);" for async version of Thread.Sleep)
It's the async version of thread sleep that I need, as the Timer1 loop needs to be paused while the waiting to read the data.Which method declaration would I need to add this to, and how do I add it specifically?
Remember you're talking to a relative novice here! :P
Thanks.
How about an outer loop around a smaller thread.sleep to get the delay that you need - and add a doevents for good measure.
//for a 3 second delay
For i = 1 to 30
System.Threading.Thread.Sleep(100)
System.Windows.Forms.Application.DoEvents()
Next
You could go even finer on the Sleep - say System.Threading.Thread.Sleep(10) and increase the outer delay
//for a 3 second delay
For i = 1 to 30
System.Threading.Thread.Sleep(100)
System.Windows.Forms.Application.DoEvents()
Next
You could go even finer on the Sleep - say System.Threading.Thread.Sleep(10) and increase the outer delay
TonyRPH said:
It's the async version of thread sleep that I need, as the Timer1 loop needs to be paused while the waiting to read the data.
Which method declaration would I need to add this to, and how do I add it specifically?
Remember you're talking to a relative novice here! :P
Thanks.
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Which method declaration would I need to add this to, and how do I add it specifically?
Remember you're talking to a relative novice here! :P
Thanks.
' Call and await separately.
'Task<int> getLengthTask = AccessTheWebAsync();
'' You can do independent work here.
'int contentLength = await getLengthTask;
Dim contentLength As Integer = Await AccessTheWebAsync()
ResultsTextBox.Text &=
String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)
End Sub
from here : https://docs.microsoft.com/en-us/dotnet/visual-bas...
or in your case Await Task.Delay(whatever)
After some experimentation, I realised that Await / Task won't work either.
The problem is, as soon as I attempt to read the scope, the data is returned without delay (whether it's correct or not!).
So task await has nothing to wait for...
And I have no way of knowing if the scope has 'caught up' as there is no indication - I have a "Data Ready*" option in the DLL for the scope, however that returns "Yes" as soon as the scope goes into run mode, and not whether it has triggered etc.
I think I need to go back to the drawing board here.
It's a tricky one this!
From the manual:
The problem is, as soon as I attempt to read the scope, the data is returned without delay (whether it's correct or not!).
So task await has nothing to wait for...
And I have no way of knowing if the scope has 'caught up' as there is no indication - I have a "Data Ready*" option in the DLL for the scope, however that returns "Yes" as soon as the scope goes into run mode, and not whether it has triggered etc.
I think I need to go back to the drawing board here.
It's a tricky one this!
From the manual:
- "DataReady Indicates if there is fresh data available"
nyt said:
Can't you just throw away all data that is waiting when your 'sleep' is finished and carry on with good data?
No, the process works like this:loop and generate frequency from array
send frequency information to arduino, which generates a sinewave
sinewave then sent to device under test
scope reads output of device under test
the scope info is then parsed by my app
So it all needs to be real time - so I do need to stop sending / receiving data while waiting for the scope to catch up.
I might just setup another timer, and place the initial loop in the first (longer) timer - and then use the existing timer to resume processing.
I can't think of any other way to do it... (apart from manual steps!!)
I just need to step through the process slowly...
- Or try and do it in C / C++ lol. (no chance)
So, first things first. Regarding the oscilloscope,
You send a string to it telling it what frequency you want to read?
You get a (probably erroneous) message saying data ready?
But it's not? or its is except the lower frequency?
If it is the lower frequency you need to wait for some duration and then read again presuming this time the data is correct?
is that about right?
You send a string to it telling it what frequency you want to read?
You get a (probably erroneous) message saying data ready?
But it's not? or its is except the lower frequency?
If it is the lower frequency you need to wait for some duration and then read again presuming this time the data is correct?
is that about right?
In case it quickly doesn't become obvious, I have no idea what I'm talking about.
If you know what your processor speed is, can you integrate a large calculation as a side routine, where the calculation takes a specific time to carry out which is equivalent to the delay required.
Then once the calc is done, and the specific and only result is generated, that answer is used to trigger the rest of the code operation.
Candidate for Most Bizarre Workaround 2018?
If you know what your processor speed is, can you integrate a large calculation as a side routine, where the calculation takes a specific time to carry out which is equivalent to the delay required.
Then once the calc is done, and the specific and only result is generated, that answer is used to trigger the rest of the code operation.
Candidate for Most Bizarre Workaround 2018?
TonyRPH said:
nyt said:
Can't you just throw away all data that is waiting when your 'sleep' is finished and carry on with good data?
No, the process works like this:loop and generate frequency from array
send frequency information to arduino, which generates a sinewave
sinewave then sent to device under test
scope reads output of device under test
the scope info is then parsed by my app
So it all needs to be real time - so I do need to stop sending / receiving data while waiting for the scope to catch up.
I might just setup another timer, and place the initial loop in the first (longer) timer - and then use the existing timer to resume processing.
I can't think of any other way to do it... (apart from manual steps!!)
I just need to step through the process slowly...
- Or try and do it in C / C++ lol. (no chance)
If you throw away the (presumably incorrect) data that you've received from the oscilloscope while the delay was active, and then prices the presumably correct data then your app will still be realtime?
Pseudo code:
'SerialPort1.WriteLine("f" & " " & freq) 'fast setting
If freq <= 11 Then
Thread.Sleep(6000)
End If
'Now read data until you get a 'data not ready' from the 'scope
Call ReadAndDiscardData()
'Now read the good data
Call readScope()
If you never get a 'data not ready' then read as many points as you expect to receive from the 'scope in the delay period.
zippy3x said:
So, first things first. Regarding the oscilloscope,
You send a string to it telling it what frequency you want to read?
Yes, I send a read command as defined by the DLL provided with the scope.You send a string to it telling it what frequency you want to read?
zippy3x said:
You get a (probably erroneous) message saying data ready?
Yes, but it's not erroneous as such, just poorly defined by the scope DLL / scope itself zippy3x said:
But it's not? or its is except the lower frequency?
The scope receives the low frequency, but requires a finite 'settling time' to provide an accurate reading (0.5s to 1s at frequencies < 20..40Hz).zippy3x said:
If it is the lower frequency you need to wait for some duration and then read again presuming this time the data is correct?
This is correct.zippy3x said:
is that about right?
Yep. - and thanks for taking the time to respond.ReverendCounter said:
Same suggestion as keirik
See 2nd post above, from keirik. This doesn't quite work for me...Gassing Station | Computers, Gadgets & Stuff | Top of Page | What's New | My Stuff