1

I am writing a program to read from the Atlas Scientific EZO-HUM, -O2, and -CO2 sensors simultaneously via the I2C protocol with an Arduino Uno. The sensors all work, but for some reason, just the O2 sensor data does not convert to ASCII text. Below is my program:

#include <Ezo_i2c.h>
#include <Ezo_i2c_util.h>
#include <iot_cmd.h>
#include <sequencer1.h>
#include <sequencer2.h>
#include <sequencer3.h>
#include <sequencer4.h>
#include <Wire.h>                //enable I2C.


#define HUM_address 111          //default I2C ID number for EZO Humidity sensor.
#define O2_address 108           //default I2C ID number for EZO O2 sensor.
#define CO2_address 105          //default I2C ID number for EZO CO2 sensor.



//EZO-HUM vars 
//   | |
//   V V
char computerdata[32];           //we make a 32 byte character array to hold incoming data from a pc/mac/other.
byte received_from_computer = 0; //we need to know how many characters have been received.
byte serial_event = false;       //a flag to signal when data has been received from the pc/mac/other.
byte code = 0;                   //used to hold the I2C response code.
char Humidity_data[22];          //we make a 22-byte character array to hold incoming data from the Humidity sensor.
byte in_char = 0;                //used as a 1 byte buffer to store inbound bytes from the Humidity  sensor.
byte i = 0;                      //counter used for Humidity_data array.
int time_ = 1000;                 //used to set the delay needed to process the command sent to the EZO Humidity sensor.

//EZO-CO2 vars 
//   | |
//   V V
//char CO2_computerdata[20];           //we make a 20 byte character array to hold incoming data from a pc/mac/other.
byte CO2_received_from_computer = 0; //we need to know how many characters have been received.
byte CO2_serial_event = false;       //a flag to signal when data has been received from the pc/mac/other.
byte CO2_code = 0;                   //used to hold the I2C response code.
char CO2_data[20];               //we make a 20-byte character array to hold incoming data from the Co2 sensor.
byte CO2_in_char = 0;                //used as a 1 byte buffer to store inbound bytes from the Co2 sensor.
byte CO2_i = 0;                      //counter used for Co2_data array.
//int CO2_time_ = 1000;                 //used to set the delay needed to process the command sent to the EZO Co2 sensor.
int Co2_int;                     //int var used to hold the value of the Co2.

//EZO-O2 vars 
//   | |
//   V V
//char O2_computerdata[20];           //we make a 20 byte character array to hold incoming data from a pc/mac/other.
byte O2_received_from_computer = 0; //we need to know how many characters have been received.
byte O2_serial_event = false;       //a flag to signal when data has been received from the pc/mac/other.
byte O2_code = 0;                   //used to hold the I2C response code.
char O2_data[20];                //we make a 20-byte character array to hold incoming data from the o2 sensor.
byte O2_in_char = 0;                //used as a 1 byte buffer to store inbound bytes from the o2 sensor.
byte O2_i = 0;                      //counter used for o2_data array.
//int O2_time_ = 600;                 //used to set the delay needed to process the command sent to the EZO o2 sensor.

char *HUM;                       //char pointer used in string parsing.
char *TMP;                       //char pointer used in string parsing.
char *NUL;                       //char pointer used in string parsing (the sensor outputs some text that we don't need).
char *DEW;                       //char pointer used in string parsing.
char *O2_reading;
char *O2_reading_2;

float HUM_float;                 //float var used to hold the float value of the humidity.
float TMP_float;                 //float var used to hold the float value of the temperatur.
float DEW_float;                 //float var used to hold the float value of the dew point.
float O2_float;
float CO2Con_float;



void setup()                    //hardware initialization.
{
  Serial.begin(9600);           //enable serial port.
  Wire.begin();                 //enable I2C port.
  while(!Serial);            //wait for serial monitor to be open
}


void serialEvent() {                                                              //this interrupt will trigger when the data coming from the serial monitor(pc/mac/other) is received.
  received_from_computer = Serial.readBytesUntil(13, computerdata, 22);           //we read the data sent from the serial monitor(pc/mac/other) until we see a <CR>. We also count how many characters have been received.
  computerdata[received_from_computer] = 0;                                       //stop the buffer from transmitting leftovers or garbage.
  serial_event = true;                                                            //set the serial event flag.
}


