convertir-texto-a-numero-arduino

Methods for converting text to number in Arduino

  • 6 min

In this post, we are going to see how to convert a text string to a number, either integer or float, in a microprocessor like Arduino.

This is a common request we see on websites and forums, and sometimes there is confusion because there is more than one way to perform the conversion, each with its advantages and disadvantages.

In this post, we will see the main ways to convert a string to an integer or float number, and when it is convenient to use one or the other.

The DEBUG functions are only for visualizing the results. If you use these codes, you can remove the parts related to their definition and use.

Conversion with the String Class

The first option we are going to see is using the String class, which as we know is a wrapper around a dynamic char array included in Arduino libraries.

The String class has the functions toInt() and toFloat() that convert, respectively, the text string to an integer or float number.

Thus, the following code shows the conversion from String to Int,

#define DEBUG(a) Serial.println(a);

String text = "-12345";

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

  long value;
  value = text.toInt();
  DEBUG(value);
}

void loop()
{
}
Copied!

While the conversion from String to Float is as follows,

#define DEBUG(a) Serial.println(a);

String text = "-123.45";

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

  float value;
  value = text.toFloat();
  DEBUG(value);
}

void loop()
{
}
Copied!

Conversion via the String class is the recommended option whenever we don’t have a compelling reason not to use it. It is easy to use, efficient, and the String library is lightweight enough not to penalize its use.

Its main disadvantage is the lack of control over the process. For example, if the string contains invalid characters, the result may be unexpected (and generally incorrect).

Although in most cases this is not a problem, if we have to deal with these situations, we might prefer to perform the conversion “by hand” (see the Naive method below).

Conversion with char array

If for some reason we cannot or do not want to use the String class, another option is to perform the conversion directly from a char array.

For this, we have the functions atol and atof that convert a char array, respectively, to an integer or floating-point number.

The example for integers is as follows,

#define DEBUG(a) Serial.println(a);

char* text = "-12345";

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

  long value;
  value = atol(text);
  DEBUG(value);
}

void loop()
{
}
Copied!

Which in the case of floating-point numbers looks like this,

#define DEBUG(a) Serial.println(a);

char* text= "-123.45";

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

  long value;
  value = atof(text);
  DEBUG(value);
}

void loop()
{
}
Copied!

The efficiency and behavior are similar to those obtained using the String class because, internally, the String class uses the atol and atof functions to perform the conversion.

In this case, we have the disadvantage of having to work with char arrays, which, except in very specific cases, will usually be more cumbersome than using the String class.

Therefore, except in rare exceptions, we will normally prefer the functions seen earlier in the String class.

Conversion with the Naive Method

The last case we are going to see is the so-called “naive method,” which is nothing more than a sophisticated way of saying “doing it by hand.”

The following example shows the conversion process for integers, where we process a char array until we find a character that is not a digit between 0 and 9. We have previously checked if it is a negative number.

#define DEBUG(a) Serial.println(a);

char *text = "-12345";

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

  long value;
  value = naiveToInt(text);
  DEBUG(value);
}

void loop()
{
}

long naiveToInt(const char *charArray) {
  long data = 0;
  bool isNegative = false;
  if (*charArray == '-') 
  {
    isNegative = true;
    ++charArray;
  }

  while (*charArray >= '0' && *charArray <= '9')
  {
    data = (data * 10) + (*charArray - '0');
    ++charArray;
  }

  return isNegative ? -data : data;
}
Copied!

The case for a floating-point number is a bit more complicated because, in addition to detecting the negative sign, we must detect the decimal separator (in the example ’.’ or ’,’). Thus, the conversion is performed in two stages, a first one for the integer part before detecting the separator, and a second one for the integer part after detecting the separator.

#define DEBUG(a) Serial.println(a);

char *text = "-123.45";

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

  float value;
  value = naiveToFloat(text);
  DEBUG(value);
}

void loop()
{
}

float naiveToFloat(const char *charArray) 
{
  long dataReal = 0;
  long dataDecimal = 0;
  long dataPow = 1;
  bool isNegative = false;

  if (*charArray == '-')
  {
    isNegative = true;
    ++charArray;
  }

  while ((*charArray >= '0' && *charArray <= '9'))
  {
    dataReal = (dataReal * 10) + (*charArray - '0');
    ++charArray;
  }

  if (*charArray == '.' || *charArray == ',')
  {
    ++charArray;
    while ((*charArray >= '0' && *charArray <= '9'))
    {
      dataDecimal = (dataDecimal * 10) + (*charArray - '0');
      dataPow *= 10;
      ++charArray;
    }
  }

  float data = (float)dataReal + (float)dataDecimal / dataPow;
  return isNegative ? -data : data;
}
Copied!

The performance of the process is similar to the atol and atof functions and, by extension, to the functions of the String classes. This is because this implementation is similar to the one used internally by the atol and atof functions.

The biggest disadvantage is, logically, having to add the code instead of using it conveniently from existing functions. However, the ease of use is similar.

But in this case, we have the advantage of controlling the entire process. As an example, in the code we have made it accept ’.’ and ’,’ as decimal separators, something we cannot do with standard processes.

We can easily modify the code to have other types of behavior, such as reacting differently to certain characters, processing a comma-separated file, etc.

Therefore, we will use this method mainly when we have special constraints that prevent us from using the standard functions, and we need to customize the conversion process.

Download the Code

All the code from this post is available for download on Github. github-full