Skip to product information
1 of 4

Color Sensor (VEML6040)

Color Sensor (VEML6040)

SKU:AX22-0010

Add precise RGBW color sensing to any project with this AX22 module built around the VEML6040. Measure red, green, blue, and white light channels with 16-bit resolution, perfect for color matching, ambient light detection, or display calibration. Two onboard STEMMA QT connectors let you daisy-chain I²C devices. An ENABLE pin gives you hardware control to disable the sensor when needed, handy since the VEML6040's I²C address is fixed and can't be changed. There's also an onboard LED you can toggle for extra illumination in low-light scenarios. Drop it into any AX22 backplane and start reading color data in minutes with Arduino IDE, MicroPython, or MicroBlocks.
Regular price $9.99
Regular price Sale price $9.99
Sale Sold out
View full details

Technical Details

- 22 mm × 22 mm square
- 4× ⌀2.7 mm Mounting Holes
- 100kΩ to 200kΩ
- 3.3 V, 5.0 V
- VEML6040 RGBW color sensor, 16-bit
- 2× STEMMA QT connectors
- ENABLE pin for hardware disable
- Onboard illumination LED (software control)
- Fixed I²C address 0x10
- I²C interface
- Arduino IDE Compatible
- MicroPython Compatible
- MicroBlocks Compatible

Material Datasheet →

Pinout

Technical Resources

Color Sensor (VEML6040) - (AX22-0010)
🖱️ Click & drag to rotate
#include <Wire.h>
#include "veml6040.h"

#define LED_PIN P1_IO2
#define LED_BRIGHTNESS 1  // 0-255

VEML6040 sensor;
float rTrim = 1.0, gTrim = 1.0, bTrim = 1.0;

void setup() {
  Serial.begin(115200);
  delay(1000);

  pinMode(LED_PIN, OUTPUT);
  analogWrite(LED_PIN, LED_BRIGHTNESS);

  Wire.begin();
  sensor.begin();
  sensor.setConfiguration(VEML6040_IT_160MS + VEML6040_AF_AUTO + VEML6040_SD_ENABLE);
  delay(1000);

  // ---- Auto white balance ----
  Serial.println("Hold a WHITE object under the sensor...");
  delay(3000);

  uint16_t r = sensor.getRed();
  uint16_t g = sensor.getGreen();
  uint16_t b = sensor.getBlue();
  uint16_t maxC = max(r, max(g, b));
  rTrim = (float)maxC / r;
  gTrim = (float)maxC / g;
  bTrim = (float)maxC / b;

  Serial.println("Calibrated! Point at colors now.");
  Serial.println();
}

void loop() {
  float r = sensor.getRed() * rTrim;
  float g = sensor.getGreen() * gTrim;
  float b = sensor.getBlue() * bTrim;
  uint16_t w = sensor.getWhite();

  Serial.print("-> ");
  Serial.println(detectColor(r, g, b, w));
  delay(300);
}

const char* detectColor(float r, float g, float b, uint16_t w) {
  if (w < 300) return "BLACK / nothing";

  float maxC = max(r, max(g, b));
  float minC = min(r, min(g, b));

  // After white balance, R ~= G ~= B means white/gray
  if ((maxC - minC) / maxC < 0.15) {
    return (w > 4000) ? "WHITE" : "GRAY";
  }

  // Dominant channel decides the family
  if (r >= g && r >= b) {
    if (g > b * 1.3) return "ORANGE / YELLOW";
    if (b > g * 1.3) return "PINK / MAGENTA";
    return "RED";
  }
  if (g >= r && g >= b) {
    if (r > b * 1.3) return "YELLOW";
    return "GREEN";
  }
  // blue is max
  if (g > r * 1.3) return "CYAN";
  if (r > g * 1.3) return "PURPLE";
  return "BLUE";
}