Add calculateLux function and improve test coverage

- Add calculateLux() function using datasheet resolution tables
- Support both 1/2 PD and 2/2 PD configurations
- Add RGB gain and interrupt persistence tests to example
- Add green threshold setter/getter tests
- Optimize loop delay based on integration time + 5ms buffer
- Add lux calculation display in test output

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ladyada 2025-08-17 14:23:15 -04:00
parent 18f7d1812a
commit 77715e7a5d
3 changed files with 267 additions and 2 deletions

View file

@ -398,4 +398,160 @@ bool Adafruit_VEML6046::getData(uint16_t* r, uint16_t* g, uint16_t* b,
*ir = buffer[6] | (buffer[7] << 8);
return true;
}
/*!
* @brief Calculates lux value from green channel count
* @param green_count Raw green channel reading
* @return Calculated lux value
*/
float Adafruit_VEML6046::calculateLux(uint16_t green_count) {
// Get current settings to determine resolution factor
veml6046_integration_time_t it = getIntegrationTime();
veml6046_gain_t gain = getRGBGain();
bool half_pd = getPhotoDiodeHalfSize();
float resolution = 0.0;
// Resolution table from datasheet (lx/cnt)
// TABLE 13 - 2/2 PD USED, TABLE 14 - 1/2 PD USED
if (half_pd) {
// 1/2 PD used - TABLE 14
switch (it) {
case VEML6046_IT_400MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0105; break;
case VEML6046_GAIN_1X: resolution = 0.0210; break;
case VEML6046_GAIN_0_66X: resolution = 0.0318; break;
case VEML6046_GAIN_0_5X: resolution = 0.0420; break;
}
break;
case VEML6046_IT_200MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0210; break;
case VEML6046_GAIN_1X: resolution = 0.0420; break;
case VEML6046_GAIN_0_66X: resolution = 0.0636; break;
case VEML6046_GAIN_0_5X: resolution = 0.0840; break;
}
break;
case VEML6046_IT_100MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0420; break;
case VEML6046_GAIN_1X: resolution = 0.0840; break;
case VEML6046_GAIN_0_66X: resolution = 0.1273; break;
case VEML6046_GAIN_0_5X: resolution = 0.1680; break;
}
break;
case VEML6046_IT_50MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0840; break;
case VEML6046_GAIN_1X: resolution = 0.1680; break;
case VEML6046_GAIN_0_66X: resolution = 0.2545; break;
case VEML6046_GAIN_0_5X: resolution = 0.3360; break;
}
break;
case VEML6046_IT_25MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.1680; break;
case VEML6046_GAIN_1X: resolution = 0.3360; break;
case VEML6046_GAIN_0_66X: resolution = 0.5091; break;
case VEML6046_GAIN_0_5X: resolution = 0.6720; break;
}
break;
case VEML6046_IT_12_5MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.3360; break;
case VEML6046_GAIN_1X: resolution = 0.6720; break;
case VEML6046_GAIN_0_66X: resolution = 1.0182; break;
case VEML6046_GAIN_0_5X: resolution = 1.3440; break;
}
break;
case VEML6046_IT_6_25MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.6720; break;
case VEML6046_GAIN_1X: resolution = 1.3440; break;
case VEML6046_GAIN_0_66X: resolution = 2.0364; break;
case VEML6046_GAIN_0_5X: resolution = 2.6880; break;
}
break;
case VEML6046_IT_3_125MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 1.3440; break;
case VEML6046_GAIN_1X: resolution = 2.6880; break;
case VEML6046_GAIN_0_66X: resolution = 4.0727; break;
case VEML6046_GAIN_0_5X: resolution = 5.3760; break;
}
break;
}
} else {
// 2/2 PD used - TABLE 13
switch (it) {
case VEML6046_IT_400MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0053; break;
case VEML6046_GAIN_1X: resolution = 0.0105; break;
case VEML6046_GAIN_0_66X: resolution = 0.0159; break;
case VEML6046_GAIN_0_5X: resolution = 0.0210; break;
}
break;
case VEML6046_IT_200MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0105; break;
case VEML6046_GAIN_1X: resolution = 0.0210; break;
case VEML6046_GAIN_0_66X: resolution = 0.0318; break;
case VEML6046_GAIN_0_5X: resolution = 0.0420; break;
}
break;
case VEML6046_IT_100MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0210; break;
case VEML6046_GAIN_1X: resolution = 0.0420; break;
case VEML6046_GAIN_0_66X: resolution = 0.0636; break;
case VEML6046_GAIN_0_5X: resolution = 0.0840; break;
}
break;
case VEML6046_IT_50MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0420; break;
case VEML6046_GAIN_1X: resolution = 0.0840; break;
case VEML6046_GAIN_0_66X: resolution = 0.1273; break;
case VEML6046_GAIN_0_5X: resolution = 0.1680; break;
}
break;
case VEML6046_IT_25MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.0840; break;
case VEML6046_GAIN_1X: resolution = 0.1680; break;
case VEML6046_GAIN_0_66X: resolution = 0.2545; break;
case VEML6046_GAIN_0_5X: resolution = 0.3360; break;
}
break;
case VEML6046_IT_12_5MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.1680; break;
case VEML6046_GAIN_1X: resolution = 0.3360; break;
case VEML6046_GAIN_0_66X: resolution = 0.5091; break;
case VEML6046_GAIN_0_5X: resolution = 0.6720; break;
}
break;
case VEML6046_IT_6_25MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.3360; break;
case VEML6046_GAIN_1X: resolution = 0.6720; break;
case VEML6046_GAIN_0_66X: resolution = 1.0182; break;
case VEML6046_GAIN_0_5X: resolution = 1.3440; break;
}
break;
case VEML6046_IT_3_125MS:
switch (gain) {
case VEML6046_GAIN_2X: resolution = 0.6720; break;
case VEML6046_GAIN_1X: resolution = 1.3440; break;
case VEML6046_GAIN_0_66X: resolution = 2.0364; break;
case VEML6046_GAIN_0_5X: resolution = 2.6880; break;
}
break;
}
}
return green_count * resolution;
}

