-
-
Notifications
You must be signed in to change notification settings - Fork 891
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added MQ2 Air quality sensor by epierre (converted to 1.4)
- Loading branch information
1 parent
17e4769
commit 7b4bef5
Showing
2 changed files
with
197 additions
and
1 deletion.
There are no files selected for viewing
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
196 changes: 196 additions & 0 deletions
196
libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
/* | ||
Vera Arduino MQ2 | ||
connect the MQ2 sensor as follows : | ||
A H A >>> 5V | ||
B >>> A0 | ||
H >>> GND | ||
B >>> 10K ohm >>> GND | ||
Contribution: epierre | ||
Based on http://sandboxelectronics.com/?p=165 | ||
License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) | ||
Modified by HEK to work in 1.4 | ||
*/ | ||
|
||
#include <SPI.h> | ||
#include <MySensor.h> | ||
#include <Wire.h> | ||
|
||
#define CHILD_ID_MQ 0 | ||
/************************Hardware Related Macros************************************/ | ||
#define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use | ||
#define RL_VALUE (5) //define the load resistance on the board, in kilo ohms | ||
#define RO_CLEAN_AIR_FACTOR (9.83) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO, | ||
//which is derived from the chart in datasheet | ||
/***********************Software Related Macros************************************/ | ||
#define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase | ||
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the | ||
//cablibration phase | ||
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation | ||
#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in | ||
//normal operation | ||
/**********************Application Related Macros**********************************/ | ||
#define GAS_LPG (0) | ||
#define GAS_CO (1) | ||
#define GAS_SMOKE (2) | ||
/*****************************Globals***********************************************/ | ||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) | ||
//VARIABLES | ||
float Ro = 10000.0; // this has to be tuned 10K Ohm | ||
int val = 0; // variable to store the value coming from the sensor | ||
float valMQ =0.0; | ||
float lastMQ =0.0; | ||
float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve. | ||
//with these two points, a line is formed which is "approximately equivalent" | ||
//to the original curve. | ||
//data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) | ||
float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve. | ||
//with these two points, a line is formed which is "approximately equivalent" | ||
//to the original curve. | ||
//data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15) | ||
float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve. | ||
//with these two points, a line is formed which is "approximately equivalent" | ||
//to the original curve. | ||
//data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22) | ||
|
||
|
||
MySensor gw; | ||
MyMessage msg(CHILD_ID_MQ, V_VAR1); | ||
|
||
|
||
void setup() | ||
{ | ||
gw.begin(); | ||
|
||
// Send the sketch version information to the gateway and Controller | ||
gw.sendSketchInfo("Air Quality Sensor", "1.0"); | ||
|
||
// Register all sensors to gateway (they will be created as child devices) | ||
gw.present(CHILD_ID_MQ, S_AIR_QUALITY); | ||
|
||
Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air | ||
//when you perform the calibration | ||
} | ||
|
||
void loop() | ||
{ | ||
uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO); | ||
Serial.println(val); | ||
|
||
Serial.print("LPG:"); | ||
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) ); | ||
Serial.print( "ppm" ); | ||
Serial.print(" "); | ||
Serial.print("CO:"); | ||
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) ); | ||
Serial.print( "ppm" ); | ||
Serial.print(" "); | ||
Serial.print("SMOKE:"); | ||
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) ); | ||
Serial.print( "ppm" ); | ||
Serial.print("\n"); | ||
|
||
if (valMQ != lastMQ) { | ||
gw.send(msg.set((int)ceil(valMQ))); | ||
lastMQ = ceil(valMQ); | ||
} | ||
|
||
gw.sleep(SLEEP_TIME); //sleep for: sleepTime | ||
} | ||
|
||
/****************** MQResistanceCalculation **************************************** | ||
Input: raw_adc - raw value read from adc, which represents the voltage | ||
Output: the calculated sensor resistance | ||
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage | ||
across the load resistor and its resistance, the resistance of the sensor | ||
could be derived. | ||
************************************************************************************/ | ||
float MQResistanceCalculation(int raw_adc) | ||
{ | ||
return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc)); | ||
} | ||
|
||
/***************************** MQCalibration **************************************** | ||
Input: mq_pin - analog channel | ||
Output: Ro of the sensor | ||
Remarks: This function assumes that the sensor is in clean air. It use | ||
MQResistanceCalculation to calculates the sensor resistance in clean air | ||
and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about | ||
10, which differs slightly between different sensors. | ||
************************************************************************************/ | ||
float MQCalibration(int mq_pin) | ||
{ | ||
int i; | ||
float val=0; | ||
|
||
for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) { //take multiple samples | ||
val += MQResistanceCalculation(analogRead(mq_pin)); | ||
delay(CALIBRATION_SAMPLE_INTERVAL); | ||
} | ||
val = val/CALIBARAION_SAMPLE_TIMES; //calculate the average value | ||
|
||
val = val/RO_CLEAN_AIR_FACTOR; //divided by RO_CLEAN_AIR_FACTOR yields the Ro | ||
//according to the chart in the datasheet | ||
|
||
return val; | ||
} | ||
/***************************** MQRead ********************************************* | ||
Input: mq_pin - analog channel | ||
Output: Rs of the sensor | ||
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs). | ||
The Rs changes as the sensor is in the different consentration of the target | ||
gas. The sample times and the time interval between samples could be configured | ||
by changing the definition of the macros. | ||
************************************************************************************/ | ||
float MQRead(int mq_pin) | ||
{ | ||
int i; | ||
float rs=0; | ||
|
||
for (i=0;i<READ_SAMPLE_TIMES;i++) { | ||
rs += MQResistanceCalculation(analogRead(mq_pin)); | ||
delay(READ_SAMPLE_INTERVAL); | ||
} | ||
|
||
rs = rs/READ_SAMPLE_TIMES; | ||
|
||
return rs; | ||
} | ||
|
||
/***************************** MQGetGasPercentage ********************************** | ||
Input: rs_ro_ratio - Rs divided by Ro | ||
gas_id - target gas type | ||
Output: ppm of the target gas | ||
Remarks: This function passes different curves to the MQGetPercentage function which | ||
calculates the ppm (parts per million) of the target gas. | ||
************************************************************************************/ | ||
int MQGetGasPercentage(float rs_ro_ratio, int gas_id) | ||
{ | ||
if ( gas_id == GAS_LPG ) { | ||
return MQGetPercentage(rs_ro_ratio,LPGCurve); | ||
} else if ( gas_id == GAS_CO ) { | ||
return MQGetPercentage(rs_ro_ratio,COCurve); | ||
} else if ( gas_id == GAS_SMOKE ) { | ||
return MQGetPercentage(rs_ro_ratio,SmokeCurve); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/***************************** MQGetPercentage ********************************** | ||
Input: rs_ro_ratio - Rs divided by Ro | ||
pcurve - pointer to the curve of the target gas | ||
Output: ppm of the target gas | ||
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm) | ||
of the line could be derived if y(rs_ro_ratio) is provided. As it is a | ||
logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic | ||
value. | ||
************************************************************************************/ | ||
int MQGetPercentage(float rs_ro_ratio, float *pcurve) | ||
{ | ||
return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0]))); | ||
} |