使用3D打印,制作了个外壳。把板子和芯片包裹起来。接口使用GROVE接口。


拿到芯片之前,想着这个MLX90642应该和他的前辈MLX90640可以使用同样的驱动代码来驱动,结果试了一下,根本行不通。只能重新写驱动。
第一步:先要确定能够识别到传感器。使用GROVE线,将传感器和单片机连接起来。我这里单片机选用的是M5StickC Plus,主控采用ESP32-PICO-D4模组。开发我使用Vscode+platformio。先扫描I2C设备,寻找到传感器。可以看见,单片机成功识别到了传感器,I2C地址为0X66。


第二步:从官网提供的https://github.com/melexis/mlx90642-library.git下载源码,但是下载的源码并不完整,MLX90642_depends.h文件中定义的方法都没有做实现。参考着readme文件,新建MLX90642_depends.cpp文件,实现了以下几个函数。
#include "MLX90642_depends.h"
#include "MLX90642.h"
#include <Arduino.h>
#include <Wire.h>
// 从I2C总线上读取数据
int MLX90642_I2CRead(uint8_t slaveAddr, uint16_t startAddress, uint16_t nMemAddressRead, uint16_t *rData)
{
uint16_t bytesRemaining = nMemAddressRead * 2;
uint16_t dataSpot = 0; // Start at beginning of array
// Setup a series of chunked I2C_BUFFER_LENGTH byte reads
while (bytesRemaining > 0)
{
Wire.beginTransmission(slaveAddr);
Wire.write(startAddress >> 8); // MSB
Wire.write(startAddress & 0xFF); // LSB
if (Wire.endTransmission(false) != 0) // Do not release bus
{
Serial.println("No ack read");
return (0); // Sensor did not ACK
}
uint16_t numberOfBytesToRead = bytesRemaining;
if (numberOfBytesToRead > I2C_BUFFER_LENGTH)
numberOfBytesToRead = I2C_BUFFER_LENGTH;
Wire.requestFrom(slaveAddr, (uint8_t)numberOfBytesToRead);
if (Wire.available())
{
for (uint16_t x = 0; x < numberOfBytesToRead / 2; x++)
{
// Store data into array
rData[dataSpot] = Wire.read() << 8; // MSB
rData[dataSpot] |= Wire.read(); // LSB
dataSpot++;
}
}
bytesRemaining -= numberOfBytesToRead;
startAddress += numberOfBytesToRead / 2;
}
return (0); // Success
}
// 指定位置写一个word
int MLX90642_Config(uint8_t slaveAddr, uint16_t writeAddress, uint16_t wData)
{
Wire.beginTransmission((uint8_t)slaveAddr);
Wire.write(writeAddress >> 8); // MSB
Wire.write(writeAddress & 0xFF); // LSB
Wire.write(wData >> 8); // MSB
Wire.write(wData & 0xFF); // LSB
if (Wire.endTransmission() != 0)
{
// Sensor did not ACK
Serial.println("Error: Sensor did not ack");
return (-1);
}
uint16_t dataCheck;
MLX90642_I2CRead(slaveAddr, writeAddress, 2, &dataCheck);
// Serial.printf("Write:%d %d\n",dataCheck, wData);
if (dataCheck != wData)
{
// Serial.println("The write request didn't stick");
return -2;
}
return (0); // Success
}
int MLX90642_I2CCmd(uint8_t slaveAddr, uint16_t i2c_cmd)
{
int res;
switch (i2c_cmd)
{
case MLX90642_START_SYNC_MEAS_CMD:
res = MLX90642_Config(slaveAddr, MLX90642_CMD_OPCODE, i2c_cmd);
break;
case MLX90642_SLEEP_CMD:
Serial.println("come here too");
res = MLX90642_Config(slaveAddr, MLX90642_CMD_OPCODE, i2c_cmd);
break;
default:
res = -1;
break;
}
Serial.printf("I2CCmd res = %d\n", res);
return res;
}
void MLX90642_Wait_ms(uint16_t time_ms)
{
delay(time_ms / 1000);
}然后在setup方法中首先初始化mlx90642,但是这里初始化时,总是有个报错。查看代码应该是:

