Receiving 2 integers over serial in binary

Hi folks,

What I'm trying to achieve....

Sending 2 motor speed values across Serial.
I want to send them as bytes with a start and end marker.

I'm following example 6 of the Serial Input Basics Serial Input Basics - updated - Introductory Tutorials - Arduino Forum and was planning to use a comma "," (0x2C) as my breakmarker between the 2 integers that I'm sending...

So in serial monitor to test this...I'm sending <123,321>

The output from example 6 of that tutorial shows: "This just in (HEX values)... 31 32 33 2C 33 32 31"

But can you please assist with the code to split the numbers either side of the 2c?
I want to end up with integers used for the motor of 123 and 321 from sending the above.

I haven't included the code tags as the code is available on that tutorial, but can if needed.

Thank you so much in advance and apologies if this is covered somewhere...I did a lot of googling before turning her for help.

of course you can read a sequence of characters into a string array up to a line terminator and use something like strtok() to split the string into tokens based on commas.

i usually include the following code in all my projects. it supports single letter commands that can be preceded by a multi-digit value.

// pcRead - debugging using serial monitor

const char version [] = "PcRead 200416a";

int debug = 0;

// ---------------------------------------------------------
// toggle output bit
void
pinToggle (
    int pin)
{
    static int  bits = 0;
    int     bit = 1 << pin;

    if (debug)  {
        Serial.print ("pinToggle: ");
        Serial.println (pin);
    }

    if (bits & bit)  {
        digitalWrite (pin, LOW);
        bits &= ~bit;
    }
    else {
        digitalWrite (pin, HIGH);
        bits |= bit;
    }
}

// ---------------------------------------------------------
// toggle output bit
int
readString (
    char *s,
    int   maxChar )
{
    int  n = 0;

    Serial.print ("> ");
    do {
        if (Serial.available()) {
            int c    = Serial.read ();

            if ('\n' == c)
                break;

            s [n++] = c;
            if (maxChar == n)
                break;
        }
    } while (true);

    return n;
}

// -----------------------------------------------------------------------------
// process single character commands from the PC
#define MAX_CHAR  10
char s [MAX_CHAR] = {};

int  analogPin = 0;

void
pcRead (void)
{

    static int  val = 13;

    if (Serial.available()) {
        int c = Serial.read ();

        switch (c)  {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            val = c - '0' + (10 * val);
            break;

        case 'A':
            analogPin = val;
            Serial.print   ("analogPin = ");
            Serial.println (val);
            val = 0;
            break;

        case 'D':
            debug ^= 1;
            break;

        case 'I':
            pinMode (val, INPUT);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" INPUT");
            val = 0;
            break;

        case 'O':
            pinMode (val, OUTPUT);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" OUTPUT");
            val = 0;
            break;

        case 'P':
            pinMode (val, INPUT_PULLUP);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" INPUT_PULLUP");
            val = 0;
            break;


        case 'a':
            Serial.print   ("analogRead: ");
            Serial.println (analogRead (val));
            val = 0;
            break;

        case 'c':
            digitalWrite (val, LOW);
            Serial.print   ("digitalWrite: LOW  ");
            Serial.println (val);
            val = 0;
            break;

        case 'p':
#if !defined(ARDUINO_ARCH_ESP32)
            analogWrite (analogPin, val);
            Serial.print   ("analogWrite: pin ");
            Serial.print   (analogPin);
            Serial.print   (", ");
            Serial.println (val);
            val = 0;
#endif
            break;

        case 'r':
            Serial.print   ("digitalRead: pin ");
            Serial.print   (val);
            Serial.print   (", ");
            Serial.println (digitalRead (val));
            val = 0;
            break;

        case 's':
            digitalWrite (val, HIGH);
            Serial.print   ("digitalWrite: HIGH ");
            Serial.println (val);
            val = 0;
            break;

        case 't':
            Serial.print   ("pinToggle ");
            Serial.println (val);
            pinToggle (val);
            val = 0;
            break;

        case 'v':
            Serial.print ("\nversion: ");
            Serial.println (version);
            break;

        case '\n':          // ignore
            break;

        case '"':
            while ('\n' != Serial.read ())     // discard linefeed
                ;

            readString (s, MAX_CHAR-1);
            Serial.println (s);
            break;

        case '?':
            Serial.println ("\npcRead:\n");
            Serial.println ("    [0-9] append to #");
            Serial.println ("    A # - set analog pin #");
            Serial.println ("    D # - set debug to #");
            Serial.println ("    I # - set pin # to INPUT");
            Serial.println ("    O # - set pin # to OUTPUT");
            Serial.println ("    P # - set pin # to INPUT_PULLUP");
            Serial.println ("    a # - analogRead (pin #)");
            Serial.println ("    c # - digitalWrite (pin #, LOW)");
            Serial.println ("    p # -- analogWrite (analogPin, #)");
            Serial.println ("    r # - digitalRead (pin #)");
            Serial.println ("    s   - digitalWrite (pin #, HIGH)");
            Serial.println ("    t   -- toggle pin # output");
            Serial.println ("    v   - print version");
            Serial.println ("    \"   - read string");
            Serial.println ("    ?   - list of commands");
            break;

        default:
            Serial.print ("unknown char ");
            Serial.println (c,HEX);
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void
loop (void)
{
    pcRead ();
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin(115200);

    Serial.println (version);
#if defined(ARDUINO_ARCH_ESP32)
    Serial.println ("esp32");
#endif
}

