Built-in project · Arduino Uno R3

Fever thermometer on an Arduino Uno

An MLX90614 reads a forehead without touching it; an I2C LCD shows the temperature, and over 38 C it says FEVER and beeps. The whole build, an Arduino Uno and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Beginner About 20 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $43. On Mokxi they're free.

Step by step, with the wiring and the common mistakes: Arduino MLX90614: Non-Contact IR Thermometer

The circuit runs here once the page has loaded.

What you'll learn

  • Reading an infrared temperature sensor over I2C
  • Sharing one I2C bus between two devices with different addresses
  • Working in whole tenths of a degree instead of floats
  • Using a threshold to trigger a warning
  • Difficulty: Beginner
  • Time: About 20 minutes
  • Board: Arduino Uno R3
  • Parts: 5

How it works

An MLX90614 sensor measures the temperature of whatever it points at, using infrared, without touching it. It also reports its own temperature, which is the room. It shares the I2C bus with the LCD on A4 and A5.

Every half second the sketch reads both temperatures and rounds them to tenths of a degree. The LCD shows the forehead temperature on the first line and the room on the second. The same numbers also go to the serial monitor.

If the object temperature is above 38.0 C, the first line says FEVER instead of Temp, and the piezo on pin 8 beeps.

Parts list

5 parts, plus the jumper wires. They retail for about $43; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
IR thermometer, MLX90614 pin SCLArduino Uno R3 pin SCL
IR thermometer, MLX90614 pin SDAArduino Uno R3 pin SDA
Piezo speaker pin 1Arduino Uno R3 pin 8
IR thermometer, MLX90614 pin VINArduino Uno R3 pin 5V
Character LCD with I2C backpack pin VCCArduino Uno R3 pin 5V
IR thermometer, MLX90614 pin GNDArduino Uno R3 pin GND
Character LCD with I2C backpack pin GNDArduino Uno R3 pin GND
Piezo speaker pin 2Arduino Uno R3 pin GND
Character LCD with I2C backpack pin SDAArduino Uno R3 pin A4
Character LCD with I2C backpack pin SCLArduino Uno R3 pin A5

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Fever thermometer: an MLX90614 infrared thermometer, a 16x2 I2C LCD and a
// piezo.
//
//   SDA, SCL  the MLX90614 (0x5A) and the LCD backpack (0x27), one bus
//   pin 8     the piezo; its other leg to ground
//
// The MLX90614 reads the temperature of what it is pointed at without
// touching it, here a forehead a couple of centimeters away, and its own
// (the ambient). Twice a second the LCD shows both; over 38.0 C the first
// line says FEVER and the piezo beeps.
//
// readObjectTempC() returns a float; the sketch works in tenths of a degree
// so the comparison and the display are whole numbers.

#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <LiquidCrystal_I2C.h>

const int PIEZO = 8;
const int FEVER_TENTHS = 380;

Adafruit_MLX90614 mlx = Adafruit_MLX90614();
LiquidCrystal_I2C lcd(0x27, 16, 2);

void printTenths(int tenths) {
  if (tenths < 0) {
    lcd.print('-');
    tenths = -tenths;
  }
  lcd.print(tenths / 10);
  lcd.print('.');
  lcd.print(tenths % 10);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: fever thermometer");
  lcd.init();
  lcd.backlight();
  if (!mlx.begin()) {
    lcd.print("No MLX90614");
    Serial.println("no MLX90614: check SDA, SCL and power");
    while (1) delay(10);
  }
}

void loop() {
  int object = (int)(mlx.readObjectTempC() * 10.0 + 0.5);
  int ambient = (int)(mlx.readAmbientTempC() * 10.0 + 0.5);
  bool fever = object > FEVER_TENTHS;

  lcd.setCursor(0, 0);
  lcd.print(fever ? "FEVER " : "Temp  ");
  printTenths(object);
  lcd.print(" C   ");
  lcd.setCursor(0, 1);
  lcd.print("Room  ");
  printTenths(ambient);
  lcd.print(" C   ");

  Serial.print("forehead ");
  Serial.print(object / 10);
  Serial.print('.');
  Serial.print(object % 10);
  Serial.print(" C");
  Serial.println(fever ? "  FEVER" : "");
  if (fever) tone(PIEZO, 2000, 150);
  delay(500);
}

