Added MQ2 Air quality sensor by epierre (converted to 1.4)
This commit is contained in:
@@ -48,7 +48,7 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND,
|
S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND,
|
||||||
S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE,
|
S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE,
|
||||||
S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER
|
S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY
|
||||||
} sensor;
|
} sensor;
|
||||||
|
|
||||||
// Type of data stream (for streamed message)
|
// Type of data stream (for streamed message)
|
||||||
|
|||||||
@@ -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])));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user