Serial.read() to Integer

Hello everyone,

I saw this question all around the forum, but nobody ever gave a really good answer on it. I receive a value with serial.read() from a c# application. Then i try to convert the chars to integer which gives me not the real integer value but the bytes as intger. For example 255(int) results in 50535310. The function I use is int vlaue = (int)char_value...

I'm quiet frustrated searching for a simple way to get an integer value so I can use it to set the analogWrite value.

Thanks in advance.

1 Like

If the application sends TEXT then each character is an ASCII code for the symbol to print.

When you receive text digits

serchar = Serial.read();
if ( serchar >= '0' && serchar <= '9' )
{
digitvalue = serchar - '0';

// then whatever you do with that, like multiply value of previous digits by 10 and add this value
}

GoForSmoke:
If the application sends TEXT then each character is an ASCII code for the symbol to print.

When you receive text digits

serchar = Serial.read();
if ( serchar >= '0' && serchar <= '9' )
{
digitvalue = serchar - '0';

// then whatever you do with that, like multiply value of previous digits by 10 and add this value
}

Thank you. But I don't completly understand your approach. Why I have to multiply the value afterwards again? It looks like you only search for the first digit?

Why I have to multiply the value afterwards again?

Decimal weight.

The number one-hundred-and-twenty-three is printed as three characters 123 .

The value is obtained by adding 1 x 10^2
plus 2 x 10^1
plus 3 x 10^0

When you receive the three characters '1' '2' and '3' in the Arduino you have to do the same maths to get the number that those characters represent.

...R

Robin2:
The number one-hundred-and-twenty-three is printed as three characters 123 .

The value is obtained by adding 1 x 10^2
plus 2 x 10^1
plus 3 x 10^0

When you receive the three characters '1' '2' and '3' in the Arduino you have to do the same maths to get the number that those characters represent.

...R

I didn't think about it. Truely I already figured out that I have to multiply them, but I didn't figure out why I doesn't work. When I multiply 1 by 100 the arduino returns me 111 instead of 100 - or 100100100. My code is simple: digitvalue1 = digitvalue1*100; -- this is not just strange..

As long as you keep your code secret I can't help.

...R

Robin2:
As long as you keep your code secret I can't help.

...R

char serchar = Serial.read();
          if ( serchar >= '0' && serchar <= '9' ) 
          {
          digitvalue1 = serchar - '0';

          // then whatever you do with that, like multiply value of previous digits by 10 and add this value 
          }
          result = digitvalue1 * 100;
          Serial.print(result);

If you type 1 it returns 100100100 and so on

Why are you multiplying by 102?

digit 1 = 2; digit 2 = 5; digit 3 = 5; --> digit1 * 100 = 200; digit2*10 = 50 --> digit1+digit2+digit3 = 255 --> the integer I want.

What if only two digits are entered?

Besides, 2 * 100 + 5 * 100 + 5 * 100 won't give you the result you want.

AWOL:
What if only two digits are entered?

Besides, 2 * 100 + 5 * 100 + 5 * 100 won't give you the result you want.

I check the length before. How's your approach to this then? :%

I have text with 4 digits coming in.
First I must have a variable to hold the result which I also build there.
With each new one I move the previous digits to the left 1 place then add the new.
If I write 1234 the first is 1, then 2 makes 12, then 3 makes 123, then 4 makes 1234.

int result;

result = 0;

now my text digits come 1 at a time, "1357" I read 1 at a time in loop()

serchar = Serial.read(); // serchar == '1'
result *= 10; // now result = 0
result += serchar - '0'; // result = 1

serchar = Serial.read(); // serchar == '3'
result *= 10; // now result = 10
result += serchar - '0'; // result = 13

serchar = Serial.read(); // serchar == '5'
result *= 10; // now result = 130
result += serchar - '0'; // result = 135

serchar = Serial.read(); // serchar == '7'
result *= 10; // now result = 1350
result += serchar - '0'; // result = 1357

serchar = Serial.read(); // serchar == something not a digit
// so now the code knows the value is 1357 and reacts to the next character

You can do this as each character comes in or you can buffer then evaluate, the difference is approach, speed and RAM needed. What I have shown is only the algorithm to build a number from text.

Here is a blog by Nick Gammon on some different methods (with code examples) to really go into the subject.

GoForSmoke:
I have text with 4 digits coming in.
First I must have a variable to hold the result which I also build there.
With each new one I move the previous digits to the left 1 place then add the new.
If I write 1234 the first is 1, then 2 makes 12, then 3 makes 123, then 4 makes 1234.

int result;

result = 0;

now my text digits come 1 at a time, "1357" I read 1 at a time in loop()

serchar = Serial.read(); // serchar == '1'
result *= 10; // now result = 0
result += serchar - '0'; // result = 1

serchar = Serial.read(); // serchar == '3'
result *= 10; // now result = 10
result += serchar - '0'; // result = 13

serchar = Serial.read(); // serchar == '5'
result *= 10; // now result = 130
result += serchar - '0'; // result = 135

serchar = Serial.read(); // serchar == '7'
result *= 10; // now result = 1350
result += serchar - '0'; // result = 1357

serchar = Serial.read(); // serchar == something not a digit
// so now the code knows the value is 1357 and reacts to the next character

You can do this as each character comes in or you can buffer then evaluate, the difference is approach, speed and RAM needed. What I have shown is only the algorithm to build a number from text.

Here is a blog by Nick Gammon on some different methods (with code examples) to really go into the subject.
Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking

