NederlandsKlik deze knop voor de Nederlandstalige website

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.

MQ-3 gas sensor on breakout board for Arduino
MQ-3 gas sensor on breakout board for Arduino

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
Breadboard view
Breadboard view

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;
}
MQ-3 sensor, OLED display and leds, detail.
MQ-3 sensor, OLED display and leds, detail.
0.96 Inch White SPI OLED Display Module 12864 LED For Arduino
Tested and recommended by OneGuyOneBlog.com:

0.96 Inch White SPI OLED Display Module 12864 LED For Arduino
Geekcreit® UNO R3 ATmega328P Development Board For Arduino
Tested and recommended by OneGuyOneBlog.com:

Geekcreit® UNO R3 ATmega328P Development Board For Arduino

Add a Comment

Your email address will not be published. Required fields are marked *