void loop() {                                                                     //the main loop.
  if (serial_event == true) {                                                     //if a command was sent to the EZO device.
    for (i = 0; i <= received_from_computer; i++) {                               //set all char to lower case, this is just so this exact sample code can recognize the "sleep" command.
      computerdata[i] = tolower(computerdata[i]);                                 //"Sleep" ≠ "sleep"
    }
    i=0;                                                                          //reset i, we will need it later 
   
 //---------------------------------------------------------EZO-HUM Sensor-----------------------------------------------------------------------------//   
    Wire.beginTransmission(HUM_address);                                              //call the circuit by its ID number.
    Wire.write(computerdata);                                                     //transmit the command that was sent through the serial port.
    Wire.endTransmission();                                                       //end the I2C data transmission.

    

// Need to talk to each sensor separately. Because they're all Atlas Scientific EZO sensors, they all respond to the same commands
 
    if (strcmp(computerdata, "sleep") != 0) {                                     //if the command that has been sent is NOT the sleep command, wait the correct amount of time and request data.
                                                                                  //if it is the sleep command, we do nothing. Issuing a sleep command and then requesting data will wake the Humidity  sensor.

      delay(time_);                                                               //wait the correct amount of time for the circuit to complete its instruction. 
       
      Wire.requestFrom(HUM_address, 22, 1);                                           //call the circuit and request 22 bytes.
      code = Wire.read();                                                         //the first byte is the response code, we read this separately.

      switch (code) {                       //switch case based on what the response code is.
        case 1:                             //decimal 1.
          Serial.println("HUM Success");        //means the command was successful.
          break;                            //exits the switch case.

        case 2:                             //decimal 2.
          Serial.println("HUM Failed");         //means the command has failed.
          break;                            //exits the switch case.

        case 254:                           //decimal 254.
          Serial.println("HUM Pending");        //means the command has not yet been finished calculating.
          break;                            //exits the switch case.

        case 255:                           //decimal 255.
          Serial.println("HUM No Data");        //means there is no further data to send.
          break;                            //exits the switch case.
    }



    while (Wire.available()) {              //are there bytes to receive.
      in_char = Wire.read();                //receive a byte.
      Humidity_data[i] = in_char;           //load this byte into our array.
      //Serial.println((int)in_char);
      i += 1;                               //incur the counter for the array element.
      if (in_char == 0) {                   //if we see that we have been sent a null command.
        i = 0;                              //reset the counter i to 0.
        break;                              //exit the while loop.
      }
    }
    if (computerdata[0] == 'r') string_pars();    //uncomment this function if you would like to break up the comma separated string into its individual parts.
  }

 //---------------------------------------------------------EZO-O2 Sensor-----------------------------------------------------------------------------// 
  
    Wire.beginTransmission(O2_address);                                           //call the circuit by its ID number.
    Wire.write(computerdata);                                                     //transmit the command that was sent through the serial port.
    Wire.endTransmission();                                                       //end the I2C data transmission.
    
    if (strcmp(computerdata, "sleep") != 0) {                                     //if the command that has been sent is NOT the sleep command, wait the correct amount of time and request data.
                                                                                  //if it is the sleep command, we do nothing. Issuing a sleep command and then requesting data will wake the Humidity  sensor.

      delay(time_);                                                               //wait the correct amount of time for the circuit to complete its instruction. 
       
      Wire.requestFrom(O2_address, 22, 1);                                           //call the circuit and request 22 bytes.
      O2_code = Wire.read();                                                         //the first byte is the response code, we read this separately.

      switch (O2_code) {                       //switch case based on what the response code is.
        case 1:                             //decimal 1.
          Serial.println("O2 Sensor Success");        //means the command was successful.
          break;                            //exits the switch case.

        case 2:                             //decimal 2.
          Serial.println("O2 Sensor Failed");         //means the command has failed.
          break;                            //exits the switch case.

        case 254:                           //decimal 254.
          Serial.println("O2 Sensor Pending");        //means the command has not yet been finished calculating.
          break;                            //exits the switch case.

        case 255:                           //decimal 255.
          Serial.println("O2 Sensor No Data");        //means there is no further data to send.
          break;                            //exits the switch case.
    }



    while (Wire.available()) {              //are there bytes to receive.
      O2_in_char = Wire.read();                //receive a byte.
      O2_data[i] = O2_in_char;           //load this byte into our array.
      Serial.println((int)O2_in_char);
      Serial.println(O2_data);
      i += 1;                               //incur the counter for the array element.
      if (O2_in_char == 0) {                   //if we see that we have been sent a null command.
        i = 0;                              //reset the counter i to 0.
        break;                              //exit the while loop.
      }
    }
//    Serial.print("O2 Concentration:");                      //This code doesn't output any information, although the program receives bytes which display in the while loop.
//    Serial.println(O2_data);
//    Serial.println();

    if (computerdata[0] == 'r') O2_string_pars();             //This code also doesn't output any information.
  }
  
 //---------------------------------------------------------EZO-CO2 Sensor-----------------------------------------------------------------------------//  
 
    Wire.beginTransmission(CO2_address);                                          //call the circuit by its ID number.
    Wire.write(computerdata);                                                     //transmit the command that was sent through the serial port.
    Wire.endTransmission();                                                       //end the I2C data transmission.
    
    if (strcmp(computerdata, "sleep") != 0) {                                     //if the command that has been sent is NOT the sleep command, wait the correct amount of time and request data.
                                                                                  //if it is the sleep command, we do nothing. Issuing a sleep command and then requesting data will wake the Humidity  sensor.

      delay(time_);                                                               //wait the correct amount of time for the circuit to complete its instruction. 
       
      Wire.requestFrom(CO2_address, 22, 1);                                           //call the circuit and request 22 bytes.
      CO2_code = Wire.read();                                                         //the first byte is the response code, we read this separately.

      switch (CO2_code) {                       //switch case based on what the response code is.
        case 1:                             //decimal 1.
          Serial.println("CO2 Sensor Success");        //means the command was successful.
          break;                            //exits the switch case.

        case 2:                             //decimal 2.
          Serial.println("CO2 Sensor Failed");         //means the command has failed.
          break;                            //exits the switch case.

        case 254:                           //decimal 254.
          Serial.println("CO2 Sensor Pending");        //means the command has not yet been finished calculating.
          break;                            //exits the switch case.

        case 255:                           //decimal 255.
          Serial.println("CO2 Sensor No Data");        //means there is no further data to send.
          break;                            //exits the switch case.
    }



    while (Wire.available()) {              //are there bytes to receive.
      CO2_in_char = Wire.read();                //receive a byte.
      CO2_data[i] = CO2_in_char;           //load this byte into our array.
      //Serial.println((int)CO2_in_char);
      i += 1;                               //incur the counter for the array element.
      if (CO2_in_char == 0) {                   //if we see that we have been sent a null command.
        i = 0;                              //reset the counter i to 0.
        break;                              //exit the while loop.
      }
    }  
    Serial.print("CO2 Concentration:");                      
    Serial.println(CO2_data);                       
  }

  serial_event = false;                     //reset the serial event flag

//  if (computerdata[0] == 'r') string_pars();    //uncomment this function if you would like to break up the comma separated string into its individual parts.
}
   }
  
void string_pars() {                        //this function will break up the CSV string into its 3 individual parts. HUM|TMP|DEW.
                                            //this is done using the C command “strtok”.

  HUM = strtok(Humidity_data, ",");         //let's pars the string at each comma.
  TMP = strtok(NULL, ",");                  //let's pars the string at each comma.
  NUL = strtok(NULL, ",");                  //let's pars the string at each comma (the sensor outputs the word "DEW" in the string, we dont need it.
  DEW = strtok(NULL, ",");                  //let's pars the string at each comma.

  Serial.println();                          //this just makes the output easier to read by adding an extra blank line. 
 
  Serial.print("HUM:");                      //we now print each value we parsed separately.
  Serial.println(HUM);                       //this is the humidity value.

  Serial.print("Air TMP:");                  //we now print each value we parsed separately.
  Serial.println(TMP);                       //this is the air temperatur value.

  Serial.print("DEW:");                      //we now print each value we parsed separately.
  Serial.println(DEW);                       //this is the dew point.
  Serial.println();




  
  //uncomment this section if you want to take the values and convert them into floating point number.
  /*
    HUM_float=atof(HUM);
    TMP_float=atof(TMP);
    DEW_float=atof(DEW);
  */
}  

void O2_string_pars() {                        //this function will break up the CSV string
                                            //this is done using the C command “strtok”.

  O2_reading = strtok(O2_data, ",");         //let's pars the string at each comma.
//  O2_reading_2 = strtok(NULL, ",");

  Serial.println();                          //this just makes the output easier to read by adding an extra blank line. 
 
  Serial.print("O2 Concentration: ");                   
  Serial.println(O2_reading);
//  Serial.println("O2 extra info: ");
//  Serial.print(O2_reading_2);                       




  

}

The following is the output from the program:

HUM Success

HUM:45.39

Air TMP:23.61

DEW:11.16

O2 Sensor Success

50

48

46

56

53

0

O2 Concentration:

CO2 Sensor Success

CO2 Concentration:599

7
  • Because in your code you are specifically printing the integers?
    – Majenko
    Jun 10, 2022 at 18:34
  • If you read the program, I am printing the array containing the bytes in the line below the command to print the individual bytes as they are entered into O2_data. These prints output blank lines. I tried replicating the EZO-HUM's string_pars() function for the EZO-O2's outputs, which also outputs blanks. I don't have this issue with either of the other two sensors.
    – czar1249
    Jun 10, 2022 at 18:41
  • What is i at the start of your receiving loop?
    – Majenko
    Jun 10, 2022 at 18:56
  • If you mean at the start of the "EZO-O2 Sensor" section, it has been reset to 0 after receiving a NULL command from the EZO-HUM sensor at the end of that sensor's respective section. At least, that's how I'm reading it.
    – czar1249
    Jun 10, 2022 at 19:12
  • 1
    Are you sure of that? Print what i is to make certain.
    – Majenko
    Jun 10, 2022 at 19:13

1 Answer 1

2

You are relying on a NULL byte being received to reset your i pointer variable. If that NULL never arrives for whatever reason you won't be writing your new data to the start of your next array.

You should always reset the counter before receiving new data regardless of what you have just received.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.