跳转至

49 mlx90640-红外热成像测温

一、概述

mlx90640 是 LuatOS 的红外热成像传感器驱动库,对应 Melexis MLX90640(32×24 像素、768 点红外阵列,I2C 接口、固定地址 0x33)。库本身不负责 I2C 初始化,初始化、读帧、伪彩上屏这几步要开发者自己串起来。

mlx90640 库主要功能:

1、初始化:指定 I2C 总线(硬件 I2C id 或软 I2C 对象)与刷新率;

2、读帧:feed() 取一帧,之后所有取值接口都以这一帧为准;

3、取值:整幅矩阵、单点温度、最高/最低温及其位置、外壳温度、传感器供电电压;

4、上屏:把 768 点温度映射成伪彩,直接画到 lcd 上(可整数倍放大)。

注意事项:

1、本库编译开关是 LUAT_USE_MLX90640,当前公开固件的支持表里没有列出该库,使用前请先在目标固件的支持列表里确认;不包含时只能自行编译固件;

2、init() 不会帮你 i2c.setup(),2023.5.15 之后必须先自己初始化 I2C 总线;

3、draw2lcd() 依赖 lcd 库,必须先 lcd.init() 好屏幕;伪彩固定按 20℃~35℃ 映射,超出这个区间会被截断到端点色。

二、核心示例

-- 注意:需固件包含 mlx90640 库;lcd 部分按自己屏幕的初始化参数写
local i2cid = 0
i2c.setup(i2cid, i2c.SLOW)

if mlx90640.init(i2cid, mlx90640.FPS4HZ) then
    log.info("mlx90640", "init ok")
    sys.wait(500)                       -- 上电后稍等,等传感器内部稳定
    while true do
        mlx90640.feed()                 -- 取一帧,后面所有取值都基于这一帧
        local tmax, pos = mlx90640.max_temp()
        log.info("mlx", "max", tmax, "pos", pos)
        mlx90640.draw2lcd(0, 0, 1)      -- 画到屏幕左上角,1 倍(不放大)
        sys.wait(250)                   -- 4Hz 对应 250ms
    end
else
    log.info("mlx90640", "init fail")
end

只取数值不上屏时,可以把 draw2lcd 去掉,用 raw_point(index) 读关心的点,或 raw_data() 拿整幅矩阵自己处理。

三、常量详解

mlx90640 的常量都是刷新率枚举,直接传给 init() 的第二个参数。数值上是一个位标志(1、2、4、…、64),不要自己算别的值传进去。

常量 数值 含义
mlx90640.FPS1HZ 0x01 1Hz 刷新
mlx90640.FPS2HZ 0x02 2Hz 刷新
mlx90640.FPS4HZ 0x04 4Hz 刷新(常用,init 不给参数时的默认值)
mlx90640.FPS8HZ 0x08 8Hz 刷新
mlx90640.FPS16HZ 0x10 16Hz 刷新
mlx90640.FPS32HZ 0x20 32Hz 刷新
mlx90640.FPS64HZ 0x40 64Hz 刷新

刷新率越高,单帧噪声越大、功耗越高;做人体测温、存在检测这类应用一般用 1~4Hz 就够。

四、函数详解

4.1 mlx90640.init(i2c_id, refresh_rate)

功能

初始化 MLX90640:建立 I2C 通道、读出厂校准参数、按指定刷新率启动测量。2023.5.15 之后使用该接口时,需要用户自己先初始化 I2C。

参数

i2c_id

参数含义:传感器所在的 I2C 总线
数据类型:number(硬件 I2C 的 id)或 userdata(软 I2C 对象)
取值范围:硬件 I2C 通常为 0/1;也可传 i2c.createSoft() 返回的对象
是否必选:否,默认 0
注意事项:传硬件 id 前必须先 i2c.setup();传感器地址固定 0x33,不受 7 位地址配置影响。

refresh_rate

