1 | /*Smoke Sensor MQ7 mit LCD Display
|
2 | connect the MQ2 sensor as follows :
|
3 |
|
4 | VCC >>> 5V
|
5 | AD0 >>> A0
|
6 | GND >>> GND
|
7 | Contribution: epierre
|
8 | Based on http://sandboxelectronics.com/?p=165
|
9 |
|
10 | License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
|
11 | */
|
12 |
|
13 | #include <LiquidCrystal.h> //Sample using LiquidCrystal library
|
14 |
|
15 | LiquidCrystal lcd(12, 11, 10, 7, 6, 5, 4); // select the pins used on the LCD panel
|
16 |
|
17 |
|
18 | #define CHILD_ID_MQ 0
|
19 | /************************Hardware Related Macros************************************/
|
20 | #define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use
|
21 | #define RL_VALUE (5) //define the load resistance on the board, in kilo ohms
|
22 | #define RO_CLEAN_AIR_FACTOR (9.83) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
|
23 | //which is derived from the chart in datasheet
|
24 | /***********************Software Related Macros************************************/
|
25 | #define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase
|
26 | #define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
|
27 | //cablibration phase
|
28 | #define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
|
29 | #define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
|
30 | //normal operation
|
31 | /**********************Application Related Macros**********************************/
|
32 | #define GAS_LPG (0)
|
33 | #define GAS_CO (1)
|
34 | #define GAS_SMOKE (2)
|
35 | /*****************************Globals***********************************************/
|
36 | unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
37 | //VARIABLES
|
38 | float Ro = 10000.0; // this has to be tuned 10K Ohm
|
39 | int val = 0; // variable to store the value coming from the sensor
|
40 | float valMQ = 0.0;
|
41 | float lastMQ = 0.0;
|
42 | float LPGCurve[3] = {2.3, 0.21, -0.47}; //two points are taken from the curve.
|
43 | //with these two points, a line is formed which is "approximately equivalent"
|
44 | //to the original curve.
|
45 | //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
|
46 | float COCurve[3] = {2.3, 0.72, -0.34}; //two points are taken from the curve.
|
47 | //with these two points, a line is formed which is "approximately equivalent"
|
48 | //to the original curve.
|
49 | //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
|
50 | float SmokeCurve[3] = {2.3, 0.53, -0.44}; //two points are taken from the curve.
|
51 | //with these two points, a line is formed which is "approximately equivalent"
|
52 | //to the original curve.
|
53 | //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22)
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | void setup()
|
60 | {
|
61 | pinMode(2,OUTPUT);
|
62 | Serial.begin(9600); //UART setup, baudrate = 9600bps
|
63 | Serial.print("Calibrating...\n");
|
64 | lcd.begin(16, 2); // start the LCD library
|
65 | lcd.setCursor(0, 0); // set cursor position at start
|
66 |
|
67 | lcd.print("Kalibrierung ...");
|
68 | Serial.print("Setup ...");
|
69 | Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN);
|
70 | // display standard
|
71 | lcd.clear();
|
72 | lcd.setCursor(0, 0);
|
73 | lcd.print("LPG:");
|
74 | lcd.setCursor(0, 1);
|
75 | lcd.print("SMOKE:");
|
76 | lcd.setCursor(12, 1);
|
77 | lcd.print("ppm");
|
78 | }
|
79 |
|
80 | void loop()
|
81 | {
|
82 |
|
83 | Serial.print("LPG:");
|
84 | uint16_t valLPG = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN) / Ro, GAS_LPG);
|
85 | Serial.println(valLPG);
|
86 |
|
87 | Serial.print("SMOKE:");
|
88 | uint16_t valSMOKE = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN) / Ro, GAS_SMOKE);
|
89 | Serial.println(valSMOKE);
|
90 |
|
91 | if ((valLPG >= 10) || (valSMOKE >= 10)) {
|
92 | // Alarm wenn Grenzwert überschritten!
|
93 | Serial.println ("ALARM!");
|
94 | digitalWrite(2,HIGH);
|
95 | lcd.setCursor(0, 1); // clear digits
|
96 | lcd.print( "ALARM!!!" );
|
97 | }
|
98 |
|
99 | lcd.setCursor(4, 0); // clear digits
|
100 | lcd.print( " " );
|
101 | lcd.setCursor(4, 0);
|
102 | lcd.print(valLPG);
|
103 |
|
104 | lcd.setCursor(6, 1); // clear digits
|
105 | lcd.print( " " );
|
106 | lcd.setCursor(6, 1);
|
107 | lcd.print(valSMOKE);
|
108 |
|
109 | }
|
110 |
|
111 | /****************** MQResistanceCalculation ****************************************
|
112 | Input: raw_adc - raw value read from adc, which represents the voltage
|
113 | Output: the calculated sensor resistance
|
114 | Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
|
115 | across the load resistor and its resistance, the resistance of the sensor
|
116 | could be derived.
|
117 | ************************************************************************************/
|
118 | float MQResistanceCalculation(int raw_adc)
|
119 | {
|
120 | return ( ((float)RL_VALUE * (1023 - raw_adc) / raw_adc));
|
121 | }
|
122 |
|
123 | /***************************** MQCalibration ****************************************
|
124 | Input: mq_pin - analog channel
|
125 | Output: Ro of the sensor
|
126 | Remarks: This function assumes that the sensor is in clean air. It use
|
127 | MQResistanceCalculation to calculates the sensor resistance in clean air
|
128 | and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
|
129 | 10, which differs slightly between different sensors.
|
130 | ************************************************************************************/
|
131 | float MQCalibration(int mq_pin)
|
132 | {
|
133 | int i;
|
134 | float val = 0;
|
135 |
|
136 | for (i = 0; i < CALIBARAION_SAMPLE_TIMES; i++) { //take multiple samples
|
137 | val += MQResistanceCalculation(analogRead(mq_pin));
|
138 | delay(CALIBRATION_SAMPLE_INTERVAL);
|
139 | }
|
140 | val = val / CALIBARAION_SAMPLE_TIMES; //calculate the average value
|
141 |
|
142 | val = val / RO_CLEAN_AIR_FACTOR; //divided by RO_CLEAN_AIR_FACTOR yields the Ro
|
143 | //according to the chart in the datasheet
|
144 |
|
145 | return val;
|
146 | }
|
147 | /***************************** MQRead *********************************************
|
148 | Input: mq_pin - analog channel
|
149 | Output: Rs of the sensor
|
150 | Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
|
151 | The Rs changes as the sensor is in the different consentration of the target
|
152 | gas. The sample times and the time interval between samples could be configured
|
153 | by changing the definition of the macros.
|
154 | ************************************************************************************/
|
155 | float MQRead(int mq_pin)
|
156 | {
|
157 | int i;
|
158 | float rs = 0;
|
159 |
|
160 | for (i = 0; i < READ_SAMPLE_TIMES; i++) {
|
161 | rs += MQResistanceCalculation(analogRead(mq_pin));
|
162 | delay(READ_SAMPLE_INTERVAL);
|
163 | }
|
164 |
|
165 | rs = rs / READ_SAMPLE_TIMES;
|
166 |
|
167 | return rs;
|
168 | }
|
169 |
|
170 | /***************************** MQGetGasPercentage **********************************
|
171 | Input: rs_ro_ratio - Rs divided by Ro
|
172 | gas_id - target gas type
|
173 | Output: ppm of the target gas
|
174 | Remarks: This function passes different curves to the MQGetPercentage function which
|
175 | calculates the ppm (parts per million) of the target gas.
|
176 | ************************************************************************************/
|
177 | int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
|
178 | {
|
179 | if ( gas_id == GAS_LPG ) {
|
180 | return MQGetPercentage(rs_ro_ratio, LPGCurve);
|
181 | } else if ( gas_id == GAS_CO ) {
|
182 | return MQGetPercentage(rs_ro_ratio, COCurve);
|
183 | } else if ( gas_id == GAS_SMOKE ) {
|
184 | return MQGetPercentage(rs_ro_ratio, SmokeCurve);
|
185 | }
|
186 |
|
187 | return 0;
|
188 | }
|
189 |
|
190 | /***************************** MQGetPercentage **********************************
|
191 | Input: rs_ro_ratio - Rs divided by Ro
|
192 | pcurve - pointer to the curve of the target gas
|
193 | Output: ppm of the target gas
|
194 | Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
|
195 | of the line could be derived if y(rs_ro_ratio) is provided. As it is a
|
196 | logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
|
197 | value.
|
198 | ************************************************************************************/
|
199 | int MQGetPercentage(float rs_ro_ratio, float *pcurve)
|
200 | {
|
201 | return (pow(10, ( ((log(rs_ro_ratio) - pcurve[1]) / pcurve[2]) + pcurve[0])));
|
202 | }
|