Hello all,
So, I'm a newb at this stuff and I'm basically just piecing things together for the most part.
I have a project, that among other things measures CO2 levels using this arduino mega 2560 R3 and an MH-Z14a.
I've attempted calibrating the sensor by letting it run outdoors for >24hours and also by sending the zero point calibration command after 30min. Neither seem to work as I still read below 400ppm (between 140 and 200ppm) outdoors.
Here's a "working" slice of the code that I'm having issues with:
#include <Arduino.h>
#include <LiquidCrystal.h>
int SecToPreheatCO2Sensor = 180; //Seconds to PreHeat the CO2 Sensor (docs call for 180 seconds)
int CO2PPM = 0;
long MillisToPreheatCO2Sensor = (SecToPreheatCO2Sensor * 1000L); //Milliseconds to PreHeat the CO2 Sensor
long MillisToCalibrateCO2 = 1800000; //176400000; //49 hours
long CO2WarmingTimer = 0;
long CO2CountdownTimer = 0;
long CO2CalibrationTimer = 0;
long LastCO2Reading = 0;
bool CO2Calibrated = false;
//LCD Config - Parameters: (rs, enable, d4, d5, d6, d7)//
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
/////////////////////////////////////////////////////////
//CO2 Config///////////////////////////////////////////////////////////////////////////////////
byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; // get gas command
byte cmdCal[9] = {0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78}; // calibrate command
byte mhzCmdABCEnable[9] = {0xFF,0x01,0x79,0xA0,0x00,0x00,0x00,0x00,0xE6};
byte mhzCmdABCDisable[9] = {0xFF,0x01,0x79,0x00,0x00,0x00,0x00,0x00,0x86};
char response[9]; // holds the recieved data
///////////////////////////////////////////////////////////////////////////////////////////////
//ChamberMode Switch Config////////////////////////////////////////////////////////////////////////
#define ChamberModeSwitchPin A0 //for 3-way switch
int ChamberModeSwitchValue = 0; //integer for analog value of pin that mode switch is connected to
String PreviousChamberMode = ""; //for 3-way switch
String ActualChamberMode = ""; //for 3-way switch
////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
//Initialize Serial Busses/////////////////////////////
Serial.begin(9600);
while(!Serial); // Time to get serial running
Serial1.begin(9600); //CO2 runs on Serial 1
while(!Serial1); // time to get serial1 running
///////////////////////////////////////////////////////
// LCD Initialization/////////////////////////////////////////////////////////
lcd.begin(20,4);//Specifies the dimensions (width and height) of the display
//////////////////////////////////////////////////////////////////////////////
//Call ChamberMode Function for Confirmation - reads a POT to determine mode//
ChamberMode();
//////////////////////////////////////////////////////////////////////////////
//Call calibration function (will not run unless in calibrate mode)//
calibrate();
/////////////////////////////////////////////////////////////////////
}
void loop()
{
}
//Chamber Mode Function////////////////////////////////////////////////
void ChamberMode()
{
ActualChamberMode = "Calibration";
}
///////////////////////////////////////////////////////////////////////
//CO2 Sensor Calibration Function/////////////////////////////////////////////////////////////////////////////////
void calibrate()
{
if (ActualChamberMode == "Calibration")
{
Serial1.write(mhzCmdABCEnable, 9);
CO2CalibrationTimer = millis();
LCDDataRefresh();
WarmCO2();
while ((millis() - CO2CalibrationTimer < MillisToCalibrateCO2) && (ActualChamberMode == "Calibration"))
{
GetCO2Readings();
ChamberMode();
LCDDataRefresh();
delay(15000);
}
if ((CO2Calibrated == false) && (millis() - CO2CalibrationTimer > MillisToCalibrateCO2))
{
CO2Calibrated = true;
delay(10000);//added 10 sec delay in case I screw up the code and start calling calibrate in a loop and it messes the sensor up like I read online
Serial1.write(cmdCal, 9);
delay(100);
while (CO2Calibrated == true)
{
GetCO2Readings();
ChamberMode();
LCDDataRefresh();
delay(15000);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CO2 Reading Function///////////////////////////////////////////////////////////////////////////////////////
void GetCO2Readings()
{
while (Serial1.available()) // this clears out any garbage in the RX buffer
{
int garbage = Serial1.read();
}
Serial1.write(cmd, 9); // Sent out read command to the sensor
Serial1.flush(); // this pauses the sketch and waits for the TX buffer to send all its data to the sensor
while (!Serial1.available()) // this pauses the sketch and waits for the sensors responce
{
delay(0);
}
Serial1.readBytes(response, 9); // once data is avilable, it reads it to a variable
int responseHigh = (int)response[2];
int responseLow = (int)response[3];
CO2PPM = (256 * responseHigh) + responseLow;
LastCO2Reading = millis();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Warmup CO2 Sensor Funtion//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void WarmCO2()
{
CO2WarmingTimer = millis();
Serial.println("CO2 Warmup Countdown Starting");
while (millis() - CO2WarmingTimer < MillisToPreheatCO2Sensor)
{
if (millis() - CO2CountdownTimer > 1000)
{
Serial.println((MillisToPreheatCO2Sensor - (millis() - CO2WarmingTimer)) / 1000); // counts down till the sensor is ready
lcd.setCursor(0,3);
lcd.print("CO2WarmupTimer:");
lcd.setCursor(15,3);
lcd.print(" ");
lcd.setCursor(15,3);
lcd.print((MillisToPreheatCO2Sensor - (millis() - CO2WarmingTimer)) / 1000);
CO2CountdownTimer = millis();
}
}
GetCO2Readings();
Serial.print("CO2 Read in Setup: ");
Serial.println(CO2PPM);
LastCO2Reading = millis();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//LCD Data Refresh Function////////////////////////////////////////////////////////////////////
void LCDDataRefresh()
{
lcd.clear(); // Clears the display
if (ActualChamberMode == "Calibration")
{
lcd.print("Mode:");
lcd.setCursor(6,0);
lcd.print(ActualChamberMode);
lcd.setCursor(0,1);
lcd.print("T-Minus:");
lcd.setCursor(9,1);
lcd.print(((MillisToCalibrateCO2 - (millis() - CO2CalibrationTimer)) / 1000) /60);
lcd.setCursor(0,2);
lcd.print("Calibrated?");
lcd.setCursor(12,2);
lcd.print(CO2Calibrated);
lcd.setCursor(0,3);
lcd.print("CO2PPM Reading:");
lcd.setCursor(15,3);
lcd.print(" ");
lcd.setCursor(15,3);
lcd.print(CO2PPM);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
Sorry if the code organization or comment lines are weird, it just really helps me read the code more easily.
Here's the wiring diagram: (I've also attached it in case the google link doesn't work)
Basically I just have it wired directly to the Mega's 5v, gnd and serial1 at D18 and D19.
The Mega is being powered via 5v usb.
Not sure if I'm missing anything, hopefully someone out there can give me a couple pointers.