参数含义:测量刷新率
数据类型:number
取值范围:mlx90640.FPS1HZ ~ mlx90640.FPS64HZ
是否必选:否,默认 FPS4HZ
注意事项:只有上面 7 个值有效,不要传任意整数。

返回值

bool:成功返回 true,失败返回 nil 或 false(I2C 没通、校准参数读不出来时会失败)。

示例

i2c.setup(0, i2c.SLOW)
if not mlx90640.init(0, mlx90640.FPS4HZ) then
    log.info("mlx", "init fail, check i2c wiring")
end

注意事项

  1. 传感器上电后需要几百毫秒稳定时间,init 成功后不要立刻读,先 sys.wait(500);

  2. 初始化失败最常见的原因是 SDA/SCL 接反、没有上拉电阻、供电不足(3.3V,峰值电流不小,建议就近加 10uF 以上电容)。

4.2 mlx90640.feed()

功能

从传感器读一帧数据,并完成温度换算与坏点/离群点修正。之后调用 raw_data、raw_point、max_temp、min_temp、average_temp、ta_temp、get_vdd、draw2lcd 拿到的都是这一帧的结果。

参数

无参数。

返回值

无返回值(源码内部虽然压入了布尔值,但返回参数个数为 0,Lua 侧拿到的是 nil,不要用返回值判断成败)。

示例

mlx90640.feed()
local t = mlx90640.raw_point(0)

注意事项

  1. 必须 init 之后调用,未初始化时只会打印 mlx90640 NOT init yet,并从接口直接返回;

  2. 读帧失败(I2C 出错)时也只打一条 GetFrame Error 日志,不抛异常,业务侧要自己用数值合理性兜底;

  3. 取数节奏要跟刷新率匹配:设的是 4Hz 就每 250ms 读一次,读得比刷新率快只会拿到重复帧。

4.3 mlx90640.raw_data([zbuff])

功能

取整幅温度矩阵,共 768 个点(宽 32 × 高 24),单位摄氏度。

参数

zbuff

参数含义:可选的输出缓冲
数据类型:userdata(zbuff)
取值范围:zbuff 剩余空间需能容纳本次写入
是否必选:否
注意事项:不传时返回 table;传了 zbuff 时数据追写到 zbuff 末尾。当前实现按 768 字节拷贝,而完整矩阵是 768 个 float,需要完整数据请用无参数的 table 形式。

返回值

不传 zbuff:table,768 个浮点数温度值,下标从 1 开始(1~768)。

传 zbuff:bool,写入成功返回 true。

示例

-- 方式一:table,推荐
local m = mlx90640.raw_data()
log.info("mlx", m[1], m[768])

-- 方式二:zbuff(注意长度口径,见参数说明)
local buff = zbuff.create(768 * 4)
mlx90640.raw_data(buff)

注意事项

  1. 768 个 float 组成 table 会占不少内存,低内存型号建议按需用 raw_point 逐点取;

  2. 矩阵按行存储,第 row 行第 col 列对应下标 row * 32 + col + 1(row 从 0 开始)。

4.4 mlx90640.raw_point(index)

功能

读单个像素点的温度。

参数

index

参数含义:像素下标
数据类型:number
取值范围:0~767(注意是从 0 开始,与 raw_data 返回 table 的 1 起下标差 1)
是否必选:是
注意事项:源码不做边界检查,越界会读到矩阵之外的内存,务必自己保证范围。

返回值

number:该点温度,单位摄氏度。

示例

-- 读第 1 行第 1 列
local t = mlx90640.raw_point(0)

4.5 mlx90640.ta_temp()

功能

读传感器外壳(环境)温度 Ta,即 MLX90640 自身所处温度,可用于补偿或判断设备是否过热。

参数

无参数。

返回值

number:外壳温度,单位摄氏度。

示例

log.info("mlx", "ta", mlx90640.ta_temp())

注意事项

这个值是传感器自身温度,不是被测物体温度;短时间大量读帧会让 Ta 略高于环境温度。

4.6 mlx90640.max_temp()

