1

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.

8
  • What's the number you are sending? 501050105? or 51515?
    – Nick Gammon
    Mar 26, 2016 at 22:25
  • @NickGammon currently we are sending 501050105 but we are thinking of reducing it to 51515 in future. Both will still be long in Arduino
    – Doe Joe
    Mar 27, 2016 at 4:55
  • What I am trying to ask is: What is the "actual" number you are sending? For example, could it be: 5,1,5,1,5? Are the zeroes part of the number or a delimiter?
    – Nick Gammon
    Mar 27, 2016 at 20:55
  • @NickGammon yes we are trying to send 5,1,5,1,5 efficiently from arduino to C!! Not sure if theres any other efficient ways to do it. We currently reserve 2 digits for the 5 different variables, so i split them up with x%100 followed by x/100 and repeat 4 more times
    – Doe Joe
    Mar 28, 2016 at 1:33
  • The commas sounds much more sensible to me. What if you want to send a zero?
    – Nick Gammon
    Mar 28, 2016 at 2:02

1 Answer 1

0

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.

1
  • 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
    Mar 26, 2016 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.