使用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(); }