Hi Guys,
I am new to Arduino and I am still trying to get my head around its language. I am writing a program that will extract a substring from a terminal input and send the extracted substring back to the serial monitor. The main reason for this is to determine if the command string received is valid for the device receiving it. All I am trying to do is read the first 2 digits of a 10 digit number sent to the device. Take a look at the snippet below. When I run this and enter 452000012 in the serial monitor, it returns nothing but a linefeed. All I am trying to do is find out if the first 2 digits are 45.
String deviceid;
int cmd;
int val;
int slen;
String msg;
void setup()
{
Serial.begin(9600);// setup comminications
}
void loop()
{
if (Serial.available()>0){// start the process if something arrives in the buffer
msg=char(Serial.read());// read in to 'msg' as a char string
msg=msg.trim();//trim any accidental spaces
deviceid=msg.substring(1,3);// load first 2 characters into 'deviceid'
Serial.print(deviceid);//show contents of 'deviceid' variable
Serial.flush();// get rid of any junk
Please use the #button to apply code tags to code, makes it more readable .
As charcters come in one by one msg will never contain more than one character.
(tweaked your code a bit but not compiled or tested )
String deviceid;
int cmd;
int val;
int slen;
String msg;
void setup()
{
Serial.begin(9600);
Serial.println("start "); // test serial
}
void loop()
{
while (Serial.available() > 0)
{
msg = msg + Serial.read(); // read in ONE char
delay(1); // give serial some time to accept the data
}
if (msg.Length() > 0)
{
Serial.print("msg len : ");
Serial.println(msg.Length() );
msg = msg.trim();
deviceid = msg.substring(1,3); // load first 2 characters into 'deviceid'
Serial.println(deviceid);//show contents of 'deviceid' variable
msg = "";
}
}
Thanks to all who made suggestions. With regard to RobTillaart's code modification; it does not work, in fact I am not entirely sure that is anything wrong with his code. If I enter a 9 digit number in the serial monitor, it reposts back '20'. This is wrong even if one is to assume that there is a null termination on the end. If anyone can suggest a snippet to extract a 2 digit substring from a 10 digit string sent via serial monitor. I would love to hear your suggestions. I take on board PaulS's notes on making sure the length is more than 2 before trying to find a 2 character substring in a string less than 2 characters long. This begs the question; what does the processor do if the program crashes or attempts to compute the un-computable ( such as division by zero).
regards,
Chris
This works for me. It does not clear the string or anything, just adds the bytes if the string length is less than 20.
If there are three or more characters in the string, it will print the second and third character.
EDIT: If Linux, versions seem to be important on bugs. Mine are
Arduino 0022 (modified)
avr-gcc 4.5.1 (stock out of the box)
avr-libc 1.7.1 (modified)
GCC 4.5.2 (stock out of the box)
With regard to RobTillaart's code modification; it does not work, in fact I am not entirely sure that is anything wrong with his code. If I enter a 9 digit number in the serial monitor, it reposts back '20'.
It should also provide you the length of the string read, can you provide the complete output?
The fact it provides 20 is an indication for me that it collects more than one char in msg which was the purpose of the code I posted. PaulS is right that the first two characters should do subString(0,2).
What is missing in the code is that the code has no means to align to a number, normally in a protocol there is a start-character e.g. < and a stop character e.g. > to detect where data begins and where it ends. It that is ommitted only timing (data comes in bursts) or semantic parsing of the data (detecting newlines) can help.
Diving into the substring code, it has a bug. It checks if the right parameter is greater than its inner length to prevent out of bound error, - if ( right > _length ) // 2 -
BUT it does not do so for the left parameter,
==> that means left can become larger than right again which was prevented by test 1.... Corrupting the output in String outPut = ( _buffer + left );
tring String::substring( unsigned int left, unsigned int right ) const
{
if ( left > right ) // 1
{
int temp = right;
right = left;
left = temp;
}
if ( right > _length ) // 2
{
right = _length;
}
// insert code here
char temp = _buffer[ right ]; // save the replaced character
_buffer[ right ] = '\0';
String outPut = ( _buffer + left ); // pointer arithmetic
_buffer[ right ] = temp; //restore character
return outPut;
}
one should insert this code to make it robust.
if ( left > _length )
{
left = _length;
}
update
because you called substring(1,3) on an empty string the left parameter jumped over the internal string terminator giving corrupted output.
Thanks to SurferTim and Rob Tillaart. Tims code snippet works fine. Thanks to Rob for taking time to report the bug. I have come from a VB environment where all of the dirty work of programming is done for you, so this concept of having to think during coding is a new thing to me. I am sure that this will not be my last post.
BTW: why doesn't the Serial.read() documentation indicate that it only reads a single byte from the buffer and not the whole buffer?
regards,
Chris