Built-in project · Arduino Uno R3

Thermal camera on an Arduino Uno

An AMG8833 Grid-EYE sees an 8x8 picture of temperatures and an ST7735 paints it in a thermal palette, hottest pixel underneath. The whole build, an Arduino Uno and 2 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.

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

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

The circuit runs here once the page has loaded.

What you'll learn

  • Reading a thermal sensor over I2C
  • Mapping temperature to a color palette
  • Driving a color TFT over SPI
  • Drawing only what changed
  • Finding the maximum in an array
  • Difficulty: Intermediate
  • Time: About 30 minutes
  • Board: Arduino Uno R3
  • Parts: 4

How it works

An AMG8833 Grid-EYE sensor reports 64 temperatures, an 8 by 8 picture, ten times a second. The sketch reads them over I2C and paints each one as a 16 by 16 pixel square on a 1.8 inch ST7735 screen.

The color comes from a thermal palette: blue at 20 C, through purple and red to orange, and yellow at 36 C and above. The hottest reading is printed under the picture. To save time, the sketch only repaints a square when its color changes.

Parts list

4 parts, plus the jumper wires. They retail for about $77; 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
Thermal camera, AMG8833 pin SCLArduino Uno R3 pin SCL
Thermal camera, AMG8833 pin SDAArduino Uno R3 pin SDA
TFT display, 1.8 inch ST7735 pin SCKArduino Uno R3 pin 13
TFT display, 1.8 inch ST7735 pin SDAArduino Uno R3 pin 11
TFT display, 1.8 inch ST7735 pin CSArduino Uno R3 pin 10
TFT display, 1.8 inch ST7735 pin A0Arduino Uno R3 pin 9
TFT display, 1.8 inch ST7735 pin RESETArduino Uno R3 pin 8
Thermal camera, AMG8833 pin VINArduino Uno R3 pin 5V
TFT display, 1.8 inch ST7735 pin VCCArduino Uno R3 pin 5V
TFT display, 1.8 inch ST7735 pin LEDArduino Uno R3 pin 5V
Thermal camera, AMG8833 pin GNDArduino Uno R3 pin GND
TFT display, 1.8 inch ST7735 pin GNDArduino Uno R3 pin GND

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
// Thermal camera: an AMG8833 Grid-EYE and an ST7735 color screen.
//
//   SDA, SCL       the AMG8833 (address 0x69), VIN and GND from the rails
//   pins 10, 9, 8  the screen's CS, A0 (DC) and RESET
//   pins 11, 13    the screen's SDA (MOSI) and SCK; VCC and LED from the rails
//
// The Grid-EYE gives sixty-four temperatures ten times a second. Each one is
// painted as a 16x16 square, eight across and eight down, in a thermal
// palette from blue at 20 C through red to yellow at 36 C and over, so a
// hand stands out against a room. The hottest pixel's temperature is written
// under the picture.
//
// The screen is driven a pixel at a time over the pins, so a frame takes a
// while; the sketch only repaints the squares whose color changed.

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_AMG88xx.h>

Adafruit_ST7735 tft(10, 9, 8);
Adafruit_AMG88xx amg;

float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
uint16_t shown[AMG88xx_PIXEL_ARRAY_SIZE];
int lastHot = -1000;

// 20 C to 36 C onto blue, purple, red, orange, yellow.
uint16_t colorFor(float c) {
  int t = (int)((c - 20.0) * 16.0); // 0..256 over 16 degrees
  if (t < 0) t = 0;
  if (t > 255) t = 255;
  uint8_t r, g, b;
  if (t < 64) {
    r = (uint8_t)(t * 2); g = 0; b = (uint8_t)(128 + t);
  } else if (t < 128) {
    r = (uint8_t)(128 + (t - 64) * 2); g = 0; b = (uint8_t)(192 - (t - 64) * 3);
  } else if (t < 192) {
    r = 255; g = (uint8_t)((t - 128) * 2); b = 0;
  } else {
    r = 255; g = (uint8_t)(128 + (t - 192) * 2); b = (uint8_t)((t - 192) * 3);
  }
  return tft.color565(r, g, b);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: thermal camera");
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST77XX_BLACK);
  if (!amg.begin()) {
    Serial.println("no AMG8833: check SDA, SCL and power");
    while (1) delay(10);
  }
  for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) shown[i] = 0xFFFF;
  delay(100);
}

