Lluis Nadal
/
Alcoholmeter
Alcoholmeter with MQ3 sensor
main.cpp@2:5bb97fd609cb, 2011-04-09 (annotated)
- Committer:
- lnadal
- Date:
- Sat Apr 09 14:18:50 2011 +0000
- Revision:
- 2:5bb97fd609cb
- Parent:
- 1:5a58f03abfe9
Who changed what in which revision?
User | Revision | Line number | New 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 | } |