Alcoholmeter with MQ3 sensor

Dependencies:   TextLCD mbed

Committer:
lnadal
Date:
Sat Apr 09 14:18:50 2011 +0000
Revision:
2:5bb97fd609cb
Parent:
1:5a58f03abfe9

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lnadal 0:05d4673b2832 1 /* Alcoholmeter
lnadal 0:05d4673b2832 2
lnadal 0:05d4673b2832 3 Range: 0-3000 ppm.
lnadal 0:05d4673b2832 4
lnadal 2:5bb97fd609cb 5 *********************************************************************************
lnadal 0:05d4673b2832 6
lnadal 1:5a58f03abfe9 7 This project was done in 2010-11 school year in Molins de Rei (Barcelona, Spain)
lnadal 1:5a58f03abfe9 8 in Lluis de Requesens Secondari School.
lnadal 0:05d4673b2832 9
lnadal 1:5a58f03abfe9 10 Teacher: Lluis Nadal.
lnadal 0:05d4673b2832 11 Students: Agnes Garriga, Manel Tuells.
lnadal 0:05d4673b2832 12
lnadal 2:5bb97fd609cb 13 *********************************************************************************
lnadal 0:05d4673b2832 14
lnadal 2:5bb97fd609cb 15 Sensor: MQ-3 alcohol sensor.(http://www.sparkfun.com/;
lnadal 2:5bb97fd609cb 16 http://www.bricogeek.com/shop/).
lnadal 0:05d4673b2832 17
lnadal 0:05d4673b2832 18 MQ-3 sensor wiring:
lnadal 2:5bb97fd609cb 19 H1(5V), H2(ground), A(5V), B (R load = 500 Ohm - 1%),
lnadal 2:5bb97fd609cb 20 R load (mBed pin 20 - ground).
lnadal 0:05d4673b2832 21
lnadal 0:05d4673b2832 22 Analog out (for datalogger or multimeter): mBed pin 18 (1V = 1000 ppm).
lnadal 0:05d4673b2832 23
lnadal 0:05d4673b2832 24
lnadal 0:05d4673b2832 25
lnadal 2:5bb97fd609cb 26 MQ-3 sensor response is not linear. Calibration was done by passing air
lnadal 2:5bb97fd609cb 27 (with a fishtank air pump)
lnadal 1:5a58f03abfe9 28 through a dilute solution of ethanol in water.
lnadal 2:5bb97fd609cb 29 The resulting air saturated of ethanol vapor and water vapor, was continuously
lnadal 2:5bb97fd609cb 30 introduced in an open container containing the sensor. Th voltage across a
lnadal 2:5bb97fd609cb 31 load resistor was measured.
lnadal 0:05d4673b2832 32
lnadal 2:5bb97fd609cb 33 A 500 Ohm-1% load resistor was selected in order to achieve a measuring range
lnadal 2:5bb97fd609cb 34 of 3000 ppm.
lnadal 0:05d4673b2832 35
lnadal 2:5bb97fd609cb 36 After a bit difficult calculations, the sensor response was aproximated in a
lnadal 2:5bb97fd609cb 37 five degree polynomial:
lnadal 0:05d4673b2832 38
lnadal 0:05d4673b2832 39 X = V(in)
lnadal 0:05d4673b2832 40 ppm = 2.71494E+02*X - 3.10999E+02*X^2 + 6.85051E+02*X^3 - 3.47587E+02*X^4 + 7.47499E+01*X^5
lnadal 0:05d4673b2832 41
lnadal 0:05d4673b2832 42
lnadal 2:5bb97fd609cb 43 For more accurate readins is recommended a minimum heating time of 5 minutes
lnadal 2:5bb97fd609cb 44 (the manufacturer recommends 24) but 1 minute give satisfactory results.
lnadal 0:05d4673b2832 45 After heating, the sensor is autozeroed by averaging 5 measures.
lnadal 0:05d4673b2832 46
lnadal 0:05d4673b2832 47 In heating and in autozero operations the sensor must be left away of alcohol vapors!
lnadal 0:05d4673b2832 48
lnadal 0:05d4673b2832 49
lnadal 0:05d4673b2832 50 THIS FREE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. ENJOY IT.
lnadal 0:05d4673b2832 51
lnadal 0:05d4673b2832 52 */
lnadal 2:5bb97fd609cb 53 //*******************************************************************************
lnadal 0:05d4673b2832 54
lnadal 0:05d4673b2832 55
lnadal 0:05d4673b2832 56 #include "mbed.h"
lnadal 0:05d4673b2832 57 #include "TextLCD.h"
lnadal 0:05d4673b2832 58 #include <sstream>
lnadal 0:05d4673b2832 59 using namespace std;
lnadal 0:05d4673b2832 60
lnadal 0:05d4673b2832 61
lnadal 0:05d4673b2832 62
lnadal 0:05d4673b2832 63
lnadal 0:05d4673b2832 64 float concentration (float x){
lnadal 0:05d4673b2832 65
lnadal 0:05d4673b2832 66 const float A[] = { 2.71494E+02, -3.10999E+02, 6.85051E+02, -3.47587E+02, 7.47499E+01};
lnadal 0:05d4673b2832 67 float result;
lnadal 0:05d4673b2832 68 float B[4];
lnadal 0:05d4673b2832 69 B[0] = x*x;
lnadal 0:05d4673b2832 70 B[1] = B[0]*x;
lnadal 0:05d4673b2832 71 B[2] = B[1]*x;
lnadal 0:05d4673b2832 72 B[3] = B[2]*x;
lnadal 0:05d4673b2832 73
lnadal 0:05d4673b2832 74 result = A[0]*x+A[1]*B[0]+A[2]*B[1]+A[3]*B[2]+A[4]*B[3];
lnadal 0:05d4673b2832 75 return result;
lnadal 0:05d4673b2832 76 }
lnadal 0:05d4673b2832 77
lnadal 0:05d4673b2832 78
lnadal 0:05d4673b2832 79
lnadal 0:05d4673b2832 80
lnadal 0:05d4673b2832 81 char messages[5][16] = {"Heating sensor", "64 seconds", "Autozero", "Ready!", "ppm"};
lnadal 0:05d4673b2832 82
lnadal 0:05d4673b2832 83
lnadal 0:05d4673b2832 84 int L;
lnadal 0:05d4673b2832 85 float x;
lnadal 0:05d4673b2832 86 float x0[5];
lnadal 0:05d4673b2832 87 float x_initial;
lnadal 0:05d4673b2832 88
lnadal 0:05d4673b2832 89 TextLCD lcd(p24, p26, p27, p28, p29, p30); // Wiring microcontroller - LCD:
lnadal 0:05d4673b2832 90 // rs(4), e(6), d4(11), d5(12), d6(13), d7(14) (R/W(5) a 0)
lnadal 0:05d4673b2832 91
lnadal 1:5a58f03abfe9 92 DigitalIn pushbutton = p8; // Pushbutton (normally open). Stops initial heating time when it is pressed.
lnadal 0:05d4673b2832 93 AnalogOut output(p18); // Analog output to a multimeter or datalogger (1V = 1000 ppm).
lnadal 0:05d4673b2832 94
lnadal 0:05d4673b2832 95
lnadal 0:05d4673b2832 96
lnadal 0:05d4673b2832 97 void text_screen( char message[], int colum, int row) {
lnadal 0:05d4673b2832 98
lnadal 0:05d4673b2832 99 lcd.locate( colum, row);
lnadal 0:05d4673b2832 100 lcd.printf(message);
lnadal 0:05d4673b2832 101
lnadal 0:05d4673b2832 102 }
lnadal 0:05d4673b2832 103
lnadal 0:05d4673b2832 104
lnadal 0:05d4673b2832 105
lnadal 0:05d4673b2832 106 int main() {
lnadal 0:05d4673b2832 107
lnadal 0:05d4673b2832 108 output = 0.0;
lnadal 0:05d4673b2832 109 lcd.cls();
lnadal 0:05d4673b2832 110
lnadal 0:05d4673b2832 111 text_screen(messages[0], 0, 0);
lnadal 0:05d4673b2832 112 text_screen(messages[1], 0, 1);
lnadal 0:05d4673b2832 113 wait(2);
lnadal 0:05d4673b2832 114
lnadal 0:05d4673b2832 115
lnadal 0:05d4673b2832 116
lnadal 0:05d4673b2832 117 for (int j = 0; j<4; j++){
lnadal 0:05d4673b2832 118
lnadal 0:05d4673b2832 119 lcd.cls(); // Heating sensor 4x16 = 64 seconds
lnadal 0:05d4673b2832 120 text_screen(messages[0], 0, 0);
lnadal 0:05d4673b2832 121
lnadal 0:05d4673b2832 122
lnadal 0:05d4673b2832 123 for (int i = 0; i<16; i++){
lnadal 0:05d4673b2832 124 if (pushbutton == 1){ // Pressing pushbutton stops initial heating and enters in measuring mode.
lnadal 0:05d4673b2832 125 break;
lnadal 0:05d4673b2832 126 }
lnadal 0:05d4673b2832 127 lcd.locate(i, 1);
lnadal 0:05d4673b2832 128 lcd.putc(62);
lnadal 0:05d4673b2832 129 wait(1);
lnadal 0:05d4673b2832 130 }
lnadal 0:05d4673b2832 131 }
lnadal 0:05d4673b2832 132
lnadal 0:05d4673b2832 133 lcd.cls();
lnadal 0:05d4673b2832 134 text_screen(messages[2], 0, 0);
lnadal 0:05d4673b2832 135 wait(2);
lnadal 0:05d4673b2832 136
lnadal 0:05d4673b2832 137
lnadal 0:05d4673b2832 138 AnalogIn value(p20); // Reads sensor voltage as a float int the interval (0-1) corresponding to (0 - 3.3V).
lnadal 0:05d4673b2832 139
lnadal 0:05d4673b2832 140
lnadal 0:05d4673b2832 141
lnadal 0:05d4673b2832 142 for (int i=0; i<5; i++){
lnadal 0:05d4673b2832 143
lnadal 0:05d4673b2832 144 x0[i] = value;
lnadal 0:05d4673b2832 145 wait(2);
lnadal 0:05d4673b2832 146
lnadal 0:05d4673b2832 147 }
lnadal 0:05d4673b2832 148 x_initial = (x0[0]+x0[1]+x0[2]+x0[3]+x0[4])/5.0; // Autozero. Average of 5 initial measures.
lnadal 0:05d4673b2832 149
lnadal 0:05d4673b2832 150 lcd.cls();
lnadal 0:05d4673b2832 151 text_screen(messages[3], 0, 0);
lnadal 0:05d4673b2832 152 wait(2);
lnadal 0:05d4673b2832 153
lnadal 0:05d4673b2832 154 while(1) {
lnadal 0:05d4673b2832 155 x = value;
lnadal 0:05d4673b2832 156 x = (x-x_initial)*3.3; // Calculate real voltage.
lnadal 0:05d4673b2832 157
lnadal 0:05d4673b2832 158 if(x<0) x = 0;
lnadal 0:05d4673b2832 159
lnadal 0:05d4673b2832 160 x = concentration(x);
lnadal 0:05d4673b2832 161
lnadal 0:05d4673b2832 162 output = x/3000; // If analog readings do not match digital readings you can adjust this value (1000 ppm = 1V).
lnadal 0:05d4673b2832 163
lnadal 0:05d4673b2832 164 wait(0.1);
lnadal 0:05d4673b2832 165
lnadal 0:05d4673b2832 166 // Float to string conversion.
lnadal 0:05d4673b2832 167 stringstream ss (stringstream::in | stringstream::out);
lnadal 0:05d4673b2832 168 ss <<x;
lnadal 0:05d4673b2832 169 string reading = ss.str();
lnadal 0:05d4673b2832 170 L = reading.length();
lnadal 0:05d4673b2832 171
lnadal 0:05d4673b2832 172
lnadal 0:05d4673b2832 173 lcd.cls();
lnadal 0:05d4673b2832 174 for (int i=0; i<L; i+=1){
lnadal 0:05d4673b2832 175 lcd.locate(i,0);
lnadal 0:05d4673b2832 176 lcd.putc(reading[i]);
lnadal 0:05d4673b2832 177
lnadal 0:05d4673b2832 178
lnadal 0:05d4673b2832 179
lnadal 0:05d4673b2832 180 text_screen(messages[4], 10, 0);
lnadal 0:05d4673b2832 181 }
lnadal 0:05d4673b2832 182 wait(2);
lnadal 0:05d4673b2832 183 }
lnadal 0:05d4673b2832 184 }