Arduino breathalyzer: DIY alcohol tester with MQ-3 gas sensor and OLED display
|
One of the fun things about Arduino is the availability of many types of sensors. With those sensors you are able to measure and detect about anything. Most of them are cheap and easy to use. Usually only a couple of wires and a few lines of code are required to incorporate them into your project. One of those sensors is the MQ-3 gas sensor, which detects alcohol. I got my sensor from VNG Systems. Together with some LEDs and the OLED display featured in the previous blog post you can build your own Arduino breathalyzer.
Arduino breathalyzer: the MQ-3 gas sensor
The MQ-3 gas sensor uses a small heater inside with an electro-chemical sensor. It is used indoors at room temperature. It can be calibrated more or less but a know concentration of the measured gas or gasses is needed for that. The output is an analog signal and can be read with an analog input of the Arduino. In this tutorial I use the “MQ-3 Alcohol Ethanol Sensor Breath Gas Detection Module For Arduino” on a breadboard-friendly breakout board.


The sensor will become more accurate after some use. Some datasheets use the term “preheat”, but it is the time to burn-in the sensor. This is meant to make the sensor readings more consistent. A time of 12 or 24 hours is usually used for the burn-in time. The Burn-in is achieved by applying normal power to the sensor. Hook up the sensor as follows:
MQ-3 | Arduino |
AD | A0 |
DD | (not connected) |
GND | GND |
VCC | 5V |
The OLED display
In this tutorial we will use a 6-pin SPI version of the 128×64 OLED display together with the Adafruit SSD1306 library. For details, see the previous post “Adding a 128×64 pixels white OLED display to your Arduino project“. Hook up the display as stated below:
OLED | Arduino |
GND | GND |
VCC | 5V |
SCL | D10 |
SDA | D9 |
RES | D13 |
DC | D11 |
The LEDs
Hook up the LEDs to the Arduino’s digital pins D2 to D6. Do not forget the current limiting resistors. I used 470 Ohm resistors, but you can also use 220 Ohm ones.
LED | Arduino |
1 Green | D6 |
2 Green | D5 |
3 Yellow | D4 |
4 Yellow | D3 |
5 Red | D2 |


Arduino breathalyzer code
This is the sketch, you should adapt it to your own needs. TIME_UNTIL_WARMUP is set to 15 minutes. You might want to lower this value to around 3 minutes after some use. The thresholds for ‘value’ are just an indication, you should experiment with your sensor to find the values you need.
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // OLED pins, using software SPI: #define OLED_MOSI 9 #define OLED_CLK 10 #define OLED_DC 11 #define OLED_CS 12 #define OLED_RESET 13 Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); #if (SSD1306_LCDHEIGHT != 64) #error("Height incorrect, please fix Adafruit_SSD1306.h!"); #endif int TIME_UNTIL_WARMUP = 900; // warm up for 15 minutes! unsigned long time; int analogPin = 0; int val = 0; // LED pins int led1 = 2; // Red int led2 = 3; // Yellow int led3 = 4; // Yellow int led4 = 5; // Green int led5 = 6; // Green int ledState = LOW; unsigned long previousMillis = 0; long blinkInterval = 250; void setup() { pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); pinMode(led4, OUTPUT); pinMode(led5, OUTPUT); digitalWrite(led1, LOW); digitalWrite(led2, LOW); digitalWrite(led3, LOW); digitalWrite(led4, LOW); digitalWrite(led5, LOW); Serial.begin(9600); display.begin(SSD1306_SWITCHCAPVCC); display.clearDisplay(); } void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= blinkInterval) { // save the last time you blinked the LED previousMillis = currentMillis; // if the LED is off turn it on and vice-versa: if (ledState == LOW) { ledState = HIGH; } else { ledState = LOW; } } delay(100); val = readAlcohol(); printTitle(); printWarming(); time = millis() / 1000; if (time <= TIME_UNTIL_WARMUP) { time = map(time, 0, TIME_UNTIL_WARMUP, 0, 100); display.drawRect(10, 50, 110, 10, WHITE); //Empty Bar display.fillRect(10, 50, time, 10, WHITE); } else { printTitle(); printAlcohol(val); printAlcoholLevel(val); } display.display(); } void printTitle() { display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(22, 0); display.println("Breathalyzer"); } void printWarming() { display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(0, 20); display.println("Warming up"); } void printAlcohol(int value) { display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(45, 25); display.println(val); } void printAlcoholLevel(int value) { display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(10, 55); if (value < 250) { display.println("You are sober."); digitalWrite(led1, LOW); digitalWrite(led2, LOW); digitalWrite(led3, LOW); digitalWrite(led4, LOW); digitalWrite(led5, HIGH); } if (value >= 250 && value < 300) { display.println("One beer."); digitalWrite(led1, LOW); digitalWrite(led2, LOW); digitalWrite(led3, LOW); digitalWrite(led4, HIGH); digitalWrite(led5, HIGH); } if (value >= 300 && value < 350) { blinkInterval = 750; // blinking slow display.println("2+ beers."); digitalWrite(led1, LOW); digitalWrite(led2, LOW); digitalWrite(led3, ledState); // blinking yellow LED digitalWrite(led4, HIGH); digitalWrite(led5, HIGH); } if (value >= 350 && value < 450) { blinkInterval = 250; // blinking faster display.println("Many beers!"); digitalWrite(led1, LOW); digitalWrite(led2, ledState); // blinking yellow LED digitalWrite(led3, HIGH); digitalWrite(led4, HIGH); digitalWrite(led5, HIGH); } if (value > 450) { blinkInterval = 25; // blinking fast display.println("You are drunk!"); digitalWrite(led1, ledState); // blinking red LED digitalWrite(led2, HIGH); digitalWrite(led3, HIGH); digitalWrite(led4, HIGH); digitalWrite(led5, HIGH); } } int readAlcohol() { int val = 0; int val1; int val2; int val3; display.clearDisplay(); val1 = analogRead(analogPin); delay(10); val2 = analogRead(analogPin); delay(10); val3 = analogRead(analogPin); val = (val1 + val2 + val3) / 3; return val; }