Sorry, I should have been clearer...

I'm sending these across bluetooth....

And using the example I mentioned...I'm sending

<s,122,134>

The s is an activation command....
The 122 and 134 are Joystick Axis values.

Using the example 5 on the tutorial...I then added the following to display what is being received...

    Serial.print("Message: ");Serial.print(messageFromPC);Serial.print(" - ");Serial.print("X: ");Serial.print(X);Serial.print(" - ");Serial.print("Y: ");Serial.println(Y);

The receiving Arduino is showing:

Message: s - X: 122 - Y: 134
Message: s - X: 1 - Y: 0
Message: s - X: 122 - Y: 14
Message: s - X: 122 - Y: 13122
Message: s - X: 4 - Y: 3434
Message: s - X: 122 - Y: 134

So it looks like a lot of information is not being parsed correctly.

The code I was using for this was....

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (BTserial.available() > 0 && newData == false) {
        rc = BTserial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    X = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    Y = atoi(strtokIndx);     // convert this part to an integer

}

//============

void showParsedData() {
    Serial.print("Message: ");Serial.print(messageFromPC);Serial.print(" - ");Serial.print("X: ");Serial.print(X);Serial.print(" - ");Serial.print("Y: ");Serial.println(Y);
}

But with the garbled receiving data I thought switching to Binary (as per example 6) might be the way forward.... Any help much appreciated.

Where do you handle line feeds? Oh, wait.. I guess you don't have to...

stevehaze666:
So in serial monitor to test this...I'm sending <123,321>

The parse example (Example 5) in my Tutorial explains how to split up that sort of message.

...R

Robin2:
The parse example (Example 5) in my Tutorial explains how to split up that sort of message.

...R

Hi Robin...

I posted in my other reply....that I'm getting very garbled readings using example 5...

I'm sending <s,122,134>

The receiving Arduino is showing: (and other variations like this).

Message: s - X: 122 - Y: 134
Message: s - X: 1 - Y: 0
Message: s - X: 122 - Y: 14
Message: s - X: 122 - Y: 13122
Message: s - X: 4 - Y: 3434
Message: s - X: 122 - Y: 134

Can you help?

Happy to provide more information.

SOLVED it!!!

Added a delay(10) and the garbled message is now not garbled.
I'm still interested in how to split the Binary code as per my original question, though.

Or should I send the motor values (which are from 0-255) as one byte?

stevehaze666:
SOLVED it!!!

Added a delay(10) and the garbled message is now not garbled.

Please post your program. There should be no need for a delay()

I'm still interested in how to split the Binary code as per my original question, though.

As far as I can see you never posted the program in which you tried that. However I suspect your problem is that you are thinking that <123,321> is transmitted as two binary numbers. In fact it is transmitted as 9 characters and my Example 6 does not apply.

Unless it necessary for performance it makes debugging much easier if you send numbers as human-readable text.

...R

I want to send them as bytes with a start and end marker.

So in serial monitor to test this...I'm sending <123,321>

321 won' fit in a byte. :slight_smile:

Hi,

I was sending <123,321> as 9 bytes....but my main question was ...is it possible to combine said bytes to form that numbers I'm trying to received.

So can we make the 3 bytes of 1, 2 and 3 make the number 123? :slight_smile:

Thanks all.

atoi() or sscanf() will convert your cString (ascii text) « 123 » to the number 123

If you shoot the data over Bluetooth don’t use a shotgun approach to send the data as fast as possible because you’ll saturate your serial port and if you are using software serial it can behave weirdly esp if you are above 9600 bauds. I assume the delay mentionner was to only send the data 100 times per second ? (That’s still a lot probably at 9600 bauds - will saturate the buffer and create pauses)

stevehaze666:
....but my main question was ...is it possible to combine said bytes to form that numbers I'm trying to received.

So can we make the 3 bytes of 1, 2 and 3 make the number 123? :slight_smile:

That is the whole purpose of Example 5 in my Tutorial.

And you have your terminology mixed up. You are not sending 3 bytes with the values 1, 2 and 3. You are sending 3 characters. The actual byte values will be 48, 49 and 50 which are the ASCII codes for the characters. And the C++ function atoi() is short for Ascii TO Int

...R

Thank you both for your help and wisdom! :slight_smile: