|
-
May 19th, 2013, 07:15 AM
#1
Thread Starter
Junior Member
ReadTimeout not Working?
I am communicating with an Arduino microcontroller board which is running a simple C program which echoes input on the serial port back to a PC. When the application on the PC sends the contents of a textbox to the Arduino, the code on the Arduino reads the port until it intercepts a CR and then echoes this input back to the PC, adding an LF in the process.
Now when I use a ReadLine() method, it times out straight away, even though the timeout is set to 2 seconds. The LF code is being transmitted as I have checked it using a terminal program. I can see the TX and RX LEDs lighting on the Arduino board so transmission and reception occurs immediately without a delay. The ReadLine method should block until a terminator character is received or it times out. The odd thing is that I can use two methods of sending text to the Arduino board, type text in a textbox and press a button to transmit or type text in the same textbox and hit enter to transmit. Pressing the button doesn't create a timeout but hitting enter does. AcceptsReturn is set to true for the textbox and I have set the multline property to false so as not to confound the issue. The port is a USB virtual serial port.
Any ideas? The Arduino C and VB code is below:
#define CR 13
#define LF 10
int button_input =12;
int led_output =7;
int onboard_led =13;
char received_command[50];
byte num_chars_received;
int char_received;
// Arduino program. This echoes input on the serial port
void setup()
{
pinMode(onboard_led,OUTPUT);
pinMode(button_input,INPUT_PULLUP);
pinMode(led_output,OUTPUT);
int i;
Serial.begin(9600); // Set the baud rate to 9600
}
void loop()
{
if(digitalRead(button_input)) // A high on a digital input allows the program to execute
{
if (Serial.available() > 0) // If there is data in the buffer
{
num_chars_received = Serial.readBytesUntil(CR, received_command, 25); // read until CR terminator. CR not inclued in number of characters received
if(num_chars_received>0)
{
received_command[num_chars_received]='\0'; // terminate the string with a NULL
Serial.println(received_command); // This writes to the serial port and adds an LF
digitalWrite(led_output,HIGH); // Pulse LED on and off
delay(500);
digitalWrite(led_output,LOW);
}
}
}
}
// Event handler for received data
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim myArray(1) As Object
myArray(0) = " "
SerialPort1.ReadTimeout = 2000
If told_to_close = True Then
okToCloseSerialPort.Set() 'got the close message // set a wait handle.
Exit Sub
End If
timeout = False
Try
myArray(1) = SerialPort1.BytesToRead
myArray(0) = SerialPort1.ReadLine() + vbLf // ReadLine strips the LF when reading from the buffer so add an LF to generate a newline in the text box
Catch ex As TimeoutException
timeout = True
Beep()
End Try
' use a delegate for updating controls to avoid cross threading
iasync1 = Me.BeginInvoke(DelegateDataReceived, myArray)
End Sub
// Transmit the contents of a textbox when a "send" button is clicked
Private Sub btnSendCommand_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSendCommand.Click
If SerialPort1.IsOpen = True Then
SerialPort1.Write(txtBoxSendData.Text & vbCr) // Add a CR terminator for the benefit of the Arduino
txtBoxSendData.Text = "" // blank the textbox
txtBoxSendData.Focus()
End If
End Sub
// Transmit the contents of a textbox when enter key is pressed
Private Sub txtBoxSendData_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtBoxSendData.KeyPress
If e.KeyChar = vbCr Then // Send data if enter key is pressed
If SerialPort1.IsOpen = True Then
SerialPort1.Write(txtBoxSendData.Text & vbCr)
txtBoxSendData.Text = ""
txtBoxSendData.Focus()
End If
End If
End Sub
Last edited by Eugbug; May 19th, 2013 at 07:22 AM.
-
May 19th, 2013, 09:51 AM
#2
Re: ReadTimeout not Working?
Change your Catch to this
Code:
Catch ex As TimeoutException
Debug.WriteLine(ex.Message)
Debug.WriteLine(myArray(1))
timeout = True
Beep()
In general you should not use a ReadLine in the DataReceived event handler. You are probably assuming that the handler will only be called once for the data being transmitted by your Arduino. My guess is that the event is being raised several times, but the first time it is called it is blocked, so the remaining events are queued. The code I provided will show how many times it is raised, and how many bytes are available when it is.
-
May 19th, 2013, 03:05 PM
#3
Thread Starter
Junior Member
Re: ReadTimeout not Working?
 Originally Posted by dbasnett
