123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- /*
- * The MySensors Arduino library handles the wireless radio link and protocol
- * between your home built sensors/actuators and HA controller of choice.
- * The sensors forms a self healing radio network with optional repeaters. Each
- * repeater and gateway builds a routing tables in EEPROM which keeps track of the
- * network topology allowing messages to be routed to nodes.
- *
- * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
- * Copyright (C) 2013-2018 Sensnology AB
- * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
- *
- * Documentation: http://www.mysensors.org
- * Support Forum: http://forum.mysensors.org
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- *******************************
- *
- * DESCRIPTION
- *
- * 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
- *
- */
-
- // Enable debug prints to serial monitor
- #define MY_DEBUG
-
- // Enable and select radio type attached
- #define MY_RADIO_RF24
- //#define MY_RADIO_NRF5_ESB
- //#define MY_RADIO_RFM69
- //#define MY_RADIO_RFM95
-
- #include <MySensors.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 interval(in milliseconds) between each samples in the
- //calibration 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 interval(in milliseconds) between each samples in
- //normal operation
- /**********************Application Related Macros**********************************/
- #define GAS_LPG (0)
- #define GAS_CO (1)
- #define GAS_SMOKE (2)
- /*****************************Globals***********************************************/
- uint32_t 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)
-
-
- MyMessage msg(CHILD_ID_MQ, V_LEVEL);
-
- void setup()
- {
- Ro = MQCalibration(
- MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air
- }
-
- void presentation()
- {
- // Send the sketch version information to the gateway and Controller
- sendSketchInfo("Air Quality Sensor", "1.0");
-
- // Register all sensors to gateway (they will be created as child devices)
- present(CHILD_ID_MQ, S_AIR_QUALITY);
- }
-
- 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) {
- send(msg.set((int16_t)ceil(valMQ)));
- lastMQ = ceil(valMQ);
- }
-
- 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 calculate the sensor resistance (Rs).
- The Rs changes as the sensor is in the different concentration 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])));
- }
|