Thank you - sadly it's not working for me. When I take only one digit with the code below I get (with println on variable result) the values: 1, 1, -35. So three values (!?) and the last one is obviously completly unlogical. Here's the code:

void loop() {
  // put your main code here, to run repeatedly:
        int result;
        char serchar;
        if(Serial.available()){
          result = 0;
          for(int i = 0; i < Serial.available(); i++){
            serchar = Serial.read(); // serchar == '1'
            result *= 10; // now result = 0
            result += serchar - '0'; // result = 1
          }
         
          Serial.println(result);
          Serial.println(serchar);
          
        }
        analogWrite(red1, result);
        analogWrite(green1, result);
        analogWrite(blue1, result);
        
}
if(Serial.available())

How often, without delays, do you think that is going to return more than one?

That's because you're trying to read all the serial chars at once.
But Arduino is wayyyy too fast for that!

Let loop() go round and round and only read 1 char at a time as available.
In between serial chars arriving, let loop() keep running so that other tasks may run in the time between.

If you study the State Machine example in that blog I linked, you should see that his example could be turned into R, G or B with a number to change the led RGB values instead of his RPM, Speed, Gear commands.

What Nick did not include there is error handling but that's a bit of work that would just confuse beginners.

AWOL:

if(Serial.available())

How often, without delays, do you think that is going to return more than one?

Indeed you're right I have it >0 in my code, erased it in my nightly stupidity. I set a delay of 100 , still returning it 3 times.

GoForSmoke:
That's because you're trying to read all the serial chars at once.
But Arduino is wayyyy too fast for that!

Let loop() go round and round and only read 1 char at a time as available.
In between serial chars arriving, let loop() keep running so that other tasks may run in the time between.

If you study the State Machine example in that blog I linked, you should see that his example could be turned into R, G or B with a number to change the led RGB values instead of his RPM, Speed, Gear commands.

What Nick did not include there is error handling but that's a bit of work that would just confuse beginners.

Okay. I will definitely take a closer look to that. I also figured if it's possible to send, since extended ASCII consists of 255 chars, instead of an integer just one single char converted as a string and then read it and directly convert it to a number again. Sadly at this conversion point it throws me obscure numbers where it normally should give me the specific decimal value of the char. If that worked I could easily set the value since it's 0-255 in one step. Wouldn't work for other stuff than this though...

I'm not trying to hijack this thread, but I'm having a similar issue. I am able to create a string from a char array collected by serial. The array looks like;

char masterMessage = { 'A' , 'F', '1', ' -', '4', '5', ',', '7', '8', ',', '#'}

and the string TempBuffer is:

AF1-45,78,#

this is the function I am using to decode the message:

void translateMessage()
{
  if (masterMessage[0] == 'A' || masterMessage[0] == 'B' || masterMessage[0] == 'C' || masterMessage[0] == 'D' || masterMessage[0] == 'E' || masterMessage[0] == 'F'){
    IsWeather = true;
  }
  else{
    IsWeather = false;
  }
  if (masterMessage[1] == 'F'){
   IsFarhenheit = true;
  }
  else{
    IsFarhenheit = false;
  }
  if (masterMessage[3] == '1'){
    IsMailMessage = true;
  }
  else{
    IsMailMessage = false;
  } 
  for (int i=0;i<14;i=i++){
    if (masterMessage[i] == '#'){break;}
    messageString = (messageString + masterMessage[i]);
  }
  Serial.println(messageString);
  int firstEnd = messageString.indexOf(",");
  String TempBuffer = (messageString.substring(3,firstEnd));
  Serial.println("Outdoor Temp="+ TempBuffer);
  messageString = "";
}

I want to:
atoi(TempBuffer)
but cannot. I have searched how to convert a char string to integer, but I cannot make it happen.

Sure you can write bytes. A char is 1 byte, int is 2 bytes, a long is 4, etc.
You break the variable down to bytes and send them across, read and reassemble in the Arduino and for good measure do a CRC to be sure the data did not get corrupted.
Just get the byte order right which is easy with an experiment. The order in the PC may not be the order in an UNO.

CRC: bytes are unsigned integers. If you subtract every new byte from the last the answer will always be a byte. At the end you have a value. So you do a CRC at the PC end then send the result byte to the Arduino after the bytes of the number. Arduino runs the CRC subtractions and compares the result to the CRC byte from the PC. If they match, okay, if they don't then error which your code should handle by code at both ends being ready to signal "ERR" from Arduino and PC resend the number and CRC.
Even with the CRC it will be quicker and more correct (very small chance that bad gets through!) than text. Downside it that bytes are not as easy for humans to read as text.

BulldogLowell:
I'm not trying to hijack this thread, but I'm having a similar issue. I am able to create a string from a char array collected by serial. The array looks like;

char masterMessage = { "AF1-45,78,#" }; // fixed, now it has a terminating zero and is clear to read

and the string TempBuffer is:

AF1-45,78,#

  if (masterMessage[0] >= 'A' && masterMessage[0] <= 'F'){

I want to:
atoi(TempBuffer)

"AF1-45,78,#"
atoi sees the A and stops, returning 0.

Your code can get those 2 values out in a number of ways.
With the state machine you can read until "-" then evaluate digits until ',' and again until ','.
Or you can pull the digits out by position (IF they will Always Be The Same Number of Digits, Same Place) into a buffer, tack on a terminating zero unless the buffer was filled with 0's (use memset) and atoi(buffer) each time.
Or you can learn to use strtok() to tokenize TempBuffer which means learning pointers and strtok and then you can atoi(pointer) for each value.
Or.... well there's always another way!