Change your Catch to this
Code:
Catch ex As TimeoutException
Debug.WriteLine(ex.Message)
Debug.WriteLine(myArray(1))
timeout = True
Beep()
In general you should not use a ReadLine in the DataReceived event handler. You are probably assuming that the handler will only be called once for the data being transmitted by your Arduino. My guess is that the event is being raised several times, but the first time it is called it is blocked, so the remaining events are queued. The code I provided will show how many times it is raised, and how many bytes are available when it is.
My debug output window shows debug messages but nothing from the debug.WriteLine method. Should I have something turned on in the VB settings to enable this?
Also it doesn't seem to be possible to set breakpoints within the catch block of code. I have also added an integer variable within this block which should get incremented and count the number of times an exception occurs. Even though the beep sounds, the variable never gets incremented. I also used a variable to count the number of times the DataReceived handler fires and it only does this once. If the ReadLine method is blocking, can a re-entrance occur on this handler? If not then it's ok in my example to use ReadLine within the handler and block for a response. At the moment, the responses from the Arduino are simple short replies to commands from the PC. I'm not downloading any data and the Arduino isn't continuously streaming information.
Last edited by Eugbug; May 19th, 2013 at 05:29 PM.
-
May 19th, 2013, 05:46 PM
#4
Re: ReadTimeout not Working?
Are you running the code with the Release Configuration? I think it is under Build / Configuration Manager. Set it to Debug if it isn't.
"If the ReadLine method is blocking, can a re-entrance occur on this handler?" No. The documentation is clear that only one of the SerialPort event handlers can execute at a time.
"If not then it's ok in my example to use ReadLine within the handler and block for a response." You can do what you want, but consider this. If you send 'abcd' with a CR and you send that back with a LF added how many times do you think the DataReceived event handler will fire? It will fire once for sure, unless you have made other changes to the settings. But I suspect it is firing more than once, which is typical. Lets assume twice. One time it fires after receiving 'abc' and the second time it tries to fire for 'd' and the CRLF.
The first time it fires you block on the readline but there is no 'line'. The second piece of data arrives, the event is queued to fire because the original is waiting on the readline. The original readline is eventually satisifed but then the second event fires and you have a new readline posted but no data is coming. Eventually that readline will, you guessed it, timeout.
Get the Debug's fixed and we will see.
-
May 19th, 2013, 06:47 PM
#5
Addicted Member
Re: ReadTimeout not Working?
Hi, because the data echoed is a copy of the string you transmitted you can receive the string in a String variable.
ReadLine will read every character in the serial buffer until it encounters a NewLine character (decimal 10), it is important that the data sent from the Arduino is terminated with this value. The "Newline" value can be changed if desired, for example if your arduino data was terminated with a carriage return then Newline could be adjusted like so
Code:
SerialPort1.NewLine=Chr(13)
The SerialPort1.WriteLine automatically appends the NewLine character when transmitting, if both PC and arduino could be set up to see the same "NewLine" character you could perhaps change the following line
Code:
SerialPort1.Write(txtBoxSendData.Text & vbCr) // Add a CR terminator for the benefit of the Arduino
To
Code:
SerialPort1.WriteLine(txtBoxSendData.Text) // Add a CR terminator for the benefit of the Arduino
Here is a simple example, the delegate displays the incoming string in a textbox with the MultiLine property set to true
Code:
Public Delegate Sub mydelegate(ByVal a_string As String)
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim arduino_string As String = String.Empty
SerialPort1.ReadTimeout = 20
Try
arduino_string = SerialPort1.ReadLine
Me.Invoke(New mydelegate(AddressOf txt_out), arduino_string)
Catch ex As Exception
End Try
End Sub
Private Sub txt_out(ByVal s As String)
TextBox1.AppendText(s & vbCrLf)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SerialPort1.Open()
End Sub
I was not sure why you wanted the BytesToRead, if it is important to know the character count you can capture that and display in the txt_out sub like so
Code:
Private Sub txt_out(ByVal s As String)
TextBox1.AppendText(s & vbCrLf)
Label1.Text = s.Length.ToString
End Sub
EDIT: a quick afterthought..........when you transmit data from PC to arduino it might be wise to make sure the output buffer is empty before you place you data string in there. Place the following as the first line of the transmit button/key
Code:
SerialPort1.DiscardOutBuffer()
Last edited by Mc_VB; May 19th, 2013 at 06:51 PM.
-
May 19th, 2013, 07:06 PM
#6
Thread Starter
Junior Member
Re: ReadTimeout not Working?
The "Active Solution Configuration" is now set to debug however nothing is being displayed in the output window. Both "Exception Messages" and "Program Output" are checked in the output pane.
Now this is getting stranger because I removed the beep from the catch block and it still sounds! I tried doing a build but this doesn't seem to make any difference.
Hi Mc_VB. The reason I am using BytestoRead is to keep track on the size of the backlog in the buffer. I was fiddling around with changing the baud rate during a transmission from a GPS unit (which streams out text regularly every second).This caused a backlog of data and I wanted to see how quickly the buffer could be emptied and processed after the baud rate was changed back to the correct value. So this is sort of a legacy in the code from that.
Last edited by Eugbug; May 19th, 2013 at 07:14 PM.
-
May 19th, 2013, 07:50 PM
#7
Re: ReadTimeout not Working?
Below the active configuration is the project configuration. Is it set to debug also? What version of vb are you using?
Is the GPS attached via a cable or is this a virtual serialport via bluetooth (mine is)?
-
May 19th, 2013, 08:25 PM
#8
Thread Starter
Junior Member
Re: ReadTimeout not Working?
Both active and project configuration are set to debug. I'm using VB 2008 Express Edition.
The Arduino is attached via cable to a USB port. When connected, a virtual serial port is established.
I have two VB projects. One for the GPS unit and the other for the Arduino. The initial project read from the GPS unit. Since some functionality is similar, I used the GPS project code. Now because it isn't possible to do a "save as" of a project, I copied and pasted the original project and manually renamed all relevant files so that they had the same name as the new project. This seems to work fine but this issue with the beep sounding even though it is remmed out led me to think that obj files were somehow being pulled in from the original project if the file list was referencing them (the DataReceive handler is the same in the original project with a beep in the catch block). Any changes I make to variables in this block don't occur. E.g. a variable won't increment. Yet this beep keeps happening! I also restarted the IDE to no avail.
-
May 20th, 2013, 12:22 AM
#9
Re: ReadTimeout not Working?
I'd start a new project and copy and paste just the code you have(don't copy the files). Make sure you create the controls and components before you copy the code.
-
May 20th, 2013, 01:59 PM
#10
Thread Starter
Junior Member
Re: ReadTimeout not Working?
After much hassle I rebuilt the project from scratch by creating a new form and adding controls to it which all had to be renamed. I then copied and pasted the code from the original file to the new .vb file.
(Before doing this I took a "short cut" by just creating a form in the new project, drew a selection box around the controls in the old project and copied and pasted them to the form in the new project. Unfortunately due to file references to the old project or whatever, the original code got wiped)
The Debug.WriteLines in the catch block still aren't generating output. I set a breakpoint in the DataReceive handler and the program isn't stepping into this block. The beep which I couldn't get rid of seems to be coming from somewhere else and I have no other beep statement in the code. Sometimes it occurs when the form is displayed and also when myArray(0) = SerialPort1.ReadLine() + vbLf is executed. It's as if a break in execution occurs due to an exception. However no warning is displayed and only a beep sounds.
-
May 20th, 2013, 03:09 PM
#11
Re: ReadTimeout not Working?
I'd suggest starting over with no shortcuts.
-
May 20th, 2013, 03:23 PM
#12
Thread Starter
Junior Member
Re: ReadTimeout not Working?
Ok, I've sorted where this beep is coming from! I am pressing ENTER in a textbox, but the multiline property is set to false. I set it to off while debugging and at the moment I don't need more than one line. Windows thinks I am requesting a new line and beeps to complain. See link http://support.microsoft.com/kb/78305.
Thanks for all the suggestions
-
May 20th, 2013, 03:57 PM
#13
Re: ReadTimeout not Working?
What about the "breakpoint in the DataReceive handler and the program isn't stepping into this block"??? Are you still having the timeouts?
-
May 20th, 2013, 04:07 PM
#14
Thread Starter
Junior Member
Re: ReadTimeout not Working?
 Originally Posted by dbasnett
What about the "breakpoint in the DataReceive handler and the program isn't stepping into this block"??? Are you still having the timeouts?
No, it seems there were never timeouts in the first place. When the beep sounded, I got misled into thinking that this was due to the beep function I had added in the catch block. When I took it out there was still a beep due to this multiline issue. Execution never enters the catch block.
-
May 21st, 2013, 09:26 AM
#15
Re: ReadTimeout not Working?
FYI. I tested this:
Code:
Public Delegate Sub mydelegate(ByVal a_string As String)
Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim arduino_string As String = String.Empty
SerialPort1.ReadTimeout = 20
Try
arduino_string = SerialPort1.ReadLine
Me.Invoke(New mydelegate(AddressOf txt_out), arduino_string)
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End Sub
As I suspected it is subject to timeout errors for the reasons specified. You may not see the error, but it can happen. If you run the code at very low speeds, i.e. 1200bps, the error occurs more frequently. Just wanted to give you a heads up.
-
May 21st, 2013, 02:47 PM
#16
Addicted Member
Re: ReadTimeout not Working?
Hi,that is the whole point of a time out, it is not a mistake in the example but designed into the code to stop the ReadLine blocking on reception due to erroneous data or signals. Any timeout value is subject to timeout errors or what would be the point in using it.
20 mS time out should be good for in excess of a block of 40 characters at the OP's desired rate of 9600 baud. To achieve the same amount of characters without error at 1200 baud the timeout value would have to be scaled up ~x8 (160 mS). I have not tested those figures they are just calculations off the top of my head and must be somewhere in the ball park, the principal is there.
The value in the time out is important and does not have to be a constant, it can be a variable calculated on baudrate and maximum characters allowed in a single block of data.
It is a good point raised though and shows just one of many considerations that should be made when interfacing PC to device
-
May 21st, 2013, 03:43 PM
#17
Re: ReadTimeout not Working?
 Originally Posted by Mc_VB
