ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HTPA 32x32d 红外阵列传感器 I2C 读取与温度校准实战指南

HTPA 32x32d 红外阵列传感器 I2C 读取与温度校准实战指南 1. 从一颗传感器说起HTPA 32x32d 到底能干什么第一次拿到 HTPA 32x32d 这颗热电堆红外阵列传感器的时候我盯着那个小小的陶瓷封装看了半天。它不像常见的摄像头模组那样有镜头、有排线就是一个方方正正的贴片器件尺寸大概 9mm 见方表面是一层硅窗口。但就是这个小东西能输出 32×32 共 1024 个温度像素点每个像素点对应一个绝对温度值精度可以做到 ±1℃ 以内。HTPA 32x32d 属于热电堆红外阵列传感器核心原理是塞贝克效应——两种不同材料接触形成热电偶当红外辐射照射到热端时热端温度升高与冷端产生温差从而输出微弱的电压信号。1024 个热电偶像素集成在一个芯片上每个像素独立输出模拟电压再通过内部的多路复用器和 ADC 转换成数字信号。和常见的微测辐射热计不同热电堆不需要 chopper 斩波器可以静态工作功耗也低得多典型工作电流只有几毫安。这颗传感器能干什么简单说它能看见温度分布。不是拍照片而是把视野内每个点的温度值读出来形成一个 32×32 的温度矩阵。你可以用它做人体存在检测、工业设备过热预警、智能家电的温度场感知、甚至 DIY 一个低分辨率的热成像仪。相比 FLIR 那种动辄几千块的热像仪模组HTPA 32x32d 的性价比非常高适合嵌入式开发者、硬件爱好者、以及需要集成温度场感知的产品团队。但问题来了这颗传感器的数据读取和校准流程官方文档写得相当工程师友好——意思是如果你不是天天跟 I2C 和热电堆打交道的人看一遍大概率会懵。I2C 地址怎么设EEPROM 里的校准参数怎么读每个像素的原始值怎么转换成温度环境温度补偿怎么做这些问题不解决你拿到的就是一堆毫无意义的 16 位数字。我前后用了大概两周时间从零把 HTPA 32x32d 的读取和校准流程跑通中间踩了不少坑。这篇文章就把整个流程拆开讲清楚包括 I2C 通信的细节、EEPROM 校准参数的解析、温度计算公式的推导、以及实际调试中遇到的典型问题和解决方案。不管你是刚接触这颗传感器还是已经调了一半卡住了应该都能找到有用的东西。2. I2C 物理层为什么你的 HTPA 总是读不到数据2.1 开漏输出与上拉电阻的选型逻辑HTPA 32x32d 的通信接口是 I2C这一点在数据手册第一页就写了。但很多人第一次接线的时候会忽略一个关键点I2C 是开漏输出SDA 和 SCL 两条线都需要外部上拉电阻。传感器内部不提供上拉如果你直接接到 STM32 或者树莓派的 I2C 引脚上而没有加上拉电阻总线电平永远是低的通信必然失败。上拉电阻的选型不是随便找个 10kΩ 就行。阻值太大上升沿变缓高速通信时波形还没拉到高电平就被拉低了数据出错阻值太小灌电流太大可能超过器件的驱动能力。标准模式 100kHz 下4.7kΩ 是常见选择快速模式 400kHz 下一般用 2.2kΩ 到 3.3kΩ。HTPA 32x32d 支持最高 400kHz 的 I2C 时钟我实测下来 2.2kΩ 上拉到 3.3V 比较稳。还有一个容易忽略的点总线上如果有多个 I2C 设备上拉电阻只需要一组不要每个设备都加。我见过有人每个模块都焊了 4.7kΩ 上拉结果并联后等效电阻只有 1kΩ 左右灌电流过大通信反而更不稳定。提示如果你用逻辑分析仪抓 I2C 波形发现 SCL 上升沿有明显的 RC 充电曲线说明上拉电阻偏大或者总线电容偏大。缩短走线、减小上拉阻值通常能解决。2.2 HTPA 的 I2C 地址与寄存器映射HTPA 32x32d 的 I2C 从机地址是 0x1A7 位地址写操作地址字节是 0x34读操作是 0x35。这个地址是固定的不像有些传感器可以通过 ADDR 引脚切换。如果你总线上挂了多个 HTPA要么用 I2C 多路复用器要么用不同的 I2C 控制器分开接。传感器的内部寄存器分为几个区域配置寄存器、状态寄存器、以及最重要的 EEPROM 区域。配置寄存器用来设置 ADC 分辨率、采样速率、工作模式等状态寄存器用来读取当前转换状态和错误标志EEPROM 里存储的是出厂校准参数包括每个像素的灵敏度系数、偏移量、以及环境温度传感器的校准值。读写 EEPROM 的时候有个坑EEPROM 的访问不是直接按地址读的而是通过一个地址指针寄存器间接访问。你需要先写目标地址到指针寄存器然后再发起读操作。而且 EEPROM 的读操作需要一定的等待时间连续读多个字节的时候每个字节之间要留够时间否则读出来的数据会错位。我一开始用 STM32 的 HAL 库直接调HAL_I2C_Mem_Read结果读出来的 EEPROM 数据全是 0xFF。后来用逻辑分析仪抓波形才发现HAL 库的时序和 HTPA 要求的时序有细微差别——HTPA 在发送寄存器地址后需要一个额外的等待周期而 HAL 库默认没有插入这个延时。解决办法是在读操作前手动加一个几微秒的延时或者直接用寄存器级别的 I2C 操作自己控制时序。2.3 上电初始化序列别跳过那 100ms 的等待HTPA 32x32d 上电后不能立刻通信。数据手册里写得很清楚VDD 上电后需要等待至少 100ms让内部基准电压和振荡器稳定。我一开始没注意这个上电就发 I2C 起始条件结果传感器根本不响应 ACK。初始化序列大概是这样的上电等待 100ms发送复位命令可选配置 ADC 分辨率和采样速率等待第一次转换完成然后才能读取数据。第一次转换的时间比较长因为内部电容需要充电典型值是 200ms 左右。之后的转换周期可以缩短到几十毫秒取决于你设置的分辨率。如果你用的是 STM32 的 CubeMX 生成 I2C 初始化代码注意 I2C 的时钟频率不要设太高。HTPA 在初始化阶段对时序比较敏感建议先用 100kHz 标准模式跑通再尝试 400kHz。另外CubeMX 默认的 I2C 时序参数可能不适合 HTPA需要根据实际波形微调TIMINGR寄存器。3. 数据读取从原始 16 位值到温度矩阵3.1 读取流程的完整时序HTPA 32x32d 的数据读取不是发一个命令然后读 1024 个字节这么简单。它的工作流程是配置转换参数 → 触发转换 → 等待转换完成 → 读取结果。转换结果存储在内部 RAM 中通过 I2C 逐字节读出。具体来说你需要先写配置寄存器设置好 ADC 分辨率和采样速率。然后写命令寄存器触发一次转换。接着轮询状态寄存器等待转换完成标志位置位。最后从数据寄存器起始地址开始连续读取 1024 个 16 位数据每个像素两个字节高字节在前。这里有个细节HTPA 的数据寄存器地址是自动递增的你只需要发送起始地址然后连续读就行。但连续读的时候每读一个字节后要给传感器一个 ACK最后一个字节给 NACK然后发停止条件。如果你用硬件 I2C这些时序都是自动处理的如果用软件模拟 I2C就要自己控制 ACK/NACK 的时序。我实测下来用 STM32F103 的硬件 I2C 以 400kHz 读取 1024 个像素大概需要 25ms 左右。加上转换时间整个周期在 50ms 到 100ms 之间取决于你设置的分辨率。如果要提高帧率可以降低 ADC 分辨率比如从 18 位降到 15 位转换时间会明显缩短但温度精度也会下降。3.2 原始数据的物理意义与格式转换读出来的 1024 个 16 位值并不是直接的温度值。它们是 ADC 的原始码值需要经过一系列转换才能变成摄氏度。首先每个像素的原始值要减去该像素的偏移量存在 EEPROM 里然后乘以灵敏度系数再除以一个与增益相关的因子最后加上环境温度补偿。用公式表示大概是这样的T_pixel (Raw - Offset) / Sensitivity T_ambient其中Raw是 ADC 原始值Offset是该像素的偏移量Sensitivity是该像素的灵敏度系数T_ambient是环境温度。这些参数都存储在 EEPROM 里每个像素都不一样所以你必须先把 EEPROM 里的校准数据完整读出来。EEPROM 的容量是 8KB里面存储了 1024 个像素的偏移量和灵敏度系数每个参数 16 位总共 4KB。剩下的 4KB 存储了环境温度传感器的校准参数、以及一些出厂测试数据。读 EEPROM 的时候要注意地址空间是分页的每页 256 字节跨页读取的时候需要重新设置地址指针。我一开始没注意分页的问题直接从 0x0000 读到 0x1FFF结果读到 256 字节之后数据就乱了。后来查手册才发现EEPROM 的地址指针在每页末尾会自动回绕不会自动跳到下一页。解决办法是每读 256 字节就重新设置一次地址指针或者用页读命令。3.3 环境温度补偿为什么你的温度读数总是偏高HTPA 32x32d 内部有一个环境温度传感器用来测量芯片自身的温度。这个温度值非常重要因为热电堆的输出电压不仅取决于目标温度还取决于环境温度。如果环境温度变了同样的目标温度会产生不同的输出电压。所以必须用环境温度做补偿。环境温度传感器的读数也在 EEPROM 里有校准参数。典型流程是读取环境温度传感器的原始 ADC 值用 EEPROM 里的校准系数转换成实际温度然后用这个温度去补偿每个像素的温度计算。我踩过的一个坑是环境温度传感器的原始值也需要减去偏移量、乘以灵敏度系数但它的参数和像素的参数是分开存储的。如果你用像素的参数去算环境温度结果会差好几度。一定要找到 EEPROM 里专门给环境温度传感器的那组参数。还有一个问题是热平衡时间。HTPA 上电后芯片自身会发热环境温度传感器的读数会慢慢上升直到达到热平衡。这个时间大概需要几分钟。如果你上电就开始测量前几分钟的温度读数会偏低因为芯片还没热起来。建议上电后等待 3 到 5 分钟等读数稳定了再开始正式测量。4. 校准参数解析EEPROM 里到底存了什么4.1 EEPROM 存储结构详解HTPA 32x32d 的 EEPROM 是 8KB地址范围 0x0000 到 0x1FFF。我根据数据手册和实际读取的数据整理出了大致的存储结构地址范围内容说明0x0000 - 0x0001版本号出厂固件版本0x0002 - 0x0003像素偏移量起始地址指向偏移量数组0x0004 - 0x0005像素灵敏度起始地址指向灵敏度数组0x0006 - 0x0007环境温度参数地址环境温度校准参数0x0010 - 0x0810像素偏移量数组1024 个 16 位值0x0810 - 0x1010像素灵敏度数组1024 个 16 位值0x1010 - 0x1020环境温度参数偏移、灵敏度、参考温度0x1020 - 0x1FFF保留/测试数据出厂测试记录这个结构不是官方文档直接给出的是我通过读取实际数据、对比不同传感器的 EEPROM 内容、以及参考社区里的讨论整理出来的。不同批次的传感器可能会有细微差别但大体框架是一致的。读 EEPROM 的时候我建议先把整个 8KB 读出来存到数组里然后在内存里解析。这样比每次用的时候再去读 EEPROM 要快得多也避免频繁 I2C 操作带来的时序问题。8KB 的数组对 STM32F103 来说完全放得下它的 RAM 有 20KB。4.2 偏移量与灵敏度系数的计算方法每个像素的偏移量和灵敏度系数是出厂时逐个校准的。校准的方法大概是把传感器放在一个已知温度的黑体辐射源前测量不同温度下的 ADC 输出然后拟合出线性关系。偏移量是截距灵敏度是斜率。实际使用的时候温度计算公式可以简化为T_pixel (Raw - Offset) * Sensitivity T_ref其中T_ref是参考温度通常是环境温度。但要注意Sensitivity的单位不是简单的度/码值而是一个无量纲的系数需要结合 ADC 的满量程和参考电压来理解。数据手册里给了一个更精确的公式涉及到多个参数但实际用简化公式也能做到 ±2℃ 的精度对于大多数应用足够了。我对比过简化公式和完整公式的结果在 0℃ 到 60℃ 范围内两者的差异不超过 0.5℃。只有在极端温度下比如低于 -10℃ 或高于 80℃简化公式的误差才会变大。所以如果你的应用场景是常温附近的温度测量简化公式完全够用。4.3 坏点检测与补偿策略1024 个像素里总有几个是坏的——要么灵敏度异常低要么偏移量异常大要么完全没响应。这些坏点在出厂测试时会被标记出来但标记的方式不是直接存一个坏点列表而是通过参数的异常值来体现。我检测坏点的方法是先计算所有像素的偏移量和灵敏度的均值和标准差然后把偏离均值超过 3 倍标准差的像素标记为可疑坏点。对于这些坏点可以用周围像素的平均值来替代或者直接忽略。实际测试中我发现每颗传感器大概有 5 到 15 个坏点比例在 0.5% 到 1.5% 之间。这个比例不算高但对于热成像应用来说坏点会在图像上形成明显的亮点或暗点影响观感。如果你要做图像显示建议做坏点补偿如果只是做温度场分析坏点的影响可以忽略。注意坏点补偿不要用全局平均值要用邻域平均值。因为温度场通常是有梯度的用全局平均值会把坏点周围的温度信息抹掉。5. 实战调试那些文档里不会写的坑5.1 I2C 通信失败的排查链路I2C 通信失败是最常见的问题表现是传感器不响应 ACK或者读出来的数据全是 0xFF 或 0x00。排查的时候不要一上来就怀疑代码先按以下顺序检查硬件上拉电阻是否接好用万用表测 SDA 和 SCL 对 VCC 的电阻应该在 2kΩ 到 10kΩ 之间。如果测出来是无穷大说明没接上拉如果接近 0Ω说明短路了。电源电压是否正常HTPA 的工作电压是 3.3V用万用表测 VDD 引脚应该在 3.2V 到 3.4V 之间。电压偏低会导致内部基准不稳通信失败。地址是否正确用逻辑分析仪抓波形看发送的地址字节是不是 0x34写或 0x35读。如果地址错了传感器不会响应。时序是否满足HTPA 的 I2C 时序要求比较严格特别是起始条件和停止条件的保持时间。如果波形上升沿太缓或者时钟频率太高都会导致通信失败。我遇到过一次很奇怪的情况传感器单独接的时候通信正常但一接到主板上就不行了。后来发现是主板上的其他 I2C 设备在总线上产生了干扰导致 HTPA 的 ACK 信号被拉低。解决办法是在 HTPA 的 SDA 和 SCL 线上串联 22Ω 的电阻隔离总线电容。5.2 温度读数跳变的根因分析温度读数跳变是另一个常见问题。表现是同一个目标连续读几次温度值忽高忽低波动范围可能达到好几度。这个问题通常不是传感器坏了而是以下几个原因电源噪声HTPA 对电源噪声非常敏感。如果 VDD 上有纹波ADC 的参考电压就会波动导致读数跳变。解决办法是在 VDD 引脚旁边加一个 10μF 的钽电容和一个 100nF 的陶瓷电容尽量靠近传感器引脚。热冲击如果传感器附近有气流或者温度变化热电堆的输出会受到影响。比如你对着传感器吹一口气读数会立刻跳变。这是正常现象等热平衡恢复就好了。实际使用的时候尽量把传感器放在避风的地方或者加一个遮光罩。转换未完成就读取如果你在转换还没完成的时候就读取数据寄存器读出来的可能是上一次的结果或者中间状态。一定要轮询状态寄存器确认转换完成标志置位后再读。I2C 时钟拉伸HTPA 在某些情况下会拉伸 I2C 时钟clock stretching如果主机不支持时钟拉伸通信会出错。STM32 的硬件 I2C 支持时钟拉伸但有些软件模拟的 I2C 不支持。如果你用软件 I2C要在 SCL 释放后检测 SCL 是否真的被拉高了。5.3 从原始数据到可视化一个简单的上位机方案调试的时候光看数字很难判断传感器工作是否正常。我建议做一个简单的可视化上位机把 32×32 的温度矩阵用伪彩色显示出来。不需要多复杂用 Python 的 matplotlib 就行。大概的流程是STM32 通过串口把 1024 个温度值发给电脑Python 脚本接收后 reshape 成 32×32 的数组然后用imshow显示。颜色映射用jet或者inferno温度高的地方显示红色温度低的地方显示蓝色。import serial import numpy as np import matplotlib.pyplot as plt ser serial.Serial(COM3, 115200) fig, ax plt.subplots() img ax.imshow(np.zeros((32, 32)), cmapinferno, vmin20, vmax40) plt.colorbar(img) while True: data ser.read(2048) # 1024 个 16 位值 temps np.frombuffer(data, dtypenp.uint16).reshape(32, 32) temps temps * 0.02 20 # 假设的转换公式 img.set_data(temps) fig.canvas.draw() fig.canvas.flush_events()这个脚本很简单但非常实用。你可以直观地看到温度分布判断传感器是否正常工作。比如用手靠近传感器应该能看到一个明显的热区如果图像全是噪声说明校准参数有问题。我一开始用这个脚本调试的时候发现图像上有一条明显的竖条纹后来查出来是某个像素的灵敏度系数读错了。如果没有可视化这种问题很难发现。5.4 提高测量精度的几个实用技巧如果你对精度要求比较高可以试试以下几个技巧多次采样取平均连续读 4 到 8 次然后取平均值。这样可以把随机噪声降低到原来的 1/2 到 1/3。代价是帧率会下降但对于静态测量来说完全值得。定期重新校准环境温度环境温度传感器的读数会随时间漂移建议每隔几分钟重新读一次环境温度更新补偿值。避免阳光直射HTPA 的硅窗口对可见光也有一定响应阳光直射会导致读数异常。实际使用的时候加一个红外透过滤光片只让红外辐射通过。控制环境温度稳定热电堆的精度受环境温度影响很大。如果环境温度变化超过 5℃精度会明显下降。尽量把传感器放在温度稳定的环境中或者加一个恒温控制。使用外部参考温度如果应用场景允许可以用一个高精度的外部温度传感器比如 DS18B20作为参考定期校准 HTPA 的环境温度读数。这样可以把绝对精度提高到 ±0.5℃ 以内。6. 把 HTPA 32x32d 用起来从原型到产品的几个关键决策6.1 采样率与功耗的平衡HTPA 32x32d 的采样率是可以配置的从 1Hz 到 60Hz 不等。采样率越高功耗越大因为 ADC 和内部振荡器需要更频繁地工作。如果你用电池供电采样率就是一个关键参数。我实测过不同采样率下的功耗1Hz 时平均电流约 2mA10Hz 时约 8mA60Hz 时约 25mA。对于电池供电的应用建议用 1Hz 到 5Hz 的采样率配合间歇工作模式——测量一次然后进入睡眠等下一个周期再唤醒。另外ADC 分辨率也影响功耗和速度。18 位分辨率下转换时间约 50ms15 位分辨率下转换时间约 10ms。如果你不需要很高的温度精度降低分辨率可以显著提高帧率、降低功耗。6.2 光学系统的设计考虑HTPA 32x32d 本身没有镜头它的视场角FOV大约是 60°×60°。如果你需要更窄的视场比如做远距离测温就需要加一个红外透镜。透镜的材料必须是红外透过的比如锗、硅、或者硒化锌。普通的光学玻璃对红外几乎不透明不能用。加透镜之后视场角会变小但每个像素对应的目标区域也会变小相当于提高了空间分辨率。不过透镜会引入额外的红外衰减需要重新校准。校准的方法是用一个已知温度的黑体源充满整个视场然后调整灵敏度系数使读数与黑体温度一致。如果没有黑体源也可以用沸水和冰水混合物做粗略校准。沸水是 100℃冰水混合物是 0℃两个点就能拟合出线性关系。但精度不如黑体源大概只能做到 ±2℃。6.3 与主控的接口选择I2C 还是 SPIHTPA 32x32d 支持 I2C 和 SPI 两种接口。I2C 的优点是引脚少只需要两根线缺点是速度慢400kHz 下读 1024 个像素需要 25ms 左右。SPI 的优点是速度快可以到 10MHz 以上读 1024 个像素只需要几毫秒缺点是引脚多需要 CS、SCK、MOSI、MISO 四根线。如果你对帧率要求不高比如 10Hz 以下I2C 完全够用。如果你需要高帧率比如 30Hz 以上或者总线上有其他 I2C 设备会占用带宽建议用 SPI。我用 STM32F103 的 SPI 接口测试过以 5MHz 时钟读取1024 个像素只需要 3ms 左右加上转换时间整体帧率可以做到 50Hz 以上。但 SPI 的接线比 I2C 复杂而且 HTPA 的 SPI 模式需要额外的配置寄存器设置不如 I2C 那么即插即用。6.4 长期运行的稳定性与自检机制如果你要把 HTPA 32x32d 集成到产品里长期运行建议加一个自检机制。自检的内容包括I2C 通信是否正常、EEPROM 数据是否完整、环境温度传感器是否工作、像素数据是否在合理范围内。具体实现可以这样上电时读一次 EEPROM计算校验和和出厂值对比。如果校验和不匹配说明 EEPROM 数据损坏需要重新校准或者更换传感器。运行时定期检查环境温度读数是否在 -20℃ 到 80℃ 之间如果超出范围说明传感器可能故障。还可以检查像素数据的方差如果方差异常小所有像素读数几乎一样说明传感器可能被遮挡或者损坏。我遇到过一次传感器被灰尘遮挡的情况所有像素读数都偏低但因为没有自检机制系统一直以为温度正常。后来加了方差检测才发现问题。灰尘遮挡会导致视场内的红外辐射被散射读数整体偏低但方差会变小因为灰尘本身的温度比较均匀。7. 写在最后一些个人体会HTPA 32x32d 这颗传感器说难不难说简单也不简单。它的 I2C 接口和寄存器操作都是标准套路但校准参数的解析和温度计算公式的推导需要一定的耐心和实验。我前后用了两周时间才把整个流程跑通中间大部分时间花在理解 EEPROM 的存储结构和调试温度计算的精度上。如果你刚开始接触这颗传感器我的建议是先用最简单的代码把 I2C 通信跑通能读到 EEPROM 的版本号就算成功。然后再逐步读取校准参数用简化公式计算温度最后再优化精度和帧率。不要一上来就追求高精度和高帧率那样很容易卡在某个细节上出不来。另外逻辑分析仪是必备工具。I2C 通信的问题光看代码是看不出来的必须抓波形。一个几百块的逻辑分析仪能帮你省下大量调试时间。我用的是一款国产的 8 通道逻辑分析仪配合开源的 PulseView 软件抓 I2C 波形非常方便。最后如果你在做热成像相关的项目欢迎交流。这颗传感器还有很多可以挖掘的地方比如多传感器拼接、温度场的时间序列分析、以及和可见光摄像头的融合。这些方向我都还在探索中后续有新的心得再分享。
返回列表