【Digikey好物畅享】MLX90640 获取热成像图像

1.MLX90640 介绍

这是一款 Melexis 推出的高性价比器件,它填补了“单点测温红外传感器”与高分辨率专业热像仪“之间的空白。

MLX90640 本质上是一个 32x24 像素的红外热电堆阵列。

  • 分辨率 768 像素(32x24)

  • 通信接口 I2C (最高支持 1MHz 高速模式)

  • 测量范围 -40摄氏度至300摄氏度

  • 刷新率 0.5Hz 至 60Hz (可编程)

  • 精度 约±1℃(在最佳工作范围内)

  • 工作电压 3.3V (典型值)

我购买的型号是 MLX90640ESF-BAB-000-TU,其中:

  • MLX90640:芯片基础型号;

  • E:表示温度范围 -40℃~85℃

  • SF:表示 TO39 封装

  • BAB:表示 FOV 为 55°x35°

  • 000:表示标准产品

  • TU:表示罐装

1.1管脚

注意,下面这个管脚图是从底部去看,插上面包板或者焊接在PCB上,注意左右要颠倒。

1.2 常见的应用场景

  • 工业检修:寻找配电箱中的异常发热,预防火灾;

  • 智能家居:人体存在感应(比PIR传感器更准,因为它能识别人体停留);

  • 医疗健康:发热筛查、体温初步检测;

  • 隐私监控:在酒店或者公共场所进行人数统计,由于分辨率只有32x24,它能看清人体轮廓但无法识别面部特征,保护了隐私;

2.Arduino 平台获取热成像图像

好在 Arduino 平台有 adafruit/Adafruit MLX90640@^1.1.2 库,安装就能使用。

2.1获取热成像源码

#include <Arduino.h>
#include <Adafruit_MLX90640.h>
#include "bsp_serial.h"

Adafruit_MLX90640 mlx;
float frame[32 * 24]; // buffer for full frame of temperatures

// uncomment *one* of the below
// #define PRINT_TEMPERATURES
#define PRINT_ASCIIART

void setup()
{
    bsp_serial_setup(115200);

    Serial.println("Adafruit MLX90640 Simple Test");
    if (!mlx.begin(MLX90640_I2CADDR_DEFAULT, &Wire))
    {
        Serial.println("MLX90640 not found!");
        while (1)
            delay(10);
    }
    Serial.println("Found Adafruit MLX90640");

    Serial.print("Serial number: ");
    Serial.print(mlx.serialNumber[0], HEX);
    Serial.print(mlx.serialNumber[1], HEX);
    Serial.println(mlx.serialNumber[2], HEX);

    // mlx.setMode(MLX90640_INTERLEAVED);
    mlx.setMode(MLX90640_CHESS);
    Serial.print("Current mode: ");
    if (mlx.getMode() == MLX90640_CHESS)
    {
        Serial.println("Chess");
    }
    else
    {
        Serial.println("Interleave");
    }

    mlx.setResolution(MLX90640_ADC_18BIT);
    Serial.print("Current resolution: ");
    mlx90640_resolution_t res = mlx.getResolution();
    switch (res)
    {
    case MLX90640_ADC_16BIT:
        Serial.println("16 bit");
        break;
    case MLX90640_ADC_17BIT:
        Serial.println("17 bit");
        break;
    case MLX90640_ADC_18BIT:
        Serial.println("18 bit");
        break;
    case MLX90640_ADC_19BIT:
        Serial.println("19 bit");
        break;
    }

    mlx.setRefreshRate(MLX90640_2_HZ);
    Serial.print("Current frame rate: ");
    mlx90640_refreshrate_t rate = mlx.getRefreshRate();
    switch (rate)
    {
    case MLX90640_0_5_HZ:
        Serial.println("0.5 Hz");
        break;
    case MLX90640_1_HZ:
        Serial.println("1 Hz");
        break;
    case MLX90640_2_HZ:
        Serial.println("2 Hz");
        break;
    case MLX90640_4_HZ:
        Serial.println("4 Hz");
        break;
    case MLX90640_8_HZ:
        Serial.println("8 Hz");
        break;
    case MLX90640_16_HZ:
        Serial.println("16 Hz");
        break;
    case MLX90640_32_HZ:
        Serial.println("32 Hz");
        break;
    case MLX90640_64_HZ:
        Serial.println("64 Hz");
        break;
    }
}

void loop()
{
    delay(500);
    Serial.println("Capturing frame...");
    if (mlx.getFrame(frame) != 0)
    {
        Serial.println("Failed");
        return;
    }
    Serial.println("===================================");
    Serial.print("Ambient temperature = ");
    Serial.print(mlx.getTa(false)); // false = no new frame capture
    Serial.println(" degC");
    Serial.println();
    Serial.println();
    for (uint8_t h = 0; h < 24; h++)
    {
        for (uint8_t w = 0; w < 32; w++)
        {
            float t = frame[h * 32 + w];

#ifdef PRINT_TEMPERATURES
            Serial.print(t, 1);
            Serial.print(", ");
#endif

#ifdef PRINT_ASCIIART
            char c = '&';
            if (t < 20)
                c = ' ';
            else if (t < 23)
                c = '.';
            else if (t < 25)
                c = '-';
            else if (t < 27)
                c = '*';
            else if (t < 29)
                c = '+';
            else if (t < 31)
                c = 'x';
            else if (t < 33)
                c = '%';
            else if (t < 35)
                c = '#';
            else if (t < 37)
                c = 'X';
            Serial.print(c);
#endif
        }
        Serial.println();
    }
}

2.2 流程图

2.3硬件连接

注意,SCL/SDA 分别外接上拉电阻 10KΩ,否则通信不稳定,无法获取数据。

2.4串口打印

␛[0;32mI (613) esp_image: segment 0: paddr=00010020 vaddr=3c030020 size=0e23ch ( 57916) map␛[0m
␛[0;32mI (622) esp_image: segment 1: paddr=0001e264 vaddr=3fc92980 size=01db4h (  7604) load␛[0m
␛[0;32mI (624) esp_image: segment 2: paddr=00020020 vaddr=42000020 size=28550h (165200) map␛[0m
␛[0;32mI (653) esp_image: segment 3: paddr=00048578 vaddr=3fc94734 size=018bch (  6332) load␛[0m
␛[0;32mI (654) esp_image: segment 4: paddr=00049e3c vaddr=40374000 size=0e980h ( 59776) load␛[0m
␛[0;32mI (676) boot: Loaded app from partition at offset 0x10000␛[0m
␛[0;32mI (676) boot: Disabling RNG early entropy source...␛[0m
E (694) esp_core_dump_flash: No core dump partition found!
E (695) esp_core_dump_flash: No core dump partition found!
Serial started
Adafruit MLX90640 Simple Test
Outlier pixels: 5
Found Adafruit MLX90640
Serial number: 182B9C6418B
Current mode: Chess
Current resolution: 18 bit
Current frame rate: 2 Hz
Capturing frame...

2.5石头剪刀布的热成像

分别在传感器上方摆出石头剪刀布,串口打印出对应的热成像图形。

石头

剪刀

3.总结

这款 MLX90640 真是热成像界的“小钢炮”!虽然 $$32 \times 2$$ 像素看起来不高,但它能精准捕捉人体温差,还能完美避开隐私风险。

我买的 BAB 型号是 55°x35° 标准视角,比起广角版,它更像自带“变焦”,近距离观察时细节更扎实,这也是为什么我能用它流畅识别“石头剪刀布”的原因。配合官方驱动库搞定复杂的红外补偿后,无论是做手势交互还是人体感应,它都是一套极具性价比的硬核方案。