Alcoholmeter with MQ3 sensor

Dependencies:   TextLCD mbed

Revision:
0:05d4673b2832
Child:
1:5a58f03abfe9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Apr 09 14:04:34 2011 +0000
@@ -0,0 +1,174 @@
+/* Alcoholmeter
+
+Range: 0-3000 ppm.
+
+*************************************************************************************************************************
+
+This project was done in 2010-11 school year in Molins de Rei (Barcelona, Spain) in Lluis de Requesens Secondari School. 
+
+Tacher: Lluis Nadal.
+Students: Agnes Garriga, Manel Tuells.
+
+**************************************************************************************************************************
+
+Sensor: MQ-3 alcohol sensor.(http://www.sparkfun.com/;  http://www.bricogeek.com/shop/).
+
+MQ-3 sensor wiring:
+H1(5V), H2(ground), A(5V), B (R load = 500 Ohm - 1%), R load (mBed pin 20 - ground).
+
+Analog out (for datalogger or multimeter): mBed pin 18 (1V = 1000 ppm).
+
+
+
+MQ-3 sensor response is not linear. Calibration was done by passing air (with a fishtank air pump)  through a dilute solution of ethanol in water.
+The resulting air saturated of ethanol vapor and water vapor, was continuously introduced in an open container containing the sensor. Th voltage across a load resistor was measured.
+
+A 500 Ohm-1% load resistor was selected in order to achieve a measuring range of 3000 ppm.
+
+After a bit difficult calculations, the sensor response was aproximated in a five degree polynomial:
+
+X = V(in)
+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
+
+
+For more accurate readins is recommended a minimum heating time of 5 minutes (24 hours is recommended for the manufacturer) but 1 minute give satisfactory results.
+After heating, the sensor is autozeroed by averaging 5 measures.
+
+In heating and in autozero operations the sensor must be left away of alcohol vapors! 
+
+ 
+THIS FREE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. ENJOY IT.
+
+*/
+//**********************************************************************************************
+
+
+#include "mbed.h"
+#include "TextLCD.h"
+#include <sstream>
+using namespace std;
+
+
+
+
+float concentration (float x){
+
+const float A[] = { 2.71494E+02, -3.10999E+02, 6.85051E+02, -3.47587E+02, 7.47499E+01}; 
+float result;
+float B[4];
+B[0] = x*x;
+B[1] = B[0]*x;
+B[2] = B[1]*x;
+B[3] = B[2]*x;
+
+result = A[0]*x+A[1]*B[0]+A[2]*B[1]+A[3]*B[2]+A[4]*B[3];
+return result;
+}
+
+
+
+
+char messages[5][16] = {"Heating sensor", "64 seconds", "Autozero", "Ready!", "ppm"};
+
+
+int L;
+float x;
+float x0[5];
+float x_initial;
+
+TextLCD lcd(p24, p26, p27, p28, p29, p30); // Wiring microcontroller - LCD:
+// rs(4), e(6), d4(11), d5(12), d6(13), d7(14) (R/W(5) a 0)
+
+DigitalIn pushbutton = p8; // Pushbutton (normally open). Stops initial heating time when it is pressed. .
+AnalogOut output(p18); // Analog output to a multimeter or datalogger (1V = 1000 ppm).
+
+
+
+void text_screen( char message[],  int colum, int row) {
+
+lcd.locate( colum, row);
+lcd.printf(message);
+
+}
+
+
+
+int main() {
+
+output = 0.0;
+lcd.cls();
+
+text_screen(messages[0], 0, 0);
+text_screen(messages[1], 0, 1);
+wait(2);
+
+
+
+for (int j = 0; j<4; j++){
+
+lcd.cls();  // Heating sensor 4x16 = 64 seconds
+text_screen(messages[0], 0, 0);
+
+
+for (int i = 0; i<16; i++){  
+if (pushbutton == 1){   // Pressing pushbutton stops initial heating and enters in measuring mode.
+ break;
+  }
+ lcd.locate(i, 1);
+ lcd.putc(62);
+wait(1);
+}
+}
+
+lcd.cls();
+text_screen(messages[2], 0, 0);
+wait(2);
+
+
+AnalogIn value(p20); // Reads sensor voltage as a float int the interval (0-1) corresponding to (0 - 3.3V).
+
+
+
+for (int i=0; i<5; i++){
+
+x0[i] = value;
+wait(2);
+
+}
+x_initial = (x0[0]+x0[1]+x0[2]+x0[3]+x0[4])/5.0; // Autozero. Average of 5 initial measures.
+
+lcd.cls();
+text_screen(messages[3], 0, 0);
+wait(2);
+
+while(1) {
+x = value;
+x = (x-x_initial)*3.3; // Calculate real voltage. 
+
+if(x<0) x = 0;
+
+x = concentration(x);
+
+output = x/3000;  // If analog readings do not match digital readings you can adjust this value (1000 ppm = 1V).
+
+wait(0.1);
+
+// Float to string conversion.
+stringstream ss (stringstream::in | stringstream::out);
+ss <<x;
+string reading = ss.str();
+L = reading.length();
+
+
+lcd.cls();
+for (int i=0; i<L; i+=1){
+lcd.locate(i,0);
+lcd.putc(reading[i]); 
+
+
+
+text_screen(messages[4], 10, 0);
+}
+wait(2);
+}
+}