Help with string of characters

Hi guys, complete newbie here, I only started with arduino about 3 weeks ago and have little to no experience with programming.

Anyway, I'm trying to use a virtual joystick Android app call "Joystick BT Commander" in order to control a couple of servos over bluetooth (I have a HC-06 bluetooth transceiver connected to the arduino). I have the code for the servo working with an potentiometer, so now it's time to get the app portion working.

The app puts out a string of 6 characters, with the first three being the value of the x-axis, and the other three being the y-axis. When I read the values and print them in the serial monitor they come out as the same six digit string of characters.

How to can I separate these characters in order use the first three to control one servo, and the second one to control the other? Sorry if this is really basic, as I am really new.

Here is the code I have so far, it's nothing really,

char inchar;

void setup() {
Serial1.begin(9600);
Serial.begin(9600);

}

void loop() {
  
if(Serial1.available() > 0) {
  inchar = Serial1.read();
  Serial.print(inchar);
  }
}

Also, I am using the arduino mega 2560, not sure if that helps at all.

Thanks in advance for any help guys! :slight_smile:

Hello and welcome :slight_smile:

My preferred solution is to use sscanf. First you have to store those characters in a char array, then you parse this char array with sscanf, something like this:

void loop()
{
    // if there is something in the serial buffer
    if ( Serial1.available() > 0 )
    {
        // an array that can hold 6 characters + the null terminator
        static char input[7];

        // this will be used as an index of the array
        static uint8_t i;

        // read one character and store it at the end of the input buffer
        input[ i++ ] = Serial1.read();

        // if we have read 6 characters
        if ( i == 6 )
        {
            // make the input array a valid c string
            input[ i ] = '\0';

            // reset for next command
            i = 0;
     
            uint16_t x;
            uint16_t y;

            // scan the input for 2 numbers of 3 digits each, store in x and y
            if ( sscanf( input, "%3hu%3hu", &x, &y ) == 2 )
            {
                // display result
                Serial.println( x );
                Serial.println( y );
            }
        }
    }
}

You can test this with the serial monitor, but you have to set the Line Ending to "No line ending".

guix:
Hello and welcome :slight_smile:

My preferred solution is to use sscanf. First you have to store those characters in a char array, then you parse this char array with sscanf, something like this:

void loop()

{
    // if there is something in the serial buffer
    if ( Serial1.available() > 0 )
    {
        // an array that can hold 6 characters + the null terminator
        static char input[7];

// this will be used as an index of the array
        static uint8_t i;

// read one character and store it at the end of the input buffer
        input[ i++ ] = Serial1.read();

// if we have read 6 characters
        if ( i == 6 )
        {
            // make the input array a valid c string
            input[ i ] = '\0';

// reset for next command
            i = 0;
   
            uint16_t x;
            uint16_t y;

// scan the input for 2 numbers of 3 digits each, store in x and y
            if ( sscanf( input, "%3hu%3hu", &x, &y ) == 2 )
            {
                // display result
                Serial.println( x );
                Serial.println( y );
            }
        }
    }
}




You can test this with the serial monitor, but you have to set the Line Ending to "No line ending".

Thanks for the reply!

Sorry to be annoying but, I think I made a mistake. :stuck_out_tongue:

I think The characters are not part of a string since they are all being printed on separate lines.

the characters appear on the serial monitor like this (copied and pasted directly from it):

2
0
0
2
0
0


2
0
0
2
0
0

Not on a same line. Sorry for the miss information!

Anyway, my question still stands, how would I be able to turn these characters in strings of three in order to use them for control?

Ok, so try with this slightly modified code (I just added a check so it adds the character in the array only if it's a digit).

void loop()
{
    // if there is something in the serial buffer
    if ( Serial1.available() > 0 )
    {
        // an array that can hold 6 characters + the null terminator
        static char input[7];

        // this will be used as an index of the array
        static uint8_t i;

        // read one character
        char c = Serial1.read();
   
        // if the character is a digit
        if ( c >= '0' && c <= '9' )
        {
            //store it at the end of the input buffer
            input[i++] = c;

            // if we have read 6 digits
            if ( i == 6 )
            {
                // make the input array a valid c string
                input[ i ] = '\0';

                // reset for next command
                i = 0;
     
                uint16_t x;
                uint16_t y;

                // scan the input for 2 numbers of 3 digits each, store in x and y
                if ( sscanf( input, "%3hu%3hu", &x, &y ) == 2 )
                {
                    // display result
                    Serial.println( x );
                    Serial.println( y );
                }
            }
        }
    }
}

Note: if you are sure that the numbers are never greater than 255 (a byte), then you can optimize the code like so

                uint8_t x;
                uint8_t y;

                // scan the input for 2 numbers of 3 digits each, store in x and y
                if ( sscanf( input, "%3hhu%3hhu", &x, &y ) == 2 )

Edit: Based on what you received in your serial monitor, it seems that there are start and end characters between each pairs of values. Here is what you posted, converted to decimal:

50 13 10 48 13 10 48 13 10 50 13 10 48 13 10 48 13 10 3 13 10 2 13 10 50 13 10 48 13 10 48 13 10 50 13 10 48 13 10 48


13 and 10 are '\r' and '\n', 3 is ETX, 2 is STX

So most likely, each pair of value is sent as:

STX
2
0
0
2
0
0
ETX

So, with this, you can make the code more robust: check if the first character is STX, if yes then store characters until a ETX character is read... I can't be bothered to write code for this, but that should be easy, try it :stuck_out_tongue:

Additionally, here is something that you should read :slight_smile:

guix:
Ok, so try with this slightly modified code (I just added a check so it adds the character in the array only if it's a digit).

void loop()

{
    // if there is something in the serial buffer
    if ( Serial1.available() > 0 )
    {
        // an array that can hold 6 characters + the null terminator
        static char input[7];

// this will be used as an index of the array
        static uint8_t i;

// read one character
        char c = Serial1.read();
 
        // if the character is a digit
        if ( c >= '0' && c <= '9' )
        {
            //store it at the end of the input buffer
            input[i++] = c;

// if we have read 6 digits
            if ( i == 6 )
            {
                // make the input array a valid c string
                input[ i ] = '\0';

// reset for next command
                i = 0;
   
                uint16_t x;
                uint16_t y;

// scan the input for 2 numbers of 3 digits each, store in x and y
                if ( sscanf( input, "%3hu%3hu", &x, &y ) == 2 )
                {
                    // display result
                    Serial.println( x );
                    Serial.println( y );
                }
            }
        }
    }
}




Note: if you are sure that the numbers are never greater than 255 (a byte), then you can optimize the code like so


uint8_t x;
                uint8_t y;

// scan the input for 2 numbers of 3 digits each, store in x and y
                if ( sscanf( input, "%3hhu%3hhu", &x, &y ) == 2 )




Edit: Based on what you received in your serial monitor, it seems that there are start and end characters between each pairs of values. Here is what you posted, converted to decimal:


50 13 10 48 13 10 48 13 10 50 13 10 48 13 10 48 13 10 3 13 10 2 13 10 50 13 10 48 13 10 48 13 10 50 13 10 48 13 10 48



http://www.asciitable.com/index/asciifull.gif
13 and 10 are '\r' and '\n', 3 is ETX, 2 is STX

So most likely, each pair of value is sent as:


STX
2
0
0
2
0
0
ETX




So, with this, you can make the code more robust: check if the first character is STX, if yes then store characters until a ETX character is read... I can't be bothered to write code for this, but that should be easy, try it :P


Additionally, [here](http://gammon.com.au/serial) is something that you should read :)

Thankyou very much for the help, really appreciate it! :slight_smile: