针对移植,我们首先需要找到相关原厂驱动地址,如下所示:(包含API手册以及驱动程序)

其中的相关内容如下图所示:说明相关驱动层以及应用层的代码

针对于MLX90640_I2C_Driver.h的移植,由于本身不用到MLX90640_I2CGeneralReset这个函数,这个函数的用意是,实现 I2C 总线的标准复位操作,根据 I2C 协议规范,用于重置总线上支持该复位条件的所有设备。


其次就是平台兼容的问题了,为不同硬件平台设置合适的 I2C 缓冲区大小,使得代码可以通用。
避免因为平台硬件特性(如内存大小或 I2C 硬件实现差异)导致的问题。

接着就是MLX90640_I2C_Driver.cpp了硬件IIC,如下所示:(这边仅仅展示读跟写)
cpp
//Read a number of words from startAddress. Store into Data array.
//Returns 0 if successful, -1 if error
int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data)
{
//Caller passes number of 'unsigned ints to read', increase this to 'bytes to read'
uint16_t bytesRemaining = nWordsRead * 2;
//It doesn't look like sequential read works. Do we need to re-issue the address command each time?
uint16_t dataSpot = 0; //Start at beginning of array
//Setup a series of chunked I2C_BUFFER_LENGTH byte reads
while (bytesRemaining > 0)
{
Wire.beginTransmission(_deviceAddress);
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((uint8_t)_deviceAddress, (uint8_t)numberOfBytesToRead);
if (Wire.available())
{
for (uint16_t x = 0 ; x < numberOfBytesToRead / 2; x++)
{
//Store data into array
data[dataSpot] = Wire.read() << 8; //MSB
data[dataSpot] |= Wire.read(); //LSB
dataSpot++;
}
}
bytesRemaining -= numberOfBytesToRead;
startAddress += numberOfBytesToRead / 2;
}
return (0); //Success
}
_deviceAddress
: I2C 从设备地址。startAddress
: 起始地址,指示从哪里开始读取数据。nWordsRead
: 要读取的 16 位数据(uint16_t
)数量。data
: 存储读取数据的指针(调用者提供的数组)。
Wire.beginTransmission(_deviceAddress)
开始与从设备通信。Wire.write(startAddress >> 8)
和Wire.write(startAddress & 0xFF)
将 16 位起始地址分为高字节和低字节,依次发送。Wire.endTransmission(false)
将命令传输给设备,但不释放总线(false
参数)。
- 功能: 每次读取的字节数不能超过 I2C 缓冲区的大小(
I2C_BUFFER_LENGTH
)。 - 如果剩余的字节数超出缓冲区大小,就读取
I2C_BUFFER_LENGTH
,否则读取剩余字节。 - 使用
Wire.requestFrom
请求指定数量的字节数据。 - 确保缓冲区中有可用数据(
Wire.available()
)。 - 将读取的高字节(
MSB
)和低字节(LSB
)组合成一个 16 位数据,存入data
数组。
cpp
//Write two bytes to a two byte address
int MLX90640_I2CWrite(uint8_t _deviceAddress, unsigned int writeAddress, uint16_t data)
{
Wire.beginTransmission((uint8_t)_deviceAddress);
Wire.write(writeAddress >> 8); //MSB
Wire.write(writeAddress & 0xFF); //LSB
Wire.write(data >> 8); //MSB
Wire.write(data & 0xFF); //LSB
if (Wire.endTransmission() != 0)
{
//Sensor did not ACK
Serial.println("Error: Sensor did not ack");
return (-1);
}
uint16_t dataCheck;
MLX90640_I2CRead(_deviceAddress, writeAddress, 1, &dataCheck);
if (dataCheck != data)
{
//Serial.println("The write request didn't stick");
return -2;
}
追根溯源,其实就是平台API的替换嘛,哪里报错改哪里。
最后就是MLX90640_API.h与MLX90640_API.cpp了,如下所示原厂驱动:


如下是我移植后的,如下所示:
cpp
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _MLX640_API_H_
#define _MLX640_API_H_
typedef struct
{
int16_t kVdd;
int16_t vdd25;
float KvPTAT;
float KtPTAT;
uint16_t vPTAT25;
float alphaPTAT;
int16_t gainEE;
float tgc;
float cpKv;
float cpKta;
uint8_t resolutionEE;
uint8_t calibrationModeEE;
float KsTa;
float ksTo[4];
int16_t ct[4];
float alpha[768];
int16_t offset[768];
float kta[768];
float kv[768];
float cpAlpha[2];
int16_t cpOffset[2];
float ilChessC[3];
uint16_t brokenPixels[5];
uint16_t outlierPixels[5];
} paramsMLX90640;
int MLX90640_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
int MLX90640_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
int MLX90640_ExtractParameters(uint16_t *eeData, paramsMLX90640 *mlx90640);
float MLX90640_GetVdd(uint16_t *frameData, const paramsMLX90640 *params);
float MLX90640_GetTa(uint16_t *frameData, const paramsMLX90640 *params);
void MLX90640_GetImage(uint16_t *frameData, const paramsMLX90640 *params, float *result);
void MLX90640_CalculateTo(uint16_t *frameData, const paramsMLX90640 *params, float emissivity, float tr, float *result);
int MLX90640_SetResolution(uint8_t slaveAddr, uint8_t resolution);
int MLX90640_GetCurResolution(uint8_t slaveAddr);
int MLX90640_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate);
int MLX90640_GetRefreshRate(uint8_t slaveAddr);
int MLX90640_GetSubPageNumber(uint16_t *frameData);
int MLX90640_GetCurMode(uint8_t slaveAddr);
int MLX90640_SetInterleavedMode(uint8_t slaveAddr);
int MLX90640_SetChessMode(uint8_t slaveAddr);
#endif
相关宏去除,直接写在了cpp里面。
因此我们如何进行app层调用,如下所示:

接下来就是STM32以及ESP32的相关代码了,如下所示:




如下是esp32你需要注意的:


因为跟RP2040同一个平台其实本质就是兼容arduino的API仅此而已。