How to extract a subarray and convert it into float?

Hello everyone, I'm new in the world of electronics, but for a university project I have to work with Arduino and a CO2 sensor.
The following code allows me to send a command to the sensor, and to receive back the CO2 concentration.

void loop() {

  int i=0;
  char measure[13];

Serial1.write("send\r");
  delay(100);
  while (Serial1.available()>0) {
    measure[i]=Serial1.read();
    i++;
  }
  Serial.println(measure);

  delay(2000);

}

The response of the sensor is:

send
  731.8

My question is: how can I extract the number "731.8" from the array, and transform it into a float?
Thank's to anyone who can help me!

Welcome to the forum

The first thing to do is to add a '\0' immediately after the characters received to turn the array into a C style string (NOTE - not a String, capital S), then use the aftof() function to convert it to a float as in this example

void setup()
{
  Serial.begin(115200);
  char measure[13];
  measure[0] = '7';
  measure[1] = '3';
  measure[2] = '1';
  measure[3] = '.';
  measure[4] = '8';
  measure[4] = '\0';  //terminate the string
  float aFloat = atof(measure);
  Serial.println(aFloat);
  Serial.println(aFloat * 10);  //prove it is a real float
}

void loop()
{
}

Thank you for your replay!
And how could I extract the numeric part from the initial string that i receive from the sensor?

consider reading an entire line

char buf [80];

void
loop (void)
{
    if (Serial.available())  {
        int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
        buf [n] = '\0';

        Serial.println (atof (buf));
    }
}

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

Your codes of post #1 is adjusted below that may answer to your question:

 int i=0;
 char measure[13] = {0};  //all locations contains 0

void setup()
{
    Serial.begin(9600);
   //put other codes as needed
}

void loop() 
{
  Serial1.write("send\r");
  delay(100);
  while (Serial1.available()>0) 
  {
      measure[i]=Serial1.read();
      i++;
  }
  //Serial.println(measure);
  float conCO2 = atof(measure); //converting five bytes ASCII coded data into float
  Serial.println(conCO2, 1);    //1-digit after decimal point
  memset(measure, 0, 13);  //resetting the array to 0s
  i = 0;
  delay(2000);
}

You mean:

atof()

Does atof() function require a null-character terminated ASCII array (the cstring) for conversion?

Does sensor send Newline terminated frame? It sends only 5 five bytes ASCII coded data items as said in post #1.

doesn't there need to be something that terminates the ASCII sequence. what if you don't start reading when the 1st character is transmitted.

if the data is repeatedly sent would it be "731.8731.87..."?

@leobeltra is being requested to post the UART Protocol of his CO2 sensor.

The sensor sends data items after receiving "Send\r" command from the Host -- this event can be seen as a preamble and then Host should read only 5 bytes.

I tried your codes, this one of GolamMostafa functions a little bit: it returns "0.0" to each measure.
So I still don't get the result that i would, but at least it's able to select only the numeric part of the array!

After receiving the command "send\r", the sensor responds replaying the command itself+NL+co2 concentration+CR+NL

Indeed I do, as in my example sketch

Yes, otherwise the length of the string cannot be known

1 Like

It would have been nice to know that earlier

void setup()
{
  Serial.begin(115200);
  char received[] = {"send\r731.8\r\n"};
  Serial.println(received);
  char measure[13];
  strcpy(measure, received + 5);
  Serial.println(measure);
  float aFloat = atof(measure);
  Serial.println(aFloat);
  Serial.println(aFloat * 10);  //prove it is a real float
}

void loop()
{
}
1 Like

:wink:

Sorry you are right, anyway thanks to all those who answered my questions, now I've resolved my problem :+1:

I share another possible solution I found:

void setup() {
 
  Serial.begin(19200);
  int i=0;
  char received[13]={0};
  Serial1.write("send\r");
  delay(100);
  while (Serial1.available()>0) {
    received[i]=Serial1.read();
    i++;
  }
  
  char* initialpart = strtok(received, "\n");
  char* measure = strtok(NULL, "\r");
  Serial.println(measure);
  float co2 = atof(measure);
  Serial.println(co2, 1);
  Serial.println(co2*10, 1);
  
}
void loop(){}
  • why do you process "received regardless of whether something has been received?
  • what prevents overwriting "received", it's only 13 bytes?
  • what char terminates the received data and is the condition for processing "received"?
  1. Do you mean that I should check if the the while cycle has been filled array?
  2. I know the length of what I receive, because it's always the same thing:
    "send"+NL+"CO2conc"+CR+NL. So these are always 12 bytes.
  3. You're right, I forgot to add the terminal character of the array, that would become the 13th byte
    of the array.

You need to think about the speed of character reception on Serial1. Post a complete code, and I'll say more. What we presently have doesn't even set the baud rate for Serial1, nor "begin" the stream, so I know you've not given us the whole story. What you perceive as a solution is therefore opaque to us, denying you the benefit of this forums extensive understanding of both Serial, and the broader context of Arduino.

is there any point in processing an incomplete string? (and where is "i" reset to zero for the next string)?

in the code i posted above (copied below), readByteUntil() doesn't return until the termination char (\n) is received or there is a timeout and only after the entire string is received is it processed (the simple print after calling atof()).

@gcjr You are also guarding against overrunning the buffer endpoint, which is ignored in the OP's post. That's important, because if the sender either omits the line end, or the serial transmission is garbled by noise, the receiver has no way of knowing. Assuming perfect transmission in serial matters is always a recipe for failure.

void setup() {
  Serial.begin(19200);   // serial monitor
  Serial1.begin(19200);   // serial co2 sensor
  while(!Serial);
  while(!Serial1);
}

void loop() {
  int i=0;
  char received[13]={0};
  Serial1.write("send\r");  // ask to sensor for a co2 measure
  delay(100);
  while (Serial1.available()>0) {  // read the response by the sensor
    received[i]=Serial1.read();
    i++;
  }
  char* initialpart = strtok(received, " ");  // discard the echo
  char* measure = strtok(NULL, "\r"); // keep only the c02 concentration
  Serial.println(measure);
  float co2 = atof(measure);
  Serial.println(co2, 1);
  
  delay(2000);
}