MLX90614 + OLED Display: Simple Non-Contact Temperature Reader and calibration issue

Hi everyone,

I’ve been working on a compact non-contact temperature measurement project using the MLX90614 infrared sensorand an SSD1306 OLED display. The goal was to create a straightforward temperature gun setup that could show live object temperature readings directly on an OLED.

:toolbox: Hardware Used:

  • Arduino (Nano or Uno)
  • Adafruit MLX90614 IR Temperature Sensor
  • 0.96" I2C OLED Display (128x64)
  • Breadboard + Wires

:electric_plug: Wiring:

  • MLX90614 and OLED both use I2C, so:
    • VCC → 3.3V or 5V (depending on your breakout)
    • GND → GND
    • SDA → A4 (on Uno/Nano)
    • SCL → A5 (on Uno/Nano)

:laptop: Code:

#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Adafruit_MLX90614 mlx = Adafruit_MLX90614();

void setup() {
Serial.begin(9600);
delay(2000); // Let sensors power up

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
Serial.println(F("OLED not found"));
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("MLX90614 Temp Sensor");
display.display();
delay(1500);
}

if (!mlx.begin()) {
Serial.println(F("MLX90614 not found"));
}
}

void loop() {
float ambient = mlx.readAmbientTempC();
float object = mlx.readObjectTempC();

Serial.print("Ambient Temp: ");
Serial.print(ambient);
Serial.print(" °C | Object Temp: ");
Serial.print(object);
Serial.println(" °C");

display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Object Temp:");
display.setTextSize(2);
display.setCursor(0, 20);
display.print(object, 1);
display.cp437(true);
display.write(248); // Degree symbol
display.println("C");
display.display();

delay(1000);
}

Calibration and Accuracy: Why Add 4°C?

Most commercial infrared temperature guns—especially those used for medical screening—are not just displaying the raw skin temperature. Instead, they’re calibrated to estimate core body temperature, which is generally 3–5°C higherthan the temperature measured on the skin or forehead surface.

This is important because:

  • Skin temperature fluctuates due to ambient conditions (e.g. weather, wind, sweating).
  • But core temperature is more stable and medically relevant (e.g. fever detection).
  • So many IR thermometers add a fixed offset (typically 3–5°C) to bridge this gap.

:hammer_and_wrench: Adding a 4°C Offset in Code

To simulate this behaviour, I’ve modified my code to add 3 degrees Celsius to the object temperature before displaying it on the OLED. This simulates how a commercial thermometer might function.
code:
#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED display config
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Temperature sensor
Adafruit_MLX90614 mlx = Adafruit_MLX90614();

// Buzzer pin
const int buzzerPin = 8;

// Fever threshold
const float FEVER_THRESHOLD = 38.0;

void setup() {
Serial.begin(9600);
delay(1000); // Power-up delay

pinMode(buzzerPin, OUTPUT);
digitalWrite(buzzerPin, LOW);

// Initialise OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
Serial.println(F("OLED not found"));
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Starting Sensor...");
display.display();
delay(1500);
}

// Initialise temperature sensor
if (!mlx.begin()) {
Serial.println(F("MLX90614 not found"));
}
}

void loop() {
float objectTemp = mlx.readObjectTempC();
float coreTemp = objectTemp + 3.0; // Adjust to estimate core body temp

Serial.print("Raw Temp: ");
Serial.print(objectTemp);
Serial.print(" °C | Core Temp Est.: ");
Serial.println(coreTemp);

// Check for fever
if (coreTemp >= FEVER_THRESHOLD) {
tone(buzzerPin, 1000, 500); // 1000Hz tone for 500ms
}

// Update display
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Body Temp (Est):");

display.setTextSize(2);
display.setCursor(0, 20);
display.print(coreTemp, 1);
display.cp437(true);
display.write(248); // Degree symbol
display.println("C");

// Optional status message
display.setTextSize(1);
display.setCursor(0, 50);
if (coreTemp >= FEVER_THRESHOLD) {
display.println("Warning: Fever Detected!");
} else {
display.println("Temperature Normal");
}

display.display();
delay(2000); // Refresh every 2 seconds
}

Hi, @lukesaheed20
Welcome to the forum.

https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum

The link will show you how to place your code in your post with its own scrolling window, this makes it easier to read.

Tom.... :smiley: :+1: :coffee: :australia:

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.