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
注意事项
-
传感器上电后需要几百毫秒稳定时间,
init成功后不要立刻读,先sys.wait(500); -
初始化失败最常见的原因是 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)
注意事项
-
必须
init之后调用,未初始化时只会打印mlx90640 NOT init yet,并从接口直接返回; -
读帧失败(I2C 出错)时也只打一条
GetFrame Error日志,不抛异常,业务侧要自己用数值合理性兜底; -
取数节奏要跟刷新率匹配:设的是 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)
注意事项
-
768 个 float 组成 table 会占不少内存,低内存型号建议按需用
raw_point逐点取; -
矩阵按行存储,第
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 起的,而
raw_point是 0 起的,两者差 1,直接拿pos去raw_point会偏移一个点; -
必须紧跟在
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
注意事项
-
必须先
lcd.init(),否则只打印init lcd first!!!然后直接返回; -
伪彩映射区间是固定的 20℃~35℃:低于 20℃ 全按最低色、高于 35℃ 全按最高色,所以拍人体可以,测高温物体(如发热器件)会整片糊成红色,这种场景请用
raw_point自己取数算色阶; -
每帧都要重画整块区域,帧率高时刷屏会明显占 CPU,屏幕小的场景可以用
fold=1。
五、产品支持说明
mlx90640 是外设驱动库,编译开关 LUAT_USE_MLX90640,当前公开固件的支持表中未列出该库,使用前请先确认目标固件是否包含;不包含时需要自行编译固件,或向 FAE 索取带该库的固件。
固件支持列表: