GasAlarm.ino


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
}