Hi,that is the whole point of a time out, it is not a mistake in the example but designed into the code to stop the ReadLine blocking on reception due to erroneous data or signals. Any timeout value is subject to timeout errors or what would be the point in using it.
20 mS time out should be good for in excess of a block of 40 characters at the OP's desired rate of 9600 baud. To achieve the same amount of characters without error at 1200 baud the timeout value would have to be scaled up ~x8 (160 mS). I have not tested those figures they are just calculations off the top of my head and must be somewhere in the ball park, the principal is there.
The value in the time out is important and does not have to be a constant, it can be a variable calculated on baudrate and maximum characters allowed in a single block of data.
It is a good point raised though and shows just one of many considerations that should be made when interfacing PC to device
Timeout errors are an indication that a mistake has occurred, it is not part of a protocol. It should be used to catch errors and nothing more. It is just a little bit harder to write code that does not have timeout errors, except for a legitimate one. This example should not have timeout errors, but because of the readline in the event handler it can have them.
-
May 21st, 2013, 05:57 PM
#18
Thread Starter
Junior Member
Re: ReadTimeout not Working?
I'm still confused about how data is received and the DataReceived event works. The ReceivedBytesThreshold is set to 1 so once the first byte is received and stored in a buffer under interrupt control, doesn't the DataReceive event trigger? (To add to the confusion, it says in the documentation - "The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer")
The ReadLine method in my code then reads from the buffer until a termination character is reached or a timeout occurs. By the way my timeout is set at 1 second to allow for any minor processing being done on the Arduino board. At present the response more or less instantly follows the command. Of course if a user is performing key entry on the Arduino, a delay could occur. However the Readline is only called when the DataReceive event is triggered i.e when the Arduino actually replies.
-
May 21st, 2013, 06:33 PM
#19
Re: ReadTimeout not Working?
Lets say that you send 3 characters, say 'abc', followed by the newline character, and that the DataReceived event fires for every character.
When the 'a' is received and the event fires you post a ReadLine that is blocked.
The 'b' is received but .Net can't raise the DataReceived event because a previous invocation is waiting on the readline, so it queues it.
Same thing happens for the 'c'.
Then along comes the newline and the original readline happens. But then two more DataReceived events fire with no data and you have timeouts.
The reason you may not be seeing this is that by the time the datareceived event is fired the rest of the characters may be in the buffer.
The easiest way to visualize this is to assume that a DataReceived event will be fired for every byte received, the worst case. Program to that standard and you will not have errors.
Last edited by dbasnett; May 21st, 2013 at 06:38 PM.
-
May 25th, 2021, 02:57 AM
#20
New Member
Re: ReadTimeout not Working?
Hi....You need to use the same technique as the 'Blink without delay' example.
Before you start checking if a characetr is available on the serial port, you store the current value of millis(). You then loop waiting for a character until either a character arrives or the new current millis() value is bigger than the timeout.
pcb assembly
Last edited by JethTran; Jul 23rd, 2021 at 04:05 PM.
-
May 25th, 2021, 07:22 AM
#21
Re: ReadTimeout not Working?
Welcome to the forum. Before replying to a thread, check the date of the last response. If it is more than a few months old, generally there is no reason to reply. In this case, where the last post was over 9 years ago, you definitely should not have replied. This is known as "grave digging", and is frowned upon.
"Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930
Tags for this Thread
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
|