4. 红外传感器驱动开发:I2C通信协议详解、MLX90640寄存器配置、原始数据读取与校验
好,咱们进入正题。这一章要啃的,是红外热成像系统的“眼睛”——MLX90640传感器驱动。说白了,就是怎么让单片机跟这颗传感器“说话”,让它把看到的温度数据交出来。
我刚开始接触这颗传感器时,第一反应是:“不就是个I2C设备嘛,照着数据手册读写寄存器就行了。”结果一上手就踩了坑——数据读出来全是乱的。后来才发现,问题出在通信时序和寄存器配置上。嗯,这里面的门道,咱们一个一个说。
4.1 I2C通信协议——传感器与MCU的“对话规则”
MLX90640用的是标准I2C协议,主模式,速率最高支持1MHz。我个人习惯用400kHz,稳定又够快。
I2C协议其实不复杂,就三条线:SCL(时钟)、SDA(数据)、GND(地)。但要注意,MLX90640的I2C地址是0x33(7位地址),写操作时地址字节是0x66,读操作是0x67。这个别搞混了,我见过有人把地址左移一位搞错的。
核心要点:MLX90640的I2C通信流程
- 起始信号 → 发送设备地址+写位 → 等待ACK
- 发送寄存器地址高字节 → 等待ACK
- 发送寄存器地址低字节 → 等待ACK
- 重复起始信号 → 发送设备地址+读位 → 等待ACK
- 读取数据字节(高字节在前) → 发送ACK/NACK
- 停止信号
这里有个坑:MLX90640的寄存器地址是16位的,必须分高8位和低8位两次发送。我曾经图省事,想一次发完,结果传感器根本不搭理我。
4.2 MLX90640寄存器配置——让传感器“进入状态”
传感器上电后,不会自动开始测量。你得先配置几个关键寄存器。我一般按这个顺序来:
| 寄存器名称 | 地址 | 作用 | 推荐值 |
|---|---|---|---|
| 控制寄存器1 | 0x8000 | 主控制,启动测量 | 0x0001 |
| 控制寄存器2 | 0x8001 | 刷新率设置 | 0x0000(0.5Hz)~0x0007(64Hz) |
| 状态寄存器 | 0x8002 | 读取测量状态 | 只读 |
你想想看,刷新率设太高,数据会不稳定;设太低,画面又卡顿。我个人经验,室内场景用2Hz(0x0001)就挺好,户外快速移动场景可以调到8Hz(0x0003)。
小技巧:配置完寄存器后,一定要读回来校验一下。我曾经遇到过I2C总线干扰导致配置没写进去的情况,结果传感器一直没启动,排查了半天。
4.3 原始数据读取——把768个像素点“拽”出来
MLX90640有32×24=768个像素点。每个像素点的原始数据是16位的,存在RAM区,地址从0x0400到0x06FF。
读取流程是这样的:
- 检查状态寄存器(0x8002)的第3位,确认新数据就绪
- 从0x0400开始,连续读取1536个字节(768个像素×2字节)
- 每个像素的高字节在前,低字节在后
代码实现大概长这样:
// 伪代码示例
uint16_t raw_data[768];
uint8_t buf[1536];
// 1. 等待数据就绪
while(!(read_register(0x8002) & 0x08));
// 2. 连续读取RAM数据
i2c_read_multi(0x33, 0x0400, buf, 1536);
// 3. 解析原始数据
for(int i = 0; i < 768; i++) {
raw_data[i] = (buf[i*2] << 8) | buf[i*2+1];
}
这里要注意:连续读取时,I2C主控要能处理1536字节的数据。有些低端MCU的I2C FIFO只有32字节,得分段读。我曾在STM32F103上做过,每32字节读一次,循环48次才读完一帧。
4.4 数据校验——别让“脏数据”毁了你的图像
原始数据读出来了,但能直接用吗?不能。你得先校验。
MLX90640提供了两种校验机制:
- CRC校验:每帧数据末尾有2字节的CRC16,校验从0x0400到0x06FF的所有数据
- 像素有效性标志:每个像素的第15位(bit15)表示该像素是否有效,0为有效,1为无效
警告:千万别忽略像素有效性标志!我遇到过传感器受热不均,部分像素输出无效数据的情况。如果不做校验,画面上会出现“坏点”,严重影响测温精度。
校验代码示例:
// 像素有效性检查
for(int i = 0; i < 768; i++) {
if(raw_data[i] & 0x8000) {
// 像素无效,标记或插值处理
raw_data[i] = 0;
invalid_pixel_count++;
}
}
// CRC校验(简化版)
uint16_t calc_crc = crc16(buf, 1534); // 前1534字节
uint16_t recv_crc = (buf[1534] << 8) | buf[1535];
if(calc_crc != recv_crc) {
// 数据损坏,丢弃这一帧
return ERROR_DATA_CORRUPT;
}
我个人的习惯是,连续3帧校验失败才判定传感器异常,偶尔一帧失败可能是总线干扰,直接丢弃就好。
4.5 知识体系总览
说了这么多,咱们用一张图把整个驱动开发的脉络理清楚:
这张图把整个驱动开发的四个层次串起来了。从最底层的I2C协议,到寄存器配置,再到数据读取和校验,每一步都环环相扣。你想想看,哪一步出了问题,最终的温度数据都会不准。
好了,这一章的内容就到这儿。记住:驱动开发没有捷径,老老实实按流程来,该校验的校验,该等待的等待。我在项目里吃过不少亏,希望你能少走弯路。