Adafruit TCS34725: red, green, blue and clear counts
The TCS34725 is an RGB color sensor with a fourth, unfiltered clear channel, usually sold on a breakout with a white LED beside it to light whatever it is pointed at. Adafruit’s library talks to it at 0x29 and returns four 16-bit counts per reading.
Built in on Mokxi: #include <Adafruit_TCS34725.h> and it builds, with nothing to install. Free, and no account needed.
What Adafruit TCS34725 does
Two settings decide what those counts mean. The integration time, from 2.4 ms to around 700 ms, is how long the chip gathers light before it reports, and the gain multiplies the result by 1, 4, 16 or 60. A short time and low gain suit a bright scene; a dark object needs more of both. Push too far and the counts pin at the top, so keep an eye on the clear channel.
Raw counts depend on how bright the light is as much as on the color. Sorting projects divide each of red, green and blue by their total, which gives shares that hold steady as brightness changes, and compare those with a table of known colors. The color sorter below does exactly that before swinging its servo to a bin. calculateLux() and calculateColorTemperature_dn40() turn the same counts into lux and kelvin, and the clear-channel interrupt with its persistence is simulated as well.
| Library Manager name | Adafruit TCS34725 |
|---|---|
| Author | Adafruit |
| Include | #include <Adafruit_TCS34725.h> |
| Boards | every board Mokxi compiles for but ATtiny85 |
| In the simulator | Simulated: it runs against the part the way it does on the bench. |
| Parts it drives | Color sensor, TCS34725 |
Install it
It builds on every board Mokxi compiles for but ATtiny85.
In Mokxi it is built in: #include <Adafruit_TCS34725.h> and the sketch compiles, with no download, no zip and no Library Manager.
On a real board, install "Adafruit TCS34725" by Adafruit from the Arduino IDE’s Library Manager (Sketch, Include Library, Manage Libraries), or add Adafruit TCS34725 to lib_deps in PlatformIO. Mokxi follows the calls of release 1.4.4, so a sketch written here builds there too.
- ESP32-C3
- Arduino Uno
- Arduino Nano
- Arduino Mega 2560
- Arduino Leonardo
- SparkFun Pro Micro
- Arduino Micro
- ESP32-C6
- WCH CH32V003
- Raspberry Pi Pico
- Raspberry Pi Pico W
- Seeed XIAO SAMD21
- STM32
- STM32 Nucleo-F411RE
- STM32 Blue Pill
- micro:bit V2
- Arduino Uno R4
- ESP32 DevKit
- ESP32-S3-DevKitC-1
- ESP8266 NodeMCU
- Arduino Pro Mini 3.3 V
- Seeed XIAO ESP32-C3
- ESP32-C3 SuperMini
- Seeed XIAO ESP32-C6
- ESP32-DevKitC V4
- LOLIN32 Lite
- Wemos D1 R32
- Cheap Yellow Display
- TTGO T-Display
- Seeed XIAO ESP32-S3
- Arduino Nano ESP32
- Arduino Nano RP2040 Connect
- Seeed XIAO RP2040
- Waveshare RP2040-Zero
- Arduino Uno R4 WiFi
The calls you will use
In the order a sketch meets them.
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X)
Creates the driver with an integration time and a gain. With no arguments it uses 2.4 ms and 1x, which reads close to zero indoors.
tcs.begin()
Reads the ID register, applies the settings and starts the color cycles. Returns false when nothing answers at 0x29.
tcs.getRawData(&r, &g, &b, &c)
The four counts as uint16_t. It then waits one integration time, so a long setting slows loop() by that much.
uint16_t r, g, b, c;
tcs.getRawData(&r, &g, &b, &c);tcs.calculateColorTemperature_dn40(r, g, b, c)
Correlated color temperature in kelvin from all four counts. calculateColorTemperature(r, g, b) is the older three-count method.
tcs.calculateLux(r, g, b)
An estimate of illuminance in lux worked out from the three color counts.
tcs.setGain(TCS34725_GAIN_16X)
Changes the gain while running; setIntegrationTime(TCS34725_INTEGRATIONTIME_154MS) does the same for the time. Auto-ranging code steps these up or down from the clear count.
tcs.getRGB(&red, &green, &blue)
Each channel as a share of the clear count scaled to 0 to 255, as floats, ready to drive an RGB LED.
tcs.setInterrupt(true)
Enables the clear-channel interrupt. setIntLimits(low, high) sets the window it watches, and clearInterrupt() releases the INT pin after it fires.
Example: Color sorter
On the Arduino Uno R3. It runs in the browser exactly as printed.
// Color sorter: a TCS34725 looks at the candy in front of it and a servo
// swings the chute to that color's bin, as in the candy and bead sorters
// people build.
//
// TCS34725 SDA -> A4 SCL -> A5 VIN -> 5 V GND -> GND (LED left high: lit)
// servo signal -> 9 red -> 5 V brown -> GND
//
// The sensor gives four counts: red, green, blue and clear. Their shares of
// the total say what color it is whatever the brightness, so the sketch
// compares them with a table of the six colors it knows, measured once with
// the LED on, and picks the nearest. A low clear count is an empty chute.
//
// In the simulator the sorter's feed disc brings the candies one at a time:
// watch the chute move, and the candy land in its bin.
#include <Wire.h>
#include <Servo.h>
#include "Adafruit_TCS34725.h"
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
Servo chute;
const int SERVO_PIN = 9;
const uint16_t EMPTY_BELOW = 1500; // clear count of the empty chute
struct Reference {
const char *name;
uint16_t red, green, blue; // shares of the total, in thousandths
uint8_t angle; // where the chute points for this bin
};
const Reference COLORS[] = {
{"red", 647, 203, 148, 15},
{"orange", 566, 342, 90, 45},
{"yellow", 475, 431, 92, 75},
{"green", 192, 524, 283, 105},
{"blue", 137, 313, 549, 135},
{"purple", 324, 243, 431, 165},
};
const uint8_t COUNT = sizeof(COLORS) / sizeof(COLORS[0]);
int8_t last = -2;
void setup() {
Serial.begin(9600);
chute.attach(SERVO_PIN);
chute.write(90);
if (!tcs.begin()) {
Serial.println("No TCS34725 found ... check your connections");
while (1) delay(10);
}
Serial.println("Color sorter ready");
}
// The nearest color in the table, or -1 for an empty chute.
int8_t classify(uint16_t r, uint16_t g, uint16_t b, uint16_t c) {
if (c < EMPTY_BELOW) return -1;
uint32_t total = (uint32_t)r + g + b;
int32_t rs = (uint32_t)r * 1000 / total;
int32_t gs = (uint32_t)g * 1000 / total;
int32_t bs = (uint32_t)b * 1000 / total;
int8_t best = 0;
int32_t bestDistance = 0x7fffffff;
for (uint8_t i = 0; i < COUNT; i++) {
int32_t dr = rs - COLORS[i].red;
int32_t dg = gs - COLORS[i].green;
int32_t db = bs - COLORS[i].blue;
int32_t d = dr * dr + dg * dg + db * db;
if (d < bestDistance) {
bestDistance = d;
best = i;
}
}
return best;
}
void loop() {
uint16_t r, g, b, c;
tcs.getRawData(&r, &g, &b, &c);
int8_t color = classify(r, g, b, c);
if (color == last) return;
last = color;
if (color < 0) {
Serial.println("chute empty");
return;
}
Serial.print(COLORS[color].name);
Serial.print(" -> bin ");
Serial.print(color + 1);
Serial.print(" (R ");
Serial.print(r);
Serial.print(" G ");
Serial.print(g);
Serial.print(" B ");
Serial.print(b);
Serial.print(" C ");
Serial.print(c);
Serial.println(")");
chute.write(COLORS[color].angle);
delay(300);
}Open it in the editor, wired and ready to run · Color sorter: the project page
Common errors and how to fix them
No TCS34725 found ... check your connections
begin() saw no reply or the wrong ID at 0x29. Check the bus wiring, and that no other device on the same wires uses 0x29, such as a VL53L0X or VL53L1X distance sensor.
All four counts read 0 or close to it
The default constructor uses 2.4 ms at 1x, far too little for a room. Pass a longer time and more gain, as the sorter does with 50 ms and 4x, and make sure the LED is lit.
Every object is classified as the same color
The counts are probably saturated, typically from the LED at close range with a high gain. Lower the gain or the time until the clear count stays well below 65535, then measure the color table again.
Colors change when the room lights change
Raw counts mix brightness into color. Divide red, green and blue by their sum and compare those shares, with the sensor’s own LED doing the lighting.
Questions and answers
What is the clear channel for?
It sees all visible light with no color filter, so it measures brightness. The sorter uses a low clear count to tell an empty chute from a candy.
Which integration time should I start with?
The tutorial’s 50 ms at 4x is a fair start under the module’s LED. Lengthen it for dark objects and shorten it if the clear count nears the top.
Projects that use Adafruit TCS34725
Built-in projects that include it. Each page has the full sketch and opens in the editor, already wired.
Try Adafruit TCS34725 without installing anything
Open the example, change the sketch, and keep your version in a free account.