Last active
July 12, 2017 04:23
-
-
Save ic/6412a4354304665e05d5951912c2cbfb to your computer and use it in GitHub Desktop.
MG-811 Calibration for the auto-ctrl board on Arduino (UNO)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* About the calibration model: | |
* This calibration is very simple, and so lacks accuracy for serious use. See this script as a getting-started solution. | |
* The calibration relies on 2 points, at 400ppm and 1000ppm. The 400ppm is the assumed CO2 concentration in "fresh air". | |
* You see that this number is really inaccurate (references ranges from 350 to 390ppm). The 1000ppm comes from TODO. | |
* 150s -> ~40000ppm | |
* 0s -> ~400ppm, approximate linear growth based on Vernier's | |
* slope = 264 ppm/s; V0 = 400 | |
* Avg human 1 breath every 3-5s | |
* => 1 breath ~ +792 to +1320ppm => avg. 1056ppm, let's say 1000ppm | |
* | |
* See also: | |
* + [Calibration notes from CO2 Meter](https://www.co2meter.com/blogs/news/7512282-co2-sensor-calibration-what-you-need-to-know) | |
* + [Sandbox Electronics' MG-811 CO2 Sensor Module](http://sandboxelectronics.com/?p=147) | |
* + [Vernier's post on human respiration](http://www.vernier.com/innovate/human-respiration/) | |
*/ | |
#define MG811_OUT_PIN (0) | |
#define MG811_DIGITAL_PIN (2) | |
//#define DC_GAIN (8.5) //define the DC gain of amplifier | |
#define VENT_PIN (8) // Fan to force an airflow on the sensor. | |
#define READ_SAMPLE_INTERVAL (50) | |
#define READ_SAMPLE_TIMES (5) | |
// Constants | |
#define LOG_400 (2.602) | |
#define LOG_1000 (3) | |
// Measure model. | |
#define LOG_400_VOLTAGE (0.30) // Voltage when the concentration of CO2 is 400ppm. | |
#define LOG_1000_VOLTAGE (0.25) // Voltage when the concentration of CO2 is 1000ppm. | |
float co2_log_slope = (LOG_1000_VOLTAGE - LOG_400_VOLTAGE) / (LOG_1000 - LOG_400); | |
float v400 = LOG_400_VOLTAGE - co2_log_slope * LOG_400; | |
void setup() { | |
Serial.begin(9600); | |
pinMode(MG811_DIGITAL_PIN, INPUT); | |
digitalWrite(MG811_DIGITAL_PIN, HIGH); | |
pinMode(VENT_PIN, OUTPUT); | |
digitalWrite(VENT_PIN, HIGH); | |
Serial.print("Settings:\n"); | |
Serial.print("CO2 measurement slope: "); | |
Serial.print(co2_log_slope); | |
Serial.print(" V / log(ppm)\n"); | |
Serial.print("Voltage at 400ppm: "); | |
Serial.print(v400); | |
Serial.print("V\n\n"); | |
} | |
void loop() { | |
float volts = MG811ReportRaw(); | |
MG822ReportPPM(volts); | |
MG822ReportDigital(); | |
Serial.print("\n"); | |
delay(3000); | |
} | |
float MG811ReportRaw() { | |
float volts; | |
volts = MG811Read(MG811_OUT_PIN); | |
Serial.print("Reading: "); | |
Serial.print(volts); | |
Serial.print("V\n"); | |
return volts; | |
} | |
int MG822ReportPPM(float volts) { | |
int ppm; | |
ppm = MG811ToPPM(volts); | |
Serial.print("CO2: "); | |
if (ppm == -1) { | |
Serial.print( "< 400" ); | |
} else { | |
Serial.print(ppm); | |
} | |
Serial.print("ppm\n"); | |
return ppm; | |
} | |
void MG822ReportDigital() { | |
if (digitalRead(MG811_DIGITAL_PIN) ){ | |
Serial.print("HIGH"); | |
} else { | |
Serial.print("LOW"); | |
} | |
Serial.print("\n"); | |
} | |
float MG811Read(int pin) { | |
int i; | |
float v = 0; | |
for (i = 0; i < READ_SAMPLE_TIMES; i++) { | |
v += analogRead(pin); | |
delay(READ_SAMPLE_INTERVAL); | |
} | |
// Convert digital to analog value. | |
v = (v / READ_SAMPLE_TIMES) * 5 / 1024; | |
return v; | |
} | |
int MG811ToPPM(float volts) { | |
if (volts >= LOG_400_VOLTAGE) { | |
return -1; | |
} else { | |
return pow(10, (volts - v400) / co2_log_slope); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment