I have a general question about the Serial.read() command.
We are currently connecting a 9DOF Razor from sparkfun (have a look if you are interested)
The data we have coming into the Arduino is always in the form
!ANG:375,349,333
There will always be three digit values and there will always be commas etc.
My question is about how the Serial.read() functions, I posted previously about something similar but wasnt 100% about how it is applied.
As I want to use the values only as data i.e the 375 or 349 in this case, I was told that to skip reading the !ANG and the commas etc. I would use the Serial.read() command the required amount of times.
i.e to skip !ANG - Serial.read();Serial.read();Serial.read();Serial.read();
one to skip the exclamation mark one for the A and so on.
then the next step is to read each digit to combine these which I know how to do.
So does the Serial.read() command read the first character then the next read the second and so on in a line of data?
I have added a link above to the original post where I was discussing the best way to interpret the data, I was told that to get the whole number i.e 374 i would read the 3 then multiply by 100 then add the 7 multiplied by 10 then add the last digit.
So was what the poster said about the Serial.read() completely wrong.
The core issue is what AWOL was talking about in your linked thread. Serial data transmission is very slow compared to the execution speed of Arduino code. What this means is that just because you have read one character from the serial port does not mean that the rest of the data you're looking for has arrived yet. You have to check if it has. The code you posted in your other thread that reads the Razor data takes care of this:
Note that it never reads a serial port without checking for the presence of something to read using Serial.available.
You can use Serial.read to skip over characters you don't want and use multiplication by 10 as shown earlier to build up the digit stream into ints. You just need to take care of the problem of issuing Serial.read, thinking that you're skipping something, when in fact you got -1 from the read because the character you were expecting hasn't arrived yet.
I see what you mean now, bit of a novice with this type of work so sorry if im a bit slow on the uptake.
The code posted was a simple read code we obtained from someone else, which we just took bits out of.
By the looks of it I am guessing that this checks that the line of data is larger than some defined size and smaller than another so it knows the right data to analyse.
if this is the case, do you know of a way to do this by putting in some condition so that Arduino knows to wait until there is 9 characters to analyse.
unsigned int SerialReadThreeDigitNumber()
{
unsigned int result;
while (Serial.available() < 3)
delay(10); // wait 1/100th of a second
result = Serial.read() - '0';
result *= 10; // That is shorthand for result = result * 10;
result += Serial.read() - '0';
result *= 10;
result += Serial.read() - '0';
return result;
}
If you can put a "delimiter" on the end of each string you send to mark the end of the string, then the below code might be of use.
//zoomkat 9-9-10 simple delimited ',' string parce
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter
String readString;
void setup() {
Serial.begin(9600);
}
void loop() {
//expect a string like wer,qwe rty,123 456,hyre kjhg,
//or like hello world,who are you?,bye!,
while (Serial.available()) {
delay(1); //small delay to allow input buffer to fill
char c = Serial.read(); //gets one byte from serial buffer
if (c == ',') {break;} //breaks out of capture loop to print readstring
readString += c; //makes the string readString
}
if (readString.length() >0) {
Serial.println(readString); //prints string to serial port out
//do stuff here
readString=""; //clears variable for new input
}
}
I wonder if you could explain the start of the code you have included, regarding the Serial.available() < 3 does this mean that the code will only function if the first value is less than three ? or does it mean that it will work as long as there is less than three digits?
I understand the command and how to use it, although i dont understand what conditions are being placed on it. Does the 3 relate to a single digit or a number of digits. i.e how does the command interpret this number.
If you look at the reference information for Serial.available() you see that it returns the number of characters that are waiting in the receive buffer.
Serial.read() returns the next available character from the receive buffer. IF THERE ARE NO CHARACTERS IN THE BUFFER IT RETURNS -1.
If you check for (Serial.available()) or (Serial.available() != 0) or (Serial.available() > 0) [which all mean the same thing] you can call Serial.read() once and get a character but if you Serial.read() again without checking for Serial.available() you may get a -1 instead of the next character.
Right, thanks. As I say I am a complete novice to these systems and with the short amount of time we have am trying to learn alot.
So with that I already know that the input to the serial is always in the form of 9 numbers per line, nothing else. My only concern if it is possible is that when doing a serial.read() it starts reading halfway through the line.
As i mentioned before that I need is the three numbers.
e.g 325421544 so from this I need to recognise the numbers 325, 421 and 544 if you get me
lau06275:
My only concern if it is possible is that when doing a serial.read() it starts reading halfway through the line.
You need some form of delimiter to handle that. A prefix or suffix character (or both), to indicate the start and end of a line.
Another potential concern: Are all the readings guaranteed to be 3 characters long? will a value of 90 be represented as 090, or as 90 (meaning you may not always get 9 characters total). The answer is that the readings are not guaranteed to be 3 characters long (unless you are running modified code on the Razor to make it so).
The reality is the original formatted output of the Razor is exactly what you should be using. It provides an identifiable header, delimiters, and terminating characters to be able to reliably parse the readings. the process to properly parse the output is not all the difficult.
Read and drop incoming characters until you get an '!'.
Read incoming characters and store them in a c string until you get a newline character.
Use strchr() to find the start of each numeric value.
a. Start of the first value will be after the ':' character.
b. Start of the second value will be after the first ',' character.
c. Start of the third value will be after the second ',' character.
As you find the start of each value, pass it to atoi() to convert each value to an int.
Yes what I have done is add 360 onto each value so that they will never go below a three digit number and never be negative etc as that changed the amount if characters.
So in the method you have described it will find the three digit int value without having to read each character then combine them by multiplying by 100 and 10 etc.
It seems a much more elegant way of getting the values.
Trying to go forward with the method you highlighted. Do you have an example code or anything that you have done in the past you could upload, just to get a feel for using the strchr(0 and atoi() functions
This sample code should help you with the usage of strchr() and atoi(). Comments in code explain critical points:
#include <string.h>
#include <stdlib.h>
//Sample string to search
char buf[] = "!ANG:321,24,194";
void setup(){
Serial.begin(115200);
}
void loop(){
//strchr returns a pointer to the character we are looking for
//However, we really want the character AFTER the colon, so we add 1 to the pointer
char* tmp = strchr(buf, ':') + 1;
int tmpVal = 0;
//We should check that the pointer isn't NULL (which is what strchr returns when it fails to find the character)
if(tmp != NULL){
//extract the int from the buffer
tmpVal = atoi(tmp);
Serial.println(tmpVal);
}
else{
Serial.println("NULL");
}
tmp = strchr(buf, ',') + 1;
if(tmp != NULL){
tmpVal = atoi(tmp);
Serial.println(tmpVal);
}
else{
Serial.println("NULL");
}
//IMPORTANT NOTE:
//For the second comma, we pass it the previous pointer instead of the entire buffer
//Otherwise we would just continue finding the first comma.
//buf itself is really just a pointer to the start of our string of chars.
tmp = strchr(tmp, ',') + 1;
if(tmp != NULL){
tmpVal = atoi(tmp);
Serial.println(tmpVal);
}
else{
Serial.println("NULL");
}
//This just shows what happens when we search for a character that isn't in our string
tmp = strchr(buf, 'x');
if(tmp != NULL){
tmpVal = atoi(tmp);
Serial.println(tmpVal);
}
else{
Serial.println("NULL");
}
delay(1000);
}
void setup()
{
Serial.begin(9600);
}
bool ReadingString=false; // Are we building a string?
char Buffer[17]; // Build up the string from the Razor here
byte BufferIndex=0; // Next free position in the buffer
int AxisOne=0; // Value from the Razor
int AxisTwo=0; // Value from the Razor
int AxisThree=0; // Value from the Razor
void loop()
{
int c;
if(Serial.available()) // Something there?
{
c=Serial.read(); // Get a character
if(c=='!') // Use the ! to indicate the start of a series to read
{
ReadingString=true; // Now we're reading to the buffer, rather than just throwing stuff away
BufferIndex=0; // Reset to the start of the buffer
}
else //Not a !. If we're mid string, store it, otherwise, throw it away
{
if(ReadingString) //Should we store it?
Buffer[BufferIndex++]=c;
if(BufferIndex>14) // Have we read an entire Razor string
{
ReadingString=false; // Done reading
Buffer[BufferIndex]=0; // Set a terminator for the last atoi
BufferIndex=0; // Reset to start of buffer for next string
ReadAxisValues(); // Read & display the values we got
}
}
}
}
void ReadAxisValues()
{
AxisOne=atoi(&Buffer[4]);
AxisTwo=atoi(&Buffer[8]);
AxisThree=atoi(&Buffer[12]);
Serial.print (AxisOne);
Serial.print(" ");
Serial.print (AxisTwo);
Serial.print(" ");
Serial.print (AxisThree);
Serial.println("");
}
It's looking for strings of the form !ANG:321,245,194 as in your original post, noting that each value must have 3 chars. Basically, it looks for a ! and then grabs the 15 bytes that follow it, then uses atoi to parse the values out of it.