I have a quick question regarding this code below in Arduino:
Serial.print("0");
Serial.print(5);
Serial.print("0");
Serial.print(1);
Serial.print("0");
Serial.print(5);
Serial.print("0");
Serial.print(1);
Serial.print("0");
Serial.println(5);
In C code, currently I'm receiving the message using this method below:
int serialport_read_until(int fd, char* buf, char until, int buf_max, int timeout)
{
char b[1]; // read expects an array, so we give it a 1-byte array
int i=0;
do {
int n = read(fd, b, 1); // read a char at a time
if( n==-1) return -1; // couldn't read
if( n==0 ) {
usleep( 1 * 1000 ); // wait 1 msec try again
timeout--;
if( timeout==0 ) return -2;
continue;
}
buf[i] = b[0];
i++;
} while( b[0] != until && i+1 < buf_max && timeout>0 );
buf[i] = 0; // null terminate the string
return 0;
}
In C i defined:
char message[13];
uint32_t num;
char until = '\n';
serialport_read_until(fd, message, newLine, sizeof message, 20000);
// the 20000 is timeout in millisec
// this method stores the data in serial buffer into message array
printf("message is %d\n", num);
I am expecting a raw value of 0501050105 first. Then I convert this raw string into 501050105 using:
sscanf(message, "%d", &num);
Currently it works fine, but I strongly believe it is not the correct way to do it (or rather not the optimized way to do it).
In addition, when i use serialport_read_until() method above, even though i specify the char until as '\n', the method terminates after reading '\r' (leaving the \n in the serial buffer), and the '\n' is only captured in the next method call.
Q1: Am i reading the \r\n wrongly from the println (I saw in Arduino documentation that println prints \r\n)? What resulted in C 'cutting off' the message when it detected a \r from Arduino even though I specifically set to kill it only when \n is received?
Q2: Instead of printing a string to me and converting it back to integer in C, is there a way for Arduino to send me a long value directly instead? eg 501050105 or 51515. how should I rewrite the serial print or method? And how do i capture that integer correctly in C? If i'm not wrong if a raw integer is print out from Arduino, it converts it into ASCII code. I'm still very new to C and Arduino and hope some guidelines to be given so I can improve on the current coding.
Thank you very much.
1 Answer 1
char b[1]; // read expects an array, so we give it a 1-byte array
No, it expects a pointer to a destination to store the data. You don't need a 1-entry array - you can simplify your code with:
char b;
...
int n = read(fd, &b, 1); // read a char at a time
...
buf[i] = b;
... etc ...
Currently it works fine, but I strongly believe it is not the correct way to do it (or rather not the optimized way to do it).
C has the function strtoul()
which is far more efficient that sscanf.
uint32_t val = strtoul(buf, NULL, 10);
The 10
is the base to convert from, so you could convert hexadecimal (base 16), octal (base 8), etc using it.
Q1: Am i reading the \r\n wrongly from the println (I saw in Arduino documentation that println prints \r\n)? What resulted in C 'cutting off' the message when it detected a \r from Arduino even though I specifically set to kill it only when \n is received?
You're defining the variable until
to contain \n
, yet passing the variable newLine
to your function. Maybe that has something to do with it?
Q2: Instead of printing a string to me and converting it back to integer in C, is there a way for Arduino to send me a long value directly instead? eg 501050105 or 51515. how should I rewrite the serial print or method? And how do i capture that integer correctly in C? If i'm not wrong if a raw integer is print out from Arduino, it converts it into ASCII code. I'm still very new to C and Arduino and hope some guidelines to be given so I can improve on the current coding.
You can send a 32-bit value using just 4 bytes. However it's not reliable without implementing a whole protocol around those 4 bytes which, for just 4 bytes, is a bit of a waste. Simplest just to stick to ASCII encoding your data.
-
Thanks for the feedback! That was a typo! It's
char newLine = '\n';
Not sure why it still cuts at \r. Could it possibly be because of something like this? github.com/todbot/arduino-serial/issues/9 Could I be missing something like this?options.c_iflag &= ~ICRNL; // Don't Map CR to NL
Doe Joe– Doe Joe2016年03月26日 17:39:00 +00:00Commented Mar 26, 2016 at 17:39
5,1,5,1,5
? Are the zeroes part of the number or a delimiter?