Add extended range mode support and optimize continuous measurements

- Implement extended range measurement mode for both ambient and object temperature
- Support automatic mode detection (Medical vs Extended Range)
- Extended range uses RAM_52-59 with complex S calculation formula
- Medical mode continues using cycle position-based calculations
- Unify variable names (ram_ambient, ram_ref) for cleaner code
- Update debug output to show measurement mode and generic variables
- Optimize test sketch for efficient continuous monitoring:
  - Reset new data flag before starting measurements
  - Only check isNewData() flag instead of busy flags
  - Reset flag after each reading for proper data flow
  - Reduce I2C bus traffic with minimal delay

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ladyada 2025-08-02 15:56:29 -04:00
parent 4552553eb3
commit 195681dc69
2 changed files with 148 additions and 79 deletions

View file

@ -416,19 +416,35 @@ bool Adafruit_MLX90632::getCalibrations() {
* @return Ambient temperature in degrees Celsius * @return Ambient temperature in degrees Celsius
*/ */
double Adafruit_MLX90632::getAmbientTemperature() { double Adafruit_MLX90632::getAmbientTemperature() {
// Read raw data from RAM registers // Check measurement mode to determine which RAM registers to use
Adafruit_BusIO_Register ram6_reg = mlx90632_meas_select_t meas_mode = getMeasurementSelect();
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_6), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram9_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_9), 2, MSBFIRST, 2);
int16_t ram6 = (int16_t)ram6_reg.read(); int16_t ram_ambient, ram_ref;
int16_t ram9 = (int16_t)ram9_reg.read();
// Pre-calculations for ambient temperature if (meas_mode == MLX90632_MEAS_EXTENDED_RANGE) {
// Extended range mode: use RAM_54 and RAM_57
Adafruit_BusIO_Register ram54_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_54), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram57_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_57), 2, MSBFIRST, 2);
ram_ambient = (int16_t)ram54_reg.read();
ram_ref = (int16_t)ram57_reg.read();
} else {
// Medical mode: use RAM_6 and RAM_9 (default)
Adafruit_BusIO_Register ram6_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_6), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram9_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_9), 2, MSBFIRST, 2);
ram_ambient = (int16_t)ram6_reg.read();
ram_ref = (int16_t)ram9_reg.read();
}
// Pre-calculations for ambient temperature (same for both modes)
// Gb = EE_Gb * 2^-10 (already calculated in getCalibrations()) // Gb = EE_Gb * 2^-10 (already calculated in getCalibrations())
double VRTA = (double)ram9 + Gb * ((double)ram6 / 12.0); double VRTA = (double)ram_ref + Gb * ((double)ram_ambient / 12.0);
double AMB = ((double)ram6 / 12.0) / VRTA * (double)pow(2, 19); double AMB = ((double)ram_ambient / 12.0) / VRTA * (double)pow(2, 19);
// Calculate ambient temperature: P_O + (AMB - P_R)/P_G + P_T * (AMB - P_R)^2 // Calculate ambient temperature: P_O + (AMB - P_R)/P_G + P_T * (AMB - P_R)^2
double amb_diff = AMB - P_R; double amb_diff = AMB - P_R;
@ -436,8 +452,9 @@ double Adafruit_MLX90632::getAmbientTemperature() {
#ifdef MLX90632_DEBUG #ifdef MLX90632_DEBUG
// Debug output // Debug output
Serial.print(F(" RAM_6 = ")); Serial.println(ram6); Serial.print(F(" Mode = ")); Serial.println(meas_mode == MLX90632_MEAS_EXTENDED_RANGE ? F("Extended") : F("Medical"));
Serial.print(F(" RAM_9 = ")); Serial.println(ram9); Serial.print(F(" RAM_ambient = ")); Serial.println(ram_ambient);
Serial.print(F(" RAM_ref = ")); Serial.println(ram_ref);
Serial.print(F(" Gb = ")); Serial.println(Gb, 8); Serial.print(F(" Gb = ")); Serial.println(Gb, 8);
Serial.print(F(" VRTA = ")); Serial.println(VRTA, 8); Serial.print(F(" VRTA = ")); Serial.println(VRTA, 8);
Serial.print(F(" AMB = ")); Serial.println(AMB, 8); Serial.print(F(" AMB = ")); Serial.println(AMB, 8);
@ -453,54 +470,94 @@ double Adafruit_MLX90632::getAmbientTemperature() {
* @return Object temperature in degrees Celsius or NaN if invalid cycle position * @return Object temperature in degrees Celsius or NaN if invalid cycle position
*/ */
double Adafruit_MLX90632::getObjectTemperature() { double Adafruit_MLX90632::getObjectTemperature() {
// Read cycle position to determine which RAM registers to use // Check measurement mode to determine which calculation to use
uint8_t cycle_pos = readCyclePosition(); mlx90632_meas_select_t meas_mode = getMeasurementSelect();
// Read raw data from RAM registers
Adafruit_BusIO_Register ram4_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_4), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram5_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_5), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram6_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_6), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram7_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_7), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram8_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_8), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram9_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_9), 2, MSBFIRST, 2);
int16_t ram4 = (int16_t)ram4_reg.read();
int16_t ram5 = (int16_t)ram5_reg.read();
int16_t ram6 = (int16_t)ram6_reg.read();
int16_t ram7 = (int16_t)ram7_reg.read();
int16_t ram8 = (int16_t)ram8_reg.read();
int16_t ram9 = (int16_t)ram9_reg.read();
// Calculate S based on cycle position
// S = (RAM_4 + RAM_5) / 2 if cycle_pos = 2
// S = (RAM_7 + RAM_8) / 2 if cycle_pos = 1
double S; double S;
if (cycle_pos == 2) { int16_t ram_ambient, ram_ref;
S = ((double)ram4 + (double)ram5) / 2.0;
} else if (cycle_pos == 1) { if (meas_mode == MLX90632_MEAS_EXTENDED_RANGE) {
S = ((double)ram7 + (double)ram8) / 2.0; // Extended range mode: use RAM_52-59
Adafruit_BusIO_Register ram52_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_52), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram53_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_53), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram54_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_54), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram55_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_55), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram56_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_56), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram57_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_57), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram58_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_58), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram59_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_59), 2, MSBFIRST, 2);
int16_t ram52 = (int16_t)ram52_reg.read();
int16_t ram53 = (int16_t)ram53_reg.read();
int16_t ram54 = (int16_t)ram54_reg.read();
int16_t ram55 = (int16_t)ram55_reg.read();
int16_t ram56 = (int16_t)ram56_reg.read();
int16_t ram57 = (int16_t)ram57_reg.read();
int16_t ram58 = (int16_t)ram58_reg.read();
int16_t ram59 = (int16_t)ram59_reg.read();
// Extended range S calculation
S = ((double)ram52 - (double)ram53 - (double)ram55 + (double)ram56) / 2.0 + (double)ram58 + (double)ram59;
ram_ambient = ram54;
ram_ref = ram57;
} else { } else {
// Invalid cycle position - return NaN // Medical mode: use cycle position and RAM_4-9
return NAN; uint8_t cycle_pos = readCyclePosition();
Adafruit_BusIO_Register ram4_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_4), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram5_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_5), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram6_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_6), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram7_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_7), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram8_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_8), 2, MSBFIRST, 2);
Adafruit_BusIO_Register ram9_reg =
Adafruit_BusIO_Register(i2c_dev, swapBytes(MLX90632_REG_RAM_9), 2, MSBFIRST, 2);
int16_t ram4 = (int16_t)ram4_reg.read();
int16_t ram5 = (int16_t)ram5_reg.read();
int16_t ram6 = (int16_t)ram6_reg.read();
int16_t ram7 = (int16_t)ram7_reg.read();
int16_t ram8 = (int16_t)ram8_reg.read();
int16_t ram9 = (int16_t)ram9_reg.read();
// Medical mode S calculation based on cycle position
if (cycle_pos == 2) {
S = ((double)ram4 + (double)ram5) / 2.0;
} else if (cycle_pos == 1) {
S = ((double)ram7 + (double)ram8) / 2.0;
} else {
// Invalid cycle position - return NaN
return NAN;
}
ram_ambient = ram6;
ram_ref = ram9;
} }
// Pre-calculations for object temperature // Pre-calculations for object temperature (same for both modes)
// VRTO = RAM_9 + Ka * (RAM_6 / 12) // VRTO = ram_ref + Ka * (ram_ambient / 12)
// Ka = EE_Ka * 2^-10 (already calculated in getCalibrations()) // Ka = EE_Ka * 2^-10 (already calculated in getCalibrations())
double VRTO = (double)ram9 + Ka * ((double)ram6 / 12.0); double VRTO = (double)ram_ref + Ka * ((double)ram_ambient / 12.0);
// STO = [S/12]/VRTO * 2^19 // STO = [S/12]/VRTO * 2^19
double STO = ((S / 12.0) / VRTO) * (double)pow(2, 19); double STO = ((S / 12.0) / VRTO) * (double)pow(2, 19);
// Calculate AMB for ambient temperature (needed for TADUT) // Calculate AMB for ambient temperature (needed for TADUT)
double VRTA = (double)ram9 + Gb * ((double)ram6 / 12.0); double VRTA = (double)ram_ref + Gb * ((double)ram_ambient / 12.0);
double AMB = ((double)ram6 / 12.0) / VRTA * (double)pow(2, 19); double AMB = ((double)ram_ambient / 12.0) / VRTA * (double)pow(2, 19);
// Additional temperature calculations // Additional temperature calculations
double TADUT = (AMB - Eb) / Ea + 25.0; double TADUT = (AMB - Eb) / Ea + 25.0;
@ -519,13 +576,12 @@ double Adafruit_MLX90632::getObjectTemperature() {
#ifdef MLX90632_DEBUG #ifdef MLX90632_DEBUG
// Debug output // Debug output
Serial.print(F(" Cycle Position = ")); Serial.println(cycle_pos); Serial.print(F(" Mode = ")); Serial.println(meas_mode == MLX90632_MEAS_EXTENDED_RANGE ? F("Extended") : F("Medical"));
Serial.print(F(" RAM_4 = ")); Serial.println(ram4); if (meas_mode == MLX90632_MEAS_MEDICAL) {
Serial.print(F(" RAM_5 = ")); Serial.println(ram5); Serial.print(F(" Cycle Position = ")); Serial.println(readCyclePosition());
Serial.print(F(" RAM_6 = ")); Serial.println(ram6); }
Serial.print(F(" RAM_7 = ")); Serial.println(ram7); Serial.print(F(" RAM_ambient = ")); Serial.println(ram_ambient);
Serial.print(F(" RAM_8 = ")); Serial.println(ram8); Serial.print(F(" RAM_ref = ")); Serial.println(ram_ref);
Serial.print(F(" RAM_9 = ")); Serial.println(ram9);
Serial.print(F(" S = ")); Serial.println(S, 8); Serial.print(F(" S = ")); Serial.println(S, 8);
Serial.print(F(" Ka = ")); Serial.println(Ka, 8); Serial.print(F(" Ka = ")); Serial.println(Ka, 8);
Serial.print(F(" VRTO = ")); Serial.println(VRTO, 8); Serial.print(F(" VRTO = ")); Serial.println(VRTO, 8);

View file

@ -147,33 +147,46 @@ void setup() {
while (1) { delay(10); } while (1) { delay(10); }
} }
Serial.println(F("Calibration constants loaded successfully")); Serial.println(F("Calibration constants loaded successfully"));
// Clear new data flag before starting continuous measurements
Serial.println(F("\\n--- Starting Continuous Measurements ---"));
if (!mlx.resetNewData()) {
Serial.println(F("Failed to reset new data flag"));
while (1) { delay(10); }
}
Serial.println(F("New data flag reset - starting measurements"));
} }
void loop() { void loop() {
Serial.print(F("Device Busy: ")); // Only check new data flag - much more efficient for continuous mode
Serial.print(mlx.isBusy() ? F("YES") : F("NO")); if (mlx.isNewData()) {
Serial.print(F(" EEPROM Busy: ")); Serial.print(F("New Data Available - Cycle Position: "));
Serial.print(mlx.isEEPROMBusy() ? F("YES") : F("NO")); Serial.println(mlx.readCyclePosition());
Serial.print(F(" New Data: "));
Serial.print(mlx.isNewData() ? F("YES") : F("NO")); // Read ambient temperature
Serial.print(F(" Cycle Position: ")); double ambientTemp = mlx.getAmbientTemperature();
Serial.println(mlx.readCyclePosition()); Serial.print(F("Ambient Temperature: "));
Serial.print(ambientTemp, 4);
// Read ambient temperature
double ambientTemp = mlx.getAmbientTemperature();
Serial.print(F("Ambient Temperature: "));
Serial.print(ambientTemp, 4);
Serial.println(F(" °C"));
// Read object temperature
double objectTemp = mlx.getObjectTemperature();
Serial.print(F("Object Temperature: "));
if (isnan(objectTemp)) {
Serial.println(F("NaN (invalid cycle position)"));
} else {
Serial.print(objectTemp, 4);
Serial.println(F(" °C")); Serial.println(F(" °C"));
// Read object temperature
double objectTemp = mlx.getObjectTemperature();
Serial.print(F("Object Temperature: "));
if (isnan(objectTemp)) {
Serial.println(F("NaN (invalid cycle position)"));
} else {
Serial.print(objectTemp, 4);
Serial.println(F(" °C"));
}
// Reset new data flag after reading
if (!mlx.resetNewData()) {
Serial.println(F("Failed to reset new data flag"));
}
Serial.println(); // Add blank line between readings
} }
delay(500); // Small delay to prevent overwhelming the I2C bus
delay(10);
} }