void loop() {
  amg.readPixels(pixels);
  float hottest = pixels[0];
  int where = 0;
  for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) {
    if (pixels[i] > hottest) {
      hottest = pixels[i];
      where = i;
    }
    uint16_t color = colorFor(pixels[i]);
    if (color != shown[i]) {
      shown[i] = color;
      tft.fillRect((i % 8) * 16, (i / 8) * 16, 16, 16, color);
    }
  }
  int hot = (int)(hottest * 10.0 + 0.5);
  if (hot != lastHot) {
    lastHot = hot;
    tft.fillRect(0, 132, 128, 16, ST77XX_BLACK);
    tft.setCursor(4, 134);
    tft.setTextColor(ST77XX_WHITE);
    tft.setTextSize(1);
    tft.print("hottest ");
    tft.print(hot / 10);
    tft.print('.');
    tft.print(hot % 10);
    tft.print(" C");
    Serial.print("hottest ");
    Serial.print(hot / 10);
    Serial.print('.');
    Serial.print(hot % 10);
    Serial.print(" C at row ");
    Serial.print(where / 8);
    Serial.print(", column ");
    Serial.println(where % 8);
  }
  delay(100);
}

Code walkthrough

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

colorFor sketch.ino

Takes a temperature and scales 20 C to 36 C onto 0 to 255, clamping outside that range. Then it picks red, green and blue values from four bands to make blue, purple, red, orange and yellow.

// 20 C to 36 C onto blue, purple, red, orange, yellow.
uint16_t colorFor(float c) {
  int t = (int)((c - 20.0) * 16.0); // 0..256 over 16 degrees
  if (t < 0) t = 0;
  if (t > 255) t = 255;
  uint8_t r, g, b;
  if (t < 64) {
    r = (uint8_t)(t * 2); g = 0; b = (uint8_t)(128 + t);
  } else if (t < 128) {
    r = (uint8_t)(128 + (t - 64) * 2); g = 0; b = (uint8_t)(192 - (t - 64) * 3);
  } else if (t < 192) {
    r = 255; g = (uint8_t)((t - 128) * 2); b = 0;
  } else {
    r = 255; g = (uint8_t)(128 + (t - 192) * 2); b = (uint8_t)((t - 192) * 3);
  }
  return tft.color565(r, g, b);
}

setup sketch.ino

Starts the screen and clears it to black, then looks for the sensor. If it is missing it prints a message and stops. It then sets every remembered color to a value that forces a first full paint.

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: thermal camera");
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST77XX_BLACK);
  if (!amg.begin()) {
    Serial.println("no AMG8833: check SDA, SCL and power");
    while (1) delay(10);
  }
  for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) shown[i] = 0xFFFF;
  delay(100);
}

loop sketch.ino

Reads the 64 pixels, finds the hottest and repaints each square whose color changed. When the hottest value, rounded to a tenth, changes it redraws the label and prints its row and column.

void loop() {
  amg.readPixels(pixels);
  float hottest = pixels[0];
  int where = 0;
  for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) {
    if (pixels[i] > hottest) {
      hottest = pixels[i];
      where = i;
    }
    uint16_t color = colorFor(pixels[i]);
    if (color != shown[i]) {
      shown[i] = color;
      tft.fillRect((i % 8) * 16, (i / 8) * 16, 16, 16, color);
    }
  }
  int hot = (int)(hottest * 10.0 + 0.5);
  if (hot != lastHot) {
    lastHot = hot;
    tft.fillRect(0, 132, 128, 16, ST77XX_BLACK);
    tft.setCursor(4, 134);
    tft.setTextColor(ST77XX_WHITE);
    tft.setTextSize(1);
    tft.print("hottest ");
    tft.print(hot / 10);
    tft.print('.');
    tft.print(hot % 10);
    tft.print(" C");
    Serial.print("hottest ");
  // ... 10 more lines in the editor

Troubleshooting

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

  • The sketch says no AMG8833 This project
    Check SDA and SCL between the Uno and the sensor, and its VIN and GND.
  • The screen stays black This project
    Check CS on pin 10, A0 on pin 9, RESET on pin 8, SCK on pin 13, SDA on pin 11, and that LED and VCC are on 5V.
  • Everything is one color This project
    The palette only covers 20 C to 36 C. A room outside that range clamps to the end colors.
  • The sensor is not found on I2C. The address is 0x69 by default, or 0x68 when the AD_SELECT pin is tied to ground, and many scanners miss the other. Thermal camera
    Scan the bus and use the address you find. Connect SDA and SCL to the right pins with pull-ups to 3.3 V, and join the grounds.
  • The image is blocky and slow, or the values look odd. It has only 8 by 8 pixels at up to 10 frames per second, and the reading is in 0.25 C steps. Thermal camera
    Read the 64 pixels over I2C at no more than 10 Hz. Interpolate to smooth the picture. Power it from 3.3 V, since the chip is a 3.3 V part.
  • The screen is blank or white. TFT display
    Check all the SPI wires: SCK, MOSI, CS, DC and RST, plus power and the backlight pin. Many modules need the LED pin tied to 3.3 V, with a resistor on some. Use the right library init.
  • Colors are wrong, or the picture is shifted with a noisy edge. TFT display
    Pick the tab color your library asks for, such as INITR_BLACKTAB or GREENTAB, until the picture is clean. Swap red and blue if the colors are reversed. Rotation changes the offset.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.

Change it and keep it

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