Code walkthrough

The key functions of the sketch, and what each one does.

printTenths sketch.ino

Prints a temperature stored in tenths as a normal decimal. It handles a minus sign first, then prints the whole degrees with tenths / 10, a dot, and the last digit with tenths % 10. Whole numbers avoid float printing trouble.

void printTenths(int tenths) {
  if (tenths < 0) {
    lcd.print('-');
    tenths = -tenths;
  }
  lcd.print(tenths / 10);
  lcd.print('.');
  lcd.print(tenths % 10);
}

setup sketch.ino

Starts the LCD and its backlight, then calls mlx.begin. If the sensor does not answer, the LCD says No MLX90614 and the sketch stops in an endless loop, so a loose wire is easy to spot.

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: fever thermometer");
  lcd.init();
  lcd.backlight();
  if (!mlx.begin()) {
    lcd.print("No MLX90614");
    Serial.println("no MLX90614: check SDA, SCL and power");
    while (1) delay(10);
  }
}

loop sketch.ino

Reads the object and ambient temperatures, multiplies by 10 and adds 0.5 to round. Then it sets fever when the object reading is above FEVER_TENTHS. It updates both LCD lines, prints to serial, beeps with tone if there is a fever, and waits 500 ms.

void loop() {
  int object = (int)(mlx.readObjectTempC() * 10.0 + 0.5);
  int ambient = (int)(mlx.readAmbientTempC() * 10.0 + 0.5);
  bool fever = object > FEVER_TENTHS;

  lcd.setCursor(0, 0);
  lcd.print(fever ? "FEVER " : "Temp  ");
  printTenths(object);
  lcd.print(" C   ");
  lcd.setCursor(0, 1);
  lcd.print("Room  ");
  printTenths(ambient);
  lcd.print(" C   ");

  Serial.print("forehead ");
  Serial.print(object / 10);
  Serial.print('.');
  Serial.print(object % 10);
  Serial.print(" C");
  Serial.println(fever ? "  FEVER" : "");
  if (fever) tone(PIEZO, 2000, 150);
  delay(500);
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The LCD says No MLX90614. This project
    Check the sensor's SDA and SCL, and that VIN is on 5 V and GND is connected.
  • The LCD stays blank. This project
    The LCD needs its own SDA on A4 and SCL on A5, plus 5 V and GND.
  • FEVER never shows. This project
    The limit is 38.0 C. Raise the sensor's target temperature above that, or lower FEVER_TENTHS to test.
  • The sensor is not found or reads wrong. IR thermometer
    The default I2C address is 0x5A and it uses SMBus, which is slow (up to 100 kHz). Check that the board is the 3.3 V or the 5 V version you expect.
  • The object temperature is off. IR thermometer
    It reads whatever is inside its field of view, not just the spot in the middle. Shiny metal reads low because of emissivity. Get close and aim at a matte surface.
  • The screen stays blank or shows only a row of blocks. Character LCD with I2C backpack
    The I2C address is usually 0x27 or 0x3F. Run an I2C scanner to find yours. Then turn the contrast trimmer on the backpack slowly until text appears.
  • The backlight is on but there is no text, or text is garbled. Character LCD with I2C backpack
    Wire SDA and SCL to the right pins (A4 and A5 on an Uno), power it from 5 V, and call lcd.init() and the backlight call in setup.
  • A passive piezo stays silent when you just set the pin HIGH. Piezo speaker
    A passive piezo needs a changing signal. Use tone(pin, frequency) or a PWM wave. Around 2 to 4 kHz is loudest. A buzzer with a built in oscillator makes sound from plain DC instead.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.