查看官方文档,应该是这个设置。


但是不明白这里向寄存器写入数据总是出错,卡了好久都没能解决。最后无奈,只能将这段代码的错误屏蔽掉,跳过了这个异步设置的错误,好在对后边读取温度信息没啥影响。

第三步:初始化完成后,就可以在loop循环中不停地读取传感器的数据矩阵了。mlx90642传感器获得到的温度信息,为一个32x24的数据矩阵。可以看见传感器获得的温度矩阵数据,每个数据都是个整形数据。最后还需要装换为常用的摄氏度。

第四步:转换数据。

参考官方文档,将整形转换为摄氏度,使用1位小数输出。

#include <Arduino.h>
#include <M5StickCPlus.h>
#include <Wire.h>
#include "MLX90642.h"
int status = 0;
static uint16_t s_temp[MLX90642_TOTAL_NUMBER_OF_PIXELS + 1];
void setup()
{
M5.begin(); // Initialize M5StickC Plus. 初始化 M5StickC PLus
M5.Lcd.setTextSize(3); // Set font size. 设置字体大小
M5.Lcd.setRotation(3); // Rotate the screen. 将屏幕旋转
M5.Lcd.print("Hello World");
Wire.begin(32, 33); // sda= GPIO_21 /scl= GPIO_22 //外接I2C 和 内部I2C
delay(8000);
uint8_t version[3];
status = MLX90642_GetFWver(SA_90642_DEFAULT, version);
// 如果status < 0,则处理错误
Serial.printf("FW version: %d.%d.%d %d\r\n", version[0], version[1], version[2], status);
status = MLX90642_SetMeasMode(SA_90642_DEFAULT, MLX90642_STEP_MEAS_MODE);
Serial.println(status);
status = MLX90642_Init(SA_90642_DEFAULT);
// Serial.printf("MLX90642_Init:%d\r\n", status);
// status = MLX90642_SetRefreshRate(SA_90642_DEFAULT, MLX90642_REF_RATE_2HZ);
// Serial.printf("MLX90642_SetRefreshRate:%d\r\n", status);
// status = MLX90642_SetOutputFormat(SA_90642_DEFAULT, MLX90642_TEMPERATURE_OUTPUT);
// Serial.printf("MLX90642_SetOutputFormat:%d\r\n", status);
// status = MLX90642_SetI2CLevel(SA_90642_DEFAULT, MLX90642_I2C_LEVEL_VDD);
// Serial.printf("MLX90642_SetI2CLevel:%d\r\n", status);
// status = MLX90642_SetSDALimitState(SA_90642_DEFAULT, MLX90642_I2C_SDA_CUR_LIMIT_OFF);
// Serial.printf("MLX90642_SetSDALimitState:%d\r\n", status);
// status = MLX90642_SetI2CMode(SA_90642_DEFAULT, MLX90642_I2C_MODE_FM_PLUS);
// Serial.printf("MLX90642_SetI2CMode:%d\r\n", status);
// MLX90642_Set_Delay(20ul);
}
void loop()
{
delay(3000);
status = MLX90642_IsReadWindowOpen(SA_90642_DEFAULT);
Serial.printf("MLX90642_IsReadWindowOpen:%d\r\n", status);
status = MLX90642_GetImage(SA_90642_DEFAULT, s_temp);
Serial.printf("MLX90642_GetImage:%d\r\n", status);
for (uint8_t i = 0; i < 32; i++)
{
for(uint8_t j = 0; j < 24; j++){
Serial.printf("%.1f, ", float(s_temp[i*24+j])/50.00);
// Serial.printf("%d, ", s_temp[i*24+j]);
}
Serial.println("");
}
Serial.println();
}
28

