Converting 1-3 chars numbers (Decimal values 48-57) to a single int value.

So I'm trying to make 2 arduinos talk to each other trough TTL serial port.
From the transmitter I have two byte variable of decimal data that I want to sent to the receiver arduino and to the receiver I want to send a unique char for each byte of decimal data I send to let the other receiver arduino to know what the transmitter refers to and when I send byte x = 112; to the other arduino it receives that as

49
49
50

and I want to put those values into one byte that equals to 112 like what the other arduino had sent;

How do I do that? what is the standard protocol for starting a definition of data and finishing it.

Thanks for your time.

You get to define the protocol. That’s up to you and your code. I like surrounding transmissions with < and >, but you can use whatever you’d like.

As for converting the ascii characters back to real numbers, have a look at the atoi() command.

Have a look at the examples in Serial Input Basics - especially the 3rd example that uses < and > as start- and end-markers. There is also a parse example.

…R

Here’s an alternative to Robin’s suggestion. It assumes you used Delta_G’s concept of the input stream with sentinels. As a test input, try: <49, 49, 50>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  char alpha;
  char buffer[10];
  char result[4];
  char *ptr;
  int charsRead;
  int pos;
  int number;
  
      // Test input: <49,49,50>
  if (Serial.available() > 0) {
    alpha = Serial.read();
    if (alpha == '<') {             // Start the input stream...
      pos = 0;
      charsRead = Serial.readBytesUntil('>', buffer, sizeof(buffer) - 1);  // Get bytes up to sentinel
      buffer[charsRead] = '\0';     // Make it a string
      ptr = strtok(buffer, ",");    // Tokenize the string
      while (ptr != '\0') {
        result[pos++] = (char) (atoi(ptr)); // Make each a digit character
        ptr = strtok('\0', ",");
      }
      result[pos] = '\0';           // Make it a string, too.
      number = atoi(result);
      Serial.print("Number = ");
      Serial.println(number);     
    }
  }
}

@econjack, I don't like readBytesUntil() because it is a blocking function.

...R

Sometimes blocking is what you want to do and sometimes it's not.

@Robin: I realize it's a blocking function and that many (most?) people here don't like it. However, it appears that the OP can't do anything until he receives all of the input, so it may not be all that bad in this case.

Also, if blocking is a problem, this might be one of those teaching moments where the code "usually" works, but there are situations where it doesn't. Often, you learn the lesson better when you experience it rather than being told about it. Either way, I think the example might help the OP learn about the Serial object and strtok(), and that can't be all bad.

Why not just have something like this. (Single incoming value)

#define IsWithin(x,a,b) ((x >= a) && (x <= b))

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() 
{
  // put your main code here, to run repeatedly:
  static int receivedValue = 0;
  static byte ReceivedAll = false;

  if (Serial.available() )
  {
    static int myNum = 0;

    ReceivedAll = false;
    char Val = Serial.read();

    if (IsWithin(Val, '0', '9'))
      myNum = (myNum * 10) + (Val - '0');

    if (Val == '\n' || Val == '\c')
    {
      receivedValue = myNum;
      myNum = 0;
      ReceivedAll = true;
    }
  }

  if (ReceivedAll)
  {
    // do somthing
  }
}

You can also modify the code to look for multiple values separated by commas too.

econjack:
Here’s an alternative to Robin’s suggestion. It assumes you used Delta_G’s concept of the input stream with sentinels. As a test input, try: <49, 49, 50>

void setup() {

// put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  char alpha;
  char buffer[10];
  char result[4];
  char *ptr;
  int charsRead;
  int pos;
  int number;
 
      // Test input: <49,49,50>
  if (Serial.available() > 0) {
    alpha = Serial.read();
    if (alpha == ‘<’) {            // Start the input stream…
      pos = 0;
      charsRead = Serial.readBytesUntil(’>’, buffer, sizeof(buffer) - 1);  // Get bytes up to sentinel
      buffer[charsRead] = ‘\0’;    // Make it a string
      ptr = strtok(buffer, “,”);    // Tokenize the string
      while (ptr != ‘\0’) {
        result[pos++] = (char) (atoi(ptr)); // Make each a digit character
        ptr = strtok(’\0’, “,”);
      }
      result[pos] = ‘\0’;          // Make it a string, too.
      number = atoi(result);
      Serial.print("Number = ");
      Serial.println(number);   
    }
  }
}

Well thanks that kinda helps on the receiver side of the program but how to I take a part the byte and insert the , withing those strings if I it like this:

byte OutX = 112;

Serial.print(‘X’); // this chat lets the receiver to know about what variable we are talking about
Serial.print(’<’); // Start sending the
Serial.print(OutX);
Serial.print(’>’);// Done with that move on !
delay(1000);

