CO2-sensor with mega2560

Hi Guys,

I am working on a relatively simple setup. I have an funduino mega 2560 board and an SprintIR-WX-5 CO2-Sensor from CO2meter.com. They also provide a .pdf with wiring and a code for this configuration.
http://www.co2meters.com/Documentation/AppNotes/AN128-%20Cozir_Arduino.pdf

/*
 Cozir Sample code
 Written by: Jason Berger ( for Co2meter.com)

 This sketch connects will connect to a Cozir gss or SprintIR sensor
 and report readings back to the host computer over usb. The value is
 stored in a global variable 'co2' and can be used for any number of applications.

 pin connections:

 Arduino________Cozir Sensor
 GND ------------------ 1 (gnd)
 3.3v------------------- 3 (Vcc)
 10 -------------------- 5 (Rx)
 11 -------------------- 7 (Tx)
 */
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
String val= ""; //holds the string of the value
double co2 =0; // holds the actual value
double multiplier = 10; //each range of sensor has a different value.
 // up to 2% =1
 // up to 65% = 10
 //up to 100% = 100;
uint8_t buffer[25];
uint8_t ind =0;
void setup()
{
 Serial.begin(9600); //Start Serial connection with host
 Serial.println("Co2Meter.com Cozir Sample"); 
  mySerial.begin(9600); //Start Serial connection with Sensor

}
void loop()
{
 //Cozir sensors ship from the factory in streaming mode
 //So we read incoming bytes into a buffer until we get '0x0A' which is the ASCII value for new-line
 while(buffer[ind-1] != 0x0A)
 {
 if(mySerial.available())
 {
 buffer[ind] = mySerial.read();
 ind++;
 }
 }

 report(); //Once we get the '0x0A' we will report what is in the buffer
}
void report()
{
 //Cycle through the buffer and send out each byte including the final linefeed

 /*
 each packet in the stream looks like "Z 00400 z 00360"
 'Z' lets us know its a co2 reading. the first number is the filtered value
 and the number after the 'z' is the raw value.
 We are really only interested in the filtered value

 */

 for(int i=0; i < ind+1; i++)
 {
 if(buffer[i] == 'z') //once we hit the 'z' we can stop
 break;

 if((buffer[i] != 0x5A)&&(buffer[i] != 0x20)) //ignore 'Z' and white space
 {
 val += buffer[i]-48; //because we break at 'z' the only bytes getting added are the numbers
 // we subtract 48 to get to the actual numerical value
 // example the character '9' has an ASCII value of 57. [57-48=9] 
  }
 }

 co2 = (multiplier * val.toInt()); //now we multiply the value by a factor specific ot the sensor. see the
//Cozir software guide
 Serial.print( "Co2 = ");
 Serial.print(co2);
 Serial.println(" ppm");
 ind=0; //Reset the buffer index to overwrite the previous packet
 val=""; //Reset the value string
}

But I seem to have a problem to get this working. The code seem to be stuck in the while loop. while(buffer[ind-1] != 0x0A)

and I get always 0 for mySerial.available() and -1 for mySerial.read().
I checked the wiring quite a lot now. When I measured the voltage between the 3V3 and the GND to see if the power supply is correct the values for .read() changed to 0 and .available() increased very fast until it reaches 63. if i take off the multimeter the numbers decrease by one at the time but .read stays at 0. I dont know how to interpreted this.
I checked if the sensor works by using an sdk-cable and software GasLab provided by the sensor company. The sensor works fine this way.
I also tried to use another code which I found in a forum which includes the cozir.h. Still doesnt work.
Do you have any idea, what else I could try to figure out the problem?

That sort of thing indicates it's not wired correctly. Double check your wires against the instructions.

e.g. some people swap the TX and RX of Serial on a regular basis ...

I would convert it to use hardware serial, if I was using a MEGA. Just remove the #include for SoftwareSerial and replace the variable declaration with #define mySerial Serial1;

Then wire it up to the appropriate Tx1/Rx1 pins.

Hi,

Thank you very much for your help. I swapped the TX and RX wiring on the arduino, now it is contrary to what the instructions said. That brought a small improvement. I still get no automatic measurement reply about the CO2, but when ask about the preinstalled altitude properties of the sensor I get some kind of reaction from the sensor. I used this code:

void loop()
{
 //Cozir sensors ship from the factory in streaming mode
 //So we read incoming bytes into a buffer until we get '0x0A' which is the ASCII value for new-line
 while(buffer[ind-1] != 0x0A)
 {mySerial.write("s \r\n");//status of altitude properties
 if(mySerial.available())
 {
 buffer[ind] = mySerial.read();
 ind++;
 }
 }
 for(int i=1;i<26;i++){
 Serial.write(buffer[i]);
 } Serial.println("");}

strangely the reply stored in the buffer is different everytime I reupload the sketch and it doesnt make sense. It should always be like “s 08774 /r/n”

I found the problem or better the two problems. First the wiring was wrong in the instructions(TX and RX exchanged) and second the sensor was not in a default mode, but in a mode where it only sends out signals when requested. I changed that via the company software and the sdk-cable and after that the given code worked fine.
Thanks to both of you for your helpful suggestions :wink:

hallo, thank you, i had the same problem, and your post helped to solve it!
i twisted RX/TX and now the streaming mode works fine.
i have cozir-wx-60 sensor, and i use it with arduino uno.

but i have other two questions.
the first is: the value you are reading from the sensor are ok, in your opinion? i compared them with another co2 sensor, much more precise (and much more expensive, of course), and i find out than i had to change the multiplier from 10 to 4.5.

the second question: what is the sdk-cable? do i need it to change parameters in cozir senzor?

thank you,
regards,
ale

Also, i would like to ask how did you manage to log co2 concentration data. Are you logging each record outputted by the sensor (2 hz), or are you down sampling the records?
I would like to write in a txt file one record each 30 seconds, but I am not able to find how to do it.
I tried with delay and with millis method, but both ways lead to reading errors and I get a wrong value every 3 or 4 correct records.
If you can help me, it would be very appreciated!

Finally i managed to read correctly the sensor each "n" seconds, using millis function.
But i would like to put the sensor in polling mode, in order to get values only when requested. i used "K 2\r\n" command, but after this, i do not know how to request data.
Can anyone give me some hints?
Thanks,
Bye!