功能

在最近一帧里找最高温度点。

参数

无参数。

返回值

number:最高温度,单位摄氏度。

number:最高温所在位置,从 1 开始计数(1~768)。

示例

mlx90640.feed()
local tmax, pos = mlx90640.max_temp()
local t = mlx90640.raw_point(pos - 1)   -- 转成 raw_point 的 0 起下标

注意事项

  1. 位置是 1 起的,而 raw_point 是 0 起的,两者差 1,直接拿 pos 去 raw_point 会偏移一个点;

  2. 必须紧跟在 feed() 之后调用,否则拿到的是上一帧的结果。

4.7 mlx90640.min_temp()

功能

在最近一帧里找最低温度点。

参数

无参数。

返回值

number:最低温度,单位摄氏度。

number:最低温所在位置,从 1 开始计数(1~768)。

示例

local tmin, pos = mlx90640.min_temp()

注意事项

同 max_temp:位置 1 起、需紧跟 feed()。若画面里有冷背景(如窗外、金属件),最低温往往落在这些位置,做存在检测时不要只看最低温。

4.8 mlx90640.average_temp()

功能

统计最近一帧的平均温度。

参数

无参数。

返回值

number:平均温度,单位摄氏度。

示例

local tavg = mlx90640.average_temp()

注意事项

源码的统计方式是按行取平均再对行求平均,但当前实现的累加没有按行偏移,实际只累加了每行起始的同一段像素。因此当画面温度分布不均时,它的结果可能明显偏离 768 点真实均值。需要严谨的均值请自己用 raw_data() 求平均:

local m, sum = mlx90640.raw_data(), 0
for i = 1, 768 do sum = sum + m[i] end
log.info("mlx", "avg", sum / 768)

4.9 mlx90640.get_vdd()

功能

读传感器当前的供电电压。

参数

无参数。

返回值

number:VDD 电压,单位伏。

示例

log.info("mlx", "vdd", mlx90640.get_vdd())

注意事项

这个值来自帧内数据,需先 feed();电压偏低(明显低于 3.3V)时温度读数会系统性偏低,遇到读数整体偏冷先查供电与走线压降。

4.10 mlx90640.draw2lcd(x, y, fold)

功能

把最近一帧温度矩阵映射成伪彩,画到 LCD 上。

参数

x / y

参数含义:绘制区域左上角坐标
数据类型:number
取值范围:屏幕范围内
是否必选:否,默认 0, 0
注意事项:放大后占用 32*fold × 24*fold,超出屏幕的部分会被裁掉,别让坐标把图挤出屏幕。

fold

参数含义:放大倍数
数据类型:number
取值范围:2 的整数次幂(1、2、4、8、16…)
是否必选:否,默认 1
注意事项:传非 2 的幂会得到错位的插值结果;放大倍数越大越吃内存与刷屏时间。

返回值

无返回值(源码没有压入返回值,@return bool 与实现不符,不要用返回值判断)。

示例

mlx90640.feed()
mlx90640.draw2lcd(0, 0, 4)   -- 4 倍放大,占 128×96

注意事项

  1. 必须先 lcd.init(),否则只打印 init lcd first!!! 然后直接返回;

  2. 伪彩映射区间是固定的 20℃~35℃:低于 20℃ 全按最低色、高于 35℃ 全按最高色,所以拍人体可以,测高温物体(如发热器件)会整片糊成红色,这种场景请用 raw_point 自己取数算色阶;

  3. 每帧都要重画整块区域,帧率高时刷屏会明显占 CPU,屏幕小的场景可以用 fold=1。

五、产品支持说明

mlx90640 是外设驱动库,编译开关 LUAT_USE_MLX90640,当前公开固件的支持表中未列出该库,使用前请先确认目标固件是否包含;不包含时需要自行编译固件,或向 FAE 索取带该库的固件。

固件支持列表:

Air780EPM/Air780EHx 系列固件支持列表

Air8000 系列固件支持列表

搜索