And how that function works?
buffer[charsRead] = ‘\0’;

But if you want to send the byte with 112, why not sent that!

Now you just sent the value as it's ASCII representation to the other arduino and convert it back. A whole lot of work for nothing!

I think now you do something like

Serial.print(someValue);

Just change it to

Serial.write(someValue);

It will just sent out one byte of data instead of converting it into the ASCII value of it. This way you only need 1 serial.read to recover the same value.

Yeah I made some thing simpler but I’m still having some issues now when I read what the receiver side gets when I send the data is that:

X<112>

repeatedly , and all I want is to get only what is in those brackets <> into an int of a value that equals to 112;

That’s just some data protocol issue I’m trying to work on.

Here is a much simpler version to that of Robin’s and Econjack’s code. No strtok() needed and it can do strings with multiple pieces of data like this: <123,45,6789> or just simply <112>

int buffer[8];
int counter = 0;

void setup() 
{
  Serial.begin(115200);
}

void loop() 
{
  if (Serial.available() > 0) 
  {
    char temp = Serial.read(); // example incomming data <1,23,456,7890>
    if ( temp == '<' ) // is incoming char equal to <, if so gather the rest
    {
      counter = 0; // make sure counter is set to zero
      while (1) 
      {
        if (Serial.available() > 0)
        {
          char temp = Serial.read(); // read in incoming char

          if (temp != ',' && temp != '>')
          {
            buffer[counter] = (buffer[counter] * 10) + (temp - '0'); // converts temp into an int then stores it
          }

          if (temp == ',')
          {
            counter++; // increment buffer index
          }

          if (temp == '>') // if incoming char is >, then break out of loop
          {
            break; // breaks out of the while loop
          }
        }
      }
    }

    for (int NUM = 0; NUM <= counter; NUM++) //will output "1,23,456,7890"
    {
      Serial.print(buffer[NUM]);
      if (NUM != counter) Serial.print(",");
    }
    Serial.println();
  }

  memset(buffer, 0, sizeof(buffer)); // change suggested by Econjack
}

However, if it is just X<112>, then my previous code would have worked too. And if you want it to also look at the beginning char ‘X’ then you can mod the code to sort the data by that first char.

Since you have X<112> will you be using other chars like Y or Z too? Can you change the output to just X112 instead?

I made a RGB control sketch for another user a few months back. His data looked like this R10G255B50 and this sketch was able to sort the values into their correct colors. You can change it to use XYZ or anything really if you need to.

RGBLed Control:

//#define IsWithin(x,a,b) ((x >= a) && (x <= b))
#define R_pin 2
#define G_pin 3
#define B_pin 4

typedef struct myColors
{
  byte R;
  byte G;
  byte B;
};

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(R_pin, OUTPUT);
  pinMode(G_pin, OUTPUT);
  pinMode(B_pin, OUTPUT);
}

void loop()
{
  // put your main code here, to run repeatedly:
  if (Serial.available() > 0)
  {
    myColors ReturnedColors = GetColors(Serial.read());
    analogWrite(R_pin, ReturnedColors.R);
    analogWrite(G_pin, ReturnedColors.G);
    analogWrite(B_pin, ReturnedColors.B);
  }
}

struct myColors GetColors(char tmp)
{
  static myColors C;
  static int Value = 0;
  static char Color = 'R';

  if (IsWithin(tmp, '0', '9'))
    Value = (Value * 10) + tmp - '0';
  else if (IsWithin(tmp, 'a', 'z') || IsWithin(tmp, 'A', 'Z'))
  {
    Color = tmp;
    Value = 0;
  }

  switch (Color)
  {
    case 'R':
    case 'r':
      C.R = Value;
      break;

    case 'G':
    case 'g':
      C.G = Value;
      break;

    case 'B':
    case 'b':
      C.B = Value;
      break;
  }
  return C;
}

Instead of:

  while (counter != -1) 
  {
    buffer[counter] = 0;
    --counter;
  }

why not use:

memset(buffer, 0, sizeof(buffer));

Sure. But I didn't want to use it for that sketch because the guy was a beginner, so I wanted to keep it simple.

I'll change it for this one.

HazardsMind:
Here is a much simpler version to that of Robin's

My code deliberately reads all the data into a char array before trying to make sense of any of it. The idea is to separate the business of receiving the data from the business of using it.

...R

But again, why sent ascii crap to only convert it back to a byte?

septillion:
But again, why sent ascii crap to only convert it back to a byte?

It is much easier to debug code when you send printable characters. You can often test the code with the Serial Monitor.

However sometimes the greater efficiency of sending binary data outweighs the inconvenience.

...R