View file

@ -125,6 +125,8 @@ class Adafruit_VEML6046 {
bool getData(uint16_t* r, uint16_t* g, uint16_t* b, uint16_t* ir);
float calculateLux(uint16_t green_count);
private:
Adafruit_I2CDevice* i2c_dev; ///< Pointer to I2C bus interface
};

View file

@ -8,6 +8,7 @@
#include "Adafruit_VEML6046.h"
Adafruit_VEML6046 veml = Adafruit_VEML6046();
uint16_t sample_delay_ms = 30; // Will be calculated in setup
void setup() {
Serial.begin(115200);
@ -111,12 +112,111 @@ void setup() {
bool green_int_enabled = veml.getGreenIntEnabled();
Serial.print(F("Green interrupt enabled: "));
Serial.println(green_int_enabled ? F("Yes") : F("No"));
// Test RGB gain setter/getter
Serial.println(F("Setting RGB gain to 1x"));
if (veml.setRGBGain(VEML6046_GAIN_1X)) {
Serial.println(F("RGB gain set successfully"));
} else {
Serial.println(F("Failed to set RGB gain"));
}
// Read back and display current RGB gain
veml6046_gain_t current_gain = veml.getRGBGain();
Serial.print(F("Current RGB gain: "));
switch (current_gain) {
case VEML6046_GAIN_1X:
Serial.println(F("1x"));
break;
case VEML6046_GAIN_2X:
Serial.println(F("2x"));
break;
case VEML6046_GAIN_0_66X:
Serial.println(F("0.66x"));
break;
case VEML6046_GAIN_0_5X:
Serial.println(F("0.5x"));
break;
default:
Serial.println(F("Unknown"));
break;
}
// Test interrupt persistence setter/getter
Serial.println(F("Setting interrupt persistence to 1"));
if (veml.setIntPersistence(VEML6046_PERS_1)) {
Serial.println(F("Interrupt persistence set successfully"));
} else {
Serial.println(F("Failed to set interrupt persistence"));
}
// Read back and display current persistence
veml6046_persistence_t current_pers = veml.getIntPersistence();
Serial.print(F("Current interrupt persistence: "));
switch (current_pers) {
case VEML6046_PERS_1:
Serial.println(F("1 time"));
break;
case VEML6046_PERS_2:
Serial.println(F("2 times"));
break;
case VEML6046_PERS_4:
Serial.println(F("4 times"));
break;
case VEML6046_PERS_8:
Serial.println(F("8 times"));
break;
default:
Serial.println(F("Unknown"));
break;
}
// Test green threshold setter/getter
Serial.println(F("Setting green thresholds: low=1000, high=10000"));
if (veml.setGreenThresholdLow(1000)) {
Serial.println(F("Green low threshold set successfully"));
} else {
Serial.println(F("Failed to set green low threshold"));
}
if (veml.setGreenThresholdHigh(10000)) {
Serial.println(F("Green high threshold set successfully"));
} else {
Serial.println(F("Failed to set green high threshold"));
}
// Read back and display current thresholds
uint16_t low_thresh = veml.getGreenThresholdLow();
uint16_t high_thresh = veml.getGreenThresholdHigh();
Serial.print(F("Current green thresholds - Low: "));
Serial.print(low_thresh);
Serial.print(F(", High: "));
Serial.println(high_thresh);
// Calculate optimal delay based on current integration time + 5ms buffer
current_it = veml.getIntegrationTime();
sample_delay_ms = 5; // Base 5ms buffer
switch (current_it) {
case VEML6046_IT_3_125MS: sample_delay_ms += 4; break; // 3.125ms rounded up
case VEML6046_IT_6_25MS: sample_delay_ms += 7; break; // 6.25ms rounded up
case VEML6046_IT_12_5MS: sample_delay_ms += 13; break; // 12.5ms rounded up
case VEML6046_IT_25MS: sample_delay_ms += 25; break;
case VEML6046_IT_50MS: sample_delay_ms += 50; break;
case VEML6046_IT_100MS: sample_delay_ms += 100; break;
case VEML6046_IT_200MS: sample_delay_ms += 200; break;
case VEML6046_IT_400MS: sample_delay_ms += 400; break;
default: sample_delay_ms += 25; break; // Default fallback
}
Serial.print(F("Using sample delay: "));
Serial.print(sample_delay_ms);
Serial.println(F("ms"));
}
void loop() {
// Read RGBIR data in continuous mode
uint16_t r, g, b, ir;
if (veml.getData(&r, &g, &b, &ir)) {
float lux = veml.calculateLux(g);
Serial.print(F("R: "));
Serial.print(r);
Serial.print(F(" G: "));
@ -124,10 +224,17 @@ void loop() {
Serial.print(F(" B: "));
Serial.print(b);
Serial.print(F(" IR: "));
Serial.println(ir);
Serial.print(ir);
Serial.print(F(" Lux: "));
Serial.println(lux, 2);
} else {
Serial.println(F("Failed to read data"));
}
delay(1000);
// If in forced mode, trigger next reading
if (veml.getRGBModeForced()) {
veml.RGBTrigger();
}
delay(sample_delay_ms);
}