Using atoi() for bytes and booleans?

Hello,

I am using the Serial Input Basics; Example 5 (the GOAT of Arduino tutorials) ; Serial Input Basics - updated - #3 by Robin2 to parse out numerous variables from Serial.

That is, putting the serial data into a char array and parsing out variables.

Along with integers, floats and char arrays presented in the examples, I also want to be able to parse out bytes and booleans.

Although the atoi() function says it's used for int's, it seems perfectly happy to be used to parse out bytes and booleans (booleans being "1" (or higher) for "true" and "0" for "false"). Here is the example below;

// Example 5 - Receive with start- and end-markers combined with parsing

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;
byte bytefromPC = 0;
boolean booleanfromPc = 0;

boolean newData = false;



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

void setup() {
    Serial.begin(9600);
    Serial.println("This demo expects 5 pieces of data - text, an integer and a floating point value + a byte and boolean");
    Serial.println("Enter data in this style <HelloWorld, 12, 24.7, 20, 1>  ");
    Serial.println();
}

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

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

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

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

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.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() {    

    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
    integerFromPC = (atoi(strtokIndx));     // convert this part to an int

    strtokIndx = strtok(NULL, ",");
    floatFromPC = (atof(strtokIndx));     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    bytefromPC = (atoi(strtokIndx));  //converts this part to byte 
     
    strtokIndx = strtok(NULL, ",");   
    booleanfromPc = (atoi(strtokIndx));   //converts this part to boolean
        
}

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

void showParsedData() {
    Serial.print("Message ");
    Serial.println(messageFromPC);
    Serial.print("Integer ");
    Serial.println(integerFromPC);
    Serial.print("Float ");
    Serial.println(floatFromPC);
    Serial.print("byte ");
    Serial.println(bytefromPC);    
    Serial.print("boolean ");
    Serial.println(booleanfromPc);     
}

Is it safe to use atoi() in this way even though it's supposed to be for int's?

Or should I use the byte() function byte() - Arduino Reference for both byte and boolean conversions like this?

void parseData() {    
    
    //char * to byte conversion
    strtokIndx = strtok(NULL, ",");    
    bytefromPC = byte(atoi(strtokIndx));

   //char * to boolean conversion
    strtokIndx = strtok(NULL, ",");    
    byte byteToBoolean;
    byteToBoolean = byte(atoi(strtokIndx));

    if(byteToBoolean == 0){
      booleanfromPc = 0;
    }
    else{
     booleanfromPc = 1; 
    }
 }

Thank you!!!

A byte IS an integer, and even a bool is an integer (that can be only 0 or 1), so you can simply use atoi() without messing with unneeded istructions.

1 Like

You seem to be confusing an int variable with a value that is an integer. In int is an integer but an integer, such as a byte or boolean is not an int

1 Like

thanks for clarifying, I have edited the post. So does that mean the atoi() function can be used for all "integer" variables (int's, boolean, byte etc. )?

cheers

function int atoi (const char * str) return an int type.
Size of int type depends from your micro (or OS) but usually it's 16 bit long (2 bytes).

So you can use atoi() with byte, but you have to take care about the size of integer otherwise result doesn't match with wath you expect.

With something like this for example, you will get num == 4 because is the low byte of int resulting from atoi().

260 == 0b00000001 00001000 == [0x01] [0x04]

char* number = "260";
byte num = 0;

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

  num = atoi(number);
  Serial.println(num);
}
1 Like

1. atoi() stands for ASCII To (decimal) Integral (whole number and no fractional).

2. Meaning of atoi()
If there is a char-type array (string) where the characters are numerals (range: 0 - 9) and are coded in their ASCII values (Fig-1 under Step-4), then the function atoi() will convert the array into "decimal integral" value. The result will be saved in an int-type variable. (An int-type variable can hold value of this range: -32768 to 32767 (0x8000 to 0x7FFF.)

3. Example:
(1) Given the following array containing ASCII values for the digits of this decimal number: 1234.

char myNum[] = "1234";    //last element is an invisible null-charcater (0 = '\0')
==> char myNum[] = {'1', '2', '3', '4', '\0'};   //this representation requires null-charcater 
==> char myNum[] ={0x31, 0x32, 0x33, 0x34, 0x00};  //actual representation in memory

int x = atoi(myNum);    //x is an int-type (16-bit) variable and can hold: -32768 to 32767
Serial.print(x, DEC); //Serail Monitor shows: 1234

4. ASCII Table


Figure-1:

5. Example Sketch

char myNum[20] = "";

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

void loop()
{
  while (Serial.available() > 0)
  {
    byte m = Serial.readBytesUntil('\n', myNum, 20);
    int x = atoi(myNum);
    Serial.println(x, DEC);   //shows decimal value of charcaters coming from Serial Monitor
  }
}
1 Like

Thank you for all your detailed answers. My application is basically to send numerous variables from 1 arduino to another arduino (bidirectionally) using Robin2's example.

I'm assuming parsing out booleans and bytes for some basic instructions (e.g. turning something on or off) would be better than using more int type variables, as ints occupy more space.

Data exchange between two Arduinos could be done using one of the following serial communication links:
UART Port
I2C Bus
SPI Port

In UART Port based communication, data bytes are usually exchanged in ASCII format. That means that the number 1234 would be sent from the Transmitter as 0x31, 0x32, 0x33, and 0x34 which are the ASCII codes for the digits 1, 2, 3, and 4 respectively. To accomplish this task, the following simle instruction is used:

Serial.print("1234");

At the Receiver side, the received ASCII codes have to be processed using atoi() function to retrive the original 1234 number.

However, if desired, someone can send 1234 in binary format. The required instructions are:

int x = 1234;  //in memory data is saved in binary as (0000 0100 1101 0010 = 0x04D2)
Serial.write(lowByte(x));  //D2 (11010010) would be sent to Receiver
Serial.write(highByte(x));  //04 (00000100) would be sent to Receiver

At the Receiver side, we have to process/combine the received two-byte data to form the original single data item of 04D2 in hex (1234 in decimal). The codes are:

byte lowByte;   //will hold D2
byte highByte;  //will hold 04

int x = highByte << 8;   //04 ==> 0400
x = x|lowByte;                // x = 0400 + 00D4 = 04D2

From the above analysis/example, it is clear the reason for choosing ASCII format instead of binary format for exchnaging data over UART Port.

1 Like

Unless I'm mistaken, I don't think my reply was referring to sending binary data, but thank you for the info anyway!

I just meant that, for example; you wanted Arduino A to tell Arduino B to turn an LED on via UART (using serial.print) , it would make more sense for Arduino B to parse the message into a 1 byte boolean or byte from arduino A, rather than a 2 byte int, correct?

that being said, a few Arduino examples for beginners (e.g. BlinkWithoutDelay) use 2 byte int's to change an LED state for some reason.

Is that what you are doing? Then there is no need to use atoi() or any similar functions. They are only required when communicating between human and Arduino. Between two Ardunino, just send the data in binary to keep things simple.

No, it's more involved than that. I am also sending char arrays, as well as int's and bytes.

So the data will be directly read by humans. OK.

In UART communication, the Arduino A has no choice but to send at least 8-bit data (1-byte) to Arduino B, which could be binary or ASCII formatted. UART is a byte oriented protocol.

To instruct Arduino B to turn on a LED, Arduino A will send 01 (00000001). There is no point for Arduino A to send 0001 (0000000000000001).

1 Like

int-type data is broken into byte-type data and are then sent to destination over the UART Port.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.