Sensor de color TCS3200 con Arduino: conexión y calibración
Cómo funciona el sensor de color TCS3200: pines S0–S3, leer R, G, B con pulseIn, calibración con blanco y negro, distinguir colores y código ESP32 y Pico.
El sensor de color TCS3200 es el módulo de detección de color más usado en los proyectos con Arduino: mide el color de la superficie que tiene delante separándolo en sus componentes rojo, verde y azul. Convierte la luz que capta una matriz de fotodiodos directamente en una frecuencia: cuanta más luz roja refleja una superficie, más alta es la frecuencia del canal rojo. No necesitas lecturas analógicas ni un protocolo de comunicación especial; con la función pulseIn() de Arduino lees los valores R, G y B en unas pocas líneas. Con este sensor se construyen máquinas que clasifican caramelos de colores, robots que reconocen colores, vehículos que giran al ver marcas de color en el suelo y lámparas que copian el color del objeto que les pones delante.
En esta guía verás paso a paso qué hay dentro del sensor, para qué sirven los pines S0–S3, cómo conectarlo a Arduino Uno, ESP32 y Raspberry Pi Pico, cómo hacer lecturas en bruto, cómo realizar la calibración con blanco y negro y un algoritmo que averigua a qué color corresponde una lectura. Después montaremos la lógica de una máquina que clasifica objetos por color y, para terminar, lo compararemos con el TCS34725, un sensor que funciona por I2C.

¿Qué es el sensor de color TCS3200 y cómo funciona?
El chip TCS3200, el corazón del módulo (su versión anterior se llama TCS230), tiene en su superficie 64 fotodiodos en una cuadrícula de 8×8. Dieciséis de ellos llevan un filtro rojo, 16 uno verde, 16 uno azul y los 16 restantes no tienen filtro (clear) y ven la cantidad total de luz. Los 16 fotodiodos de cada color están conectados en paralelo, y los pines S2 y S3 eligen qué grupo se mide. Como los fotodiodos de distintos colores están intercalados en la matriz, la luz que cae en una esquina de la superficie afecta por igual a todos los grupos de color.
La pequeña corriente que produce el grupo de fotodiodos elegido llega a un convertidor de corriente a frecuencia dentro del chip. Este circuito genera una onda cuadrada con un ciclo de trabajo del 50 %, cuya frecuencia es directamente proporcional a la intensidad de la luz. Es decir, lo que mides no es una tensión, sino el número de pulsos por segundo: unos pocos hercios en completa oscuridad y decenas de kilohercios cerca de una superficie blanca. Lo bueno de una salida en frecuencia es que resiste bien el ruido y se puede conectar a cualquier pin digital de Arduino. Si solo quieres medir cuánta luz hay, un sensor de luz LDR es una opción más sencilla; el TCS3200 hace lo mismo por separado para tres colores.
| Característica | Valor |
|---|---|
| Chip | TCS3200 (versión anterior TCS230, compatible en pines) |
| Matriz de fotodiodos | 8×8 = 64: 16 rojos, 16 verdes, 16 azules, 16 sin filtro |
| Salida | Onda cuadrada con ciclo de trabajo del 50 %, frecuencia proporcional a la luz |
| Frecuencia a fondo de escala (típica) | 600 kHz (100 %), 120 kHz (20 %), 12 kHz (2 %) |
| Tensión de alimentación | 2,7–5,5 V |
| Consumo del chip | 1,4 mA típico (a esto se suma el consumo de los LED del módulo) |
| Pines de control | S0, S1 (escala de frecuencia), S2, S3 (filtro de color), OE (habilitación de salida, activo en LOW) |
| Distancia recomendada | Unos 1–3 cm, la misma en cada lectura |
| Iluminación | 4 LED blancos en el módulo |
Pines S0–S3: escala de frecuencia y selección del filtro de color
Cuatro pines de control determinan el comportamiento del TCS3200. S0 y S1 reducen la frecuencia de salida: al 100 % los pulsos se acortan hasta unos pocos microsegundos y ponen al límite la precisión de medida del Arduino Uno, mientras que al 2 % los pulsos se alargan, pero llegan menos en el mismo tiempo. S2 y S3 eligen qué filtro de color se lee. Conectas estos pines a salidas digitales de Arduino y los ajustas desde el código antes de cada lectura.
| S0 | S1 | Escala de la frecuencia de salida | ¿Cuándo usarla? |
|---|---|---|---|
| LOW | LOW | Apagado (power-down) | Para dormir el sensor en proyectos con batería |
| LOW | HIGH | 2 % (típico hasta 12 kHz) | Procesadores lentos, MicroPython y conteo con interrupciones |
| HIGH | LOW | 20 % (típico hasta 120 kHz) | El ajuste más adecuado para Arduino y pulseIn |
| HIGH | HIGH | 100 % (típico hasta 600 kHz) | Medidas rápidas con un contador por hardware |
| S2 | S3 | Grupo de fotodiodos leído |
|---|---|---|
| LOW | LOW | Con filtro rojo |
| LOW | HIGH | Con filtro azul |
| HIGH | LOW | Sin filtro (clear, luz total) |
| HIGH | HIGH | Con filtro verde |
Conexión del TCS3200: Arduino Uno, ESP32 y Pico
| Pin del módulo | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 3V3 | 3V3(OUT), pin 36 |
| GND | GND | GND | GND |
| S0 | D4 | GPIO 32 | GP2 |
| S1 | D5 | GPIO 33 | GP3 |
| S2 | D6 | GPIO 25 | GP4 |
| S3 | D7 | GPIO 26 | GP5 |
| OUT | D8 | GPIO 27 | GP6 |
| OE | GND | GND | GND |
Los cuatro LED blancos del módulo iluminan la superficie igual en cada lectura, así que los resultados son más coherentes aunque cambie la luz de la habitación. Algunas placas tienen un pin LED aparte para encender y apagar los LED; en otras se encienden en cuanto reciben alimentación, así que revisa las serigrafías de tu placa. Para obtener los mejores resultados, rodea el sensor con un tubo o cartulina negros, coloca el objeto siempre a la misma distancia y evita las superficies brillantes y reflectantes. Puedes comprobar la distribución de pines de tu placa con la herramienta Pinout.
Paso a paso: leer R, G y B con pulseIn
- Conecta el módulo como en la tabla anterior; OE a GND y VCC a 5V.
- Elige la escala de frecuencia del 20 % poniendo S0 en HIGH y S1 en LOW.
- Para el rojo, pon S2 y S3 en LOW y espera unos milisegundos a que la salida se estabilice.
- Mide en microsegundos la duración de la parte LOW del pulso con pulseIn(OUT, LOW); promedia 10 lecturas para reducir el ruido.
- Repite lo mismo para el verde (S2 HIGH, S3 HIGH) y el azul (S2 LOW, S3 HIGH).
- Sigue los resultados en el Monitor Serie a 9600 baudios y pon delante del sensor papeles de distintos colores.
1// TCS3200 ile ham R, G, B okuma / Raw R, G, B reading with the TCS3200
2const int S0 = 4;
3const int S1 = 5;
4const int S2 = 6;
5const int S3 = 7;
6const int OUT_PIN = 8;
7
8// Filtreyi seçer, 10 darbenin ortalama LOW süresini döndürür (µs) / Selects a filter, returns the average LOW time of 10 pulses (µs)
9unsigned long readPulse(bool s2, bool s3) {
10 digitalWrite(S2, s2 ? HIGH : LOW);
11 digitalWrite(S3, s3 ? HIGH : LOW);
12 delay(5); // çıkışın oturmasını bekle / let the output settle
13 unsigned long total = 0;
14 int count = 0;
15 for (int i = 0; i < 10; i++) {
16 unsigned long t = pulseIn(OUT_PIN, LOW, 50000UL); // 50 ms zaman aşımı / 50 ms timeout
17 if (t > 0) {
18 total += t;
19 count++;
20 }
21 }
22 return count > 0 ? total / count : 50000UL; // darbe yoksa çok karanlık / no pulse means very dark
23}
24
25void setup() {
26 pinMode(S0, OUTPUT);
27 pinMode(S1, OUTPUT);
28 pinMode(S2, OUTPUT);
29 pinMode(S3, OUTPUT);
30 pinMode(OUT_PIN, INPUT);
31 digitalWrite(S0, HIGH); // S0=HIGH, S1=LOW: %20 ölçek / 20% scaling
32 digitalWrite(S1, LOW);
33 Serial.begin(9600);
34}
35
36void loop() {
37 unsigned long r = readPulse(false, false); // kırmızı filtre / red filter
38 unsigned long g = readPulse(true, true); // yeşil filtre / green filter
39 unsigned long b = readPulse(false, true); // mavi filtre / blue filter
40 Serial.print("R: ");
41 Serial.print(r);
42 Serial.print(" G: ");
43 Serial.print(g);
44 Serial.print(" B: ");
45 Serial.println(b);
46 delay(500);
47}Lo más importante de este código es que el número leído es inversamente proporcional a la luz: cuanto menor es el valor, más luz llega de ese color. Si pones delante un papel rojo, verás algo como "R: 24 G: 68 B: 52"; el número más pequeño está en el canal rojo. El tiempo de espera de 50.000 µs que se pasa a pulseIn evita que el código espere el segundo completo que usa por defecto cuando no llega ningún pulso; si no se capta ningún pulso, la función devuelve 50.000, que significa "muy oscuro". Si te cuesta leer la salida del puerto serie, echa un vistazo a la guía del Monitor Serie de Arduino.
Calibración con blanco y negro: pasar los valores en bruto a 0–255
Los valores en bruto por sí solos engañan, porque los tres grupos de fotodiodos no tienen la misma sensibilidad y los LED blancos del módulo no emiten todos los colores por igual. Por eso hasta un papel blanquísimo da números distintos en los tres canales. La calibración elimina estas diferencias y coloca cada canal entre 0 (negro) y 255 (blanco); es la misma idea que el balance de blancos de una cámara. Calibra donde el sensor vaya a trabajar de verdad, con la misma luz y a la misma distancia; una calibración hecha sobre la mesa no sirve dentro de la carcasa de la máquina.
- Fija el sensor en un soporte y ajusta la distancia de medida (por ejemplo, 1,5 cm) para que no cambie.
- Pon delante un papel blanco liso, lee varias veces los valores R, G y B con el código anterior y anota sus promedios como referencia de blanco; son los valores más pequeños.
- Pon en el mismo sitio un papel negro mate o un fieltro y anota las lecturas como referencia de negro; son los valores más grandes.
- Escribe estos seis números en las constantes WHITE_ y BLACK_ al principio del siguiente código y súbelo.
- Comprueba que los tres canales den cerca de 255 con el papel blanco y cerca de 0 con el negro; si no, repite la medida con la misma luz y distancia.
Cuidado con un error que aparece en muchos ejemplos: convertir la duración del pulso directamente a 0–255 con map() no da un resultado correcto, porque la luz es proporcional a la frecuencia y no a la duración del pulso. Lo correcto es pasar primero la duración a frecuencia (1/t) y después escalar: nivel = (f − f_negro) / (f_blanco − f_negro) × 255. Veamos un ejemplo: mediste 20 µs con el blanco, 200 µs con el negro y el objeto dio 40 µs. map() lo convierte en 226, mientras que el método de la frecuencia da 113. La frecuencia del objeto es justo la mitad que la del blanco y, al restar el nivel del negro, eso corresponde a un 44 % de la escala, es decir, a 113; map(), en cambio, muestra los colores mucho más claros de lo que son y dificulta distinguir los tonos oscuros.
Algoritmo para distinguir colores: ¿qué color es esta lectura?
Los valores R, G, B calibrados siguen dependiendo de la cantidad de luz: si el mismo objeto rojo se acerca un poco al sensor, los tres valores suben a la vez. Para resolverlo, dividimos cada valor entre la suma: r = R / (R + G + B), y lo mismo con g y b. Estas proporciones de color se mantienen casi constantes aunque la distancia y el brillo cambien un poco. Después las comparas con las proporciones de referencia que mediste y guardaste una vez para cada color, y eliges el vecino más cercano. Para comparar basta con sumar los cuadrados de las diferencias; cuanto menor es ese número, más se parecen los colores. Si incluso la referencia más cercana está más lejos que cierto umbral, el resultado es "desconocido". Si la luz total es muy baja, el objeto se considera negro, y si los tres canales son muy altos, blanco; estos dos casos no se distinguen por las proporciones, así que se comprueban primero.
1// TCS3200 ile kalibrasyonlu renk tanıma / Calibrated color recognition with the TCS3200
2const int S0 = 4, S1 = 5, S2 = 6, S3 = 7, OUT_PIN = 8;
3
4// Kalibrasyonda ölçtüğün süreler (µs), kendi değerlerinle değiştir / Pulse widths from your calibration (µs), use your own
5const float WHITE_R = 16, WHITE_G = 20, WHITE_B = 18; // beyaz kağıt / white paper
6const float BLACK_R = 140, BLACK_G = 170, BLACK_B = 150; // siyah kağıt / black paper
7
8struct ColorRef {
9 const char *name;
10 float r, g, b; // renk oranları, toplamı 1 / color ratios, sum is 1
11};
12
13// Örnek referanslar, kendi ölçümlerinle değiştir / Sample references, replace with your own measurements
14ColorRef refs[] = {
15 {"Kirmizi / Red", 0.58, 0.20, 0.22},
16 {"Turuncu / Orange", 0.55, 0.30, 0.15},
17 {"Sari / Yellow", 0.42, 0.40, 0.18},
18 {"Yesil / Green", 0.24, 0.46, 0.30},
19 {"Mavi / Blue", 0.18, 0.30, 0.52},
20 {"Mor / Purple", 0.40, 0.20, 0.40}
21};
22const int REF_COUNT = sizeof(refs) / sizeof(refs[0]);
23const float MAX_DIST = 0.02; // bundan uzaksa bilinmiyor / farther than this is unknown
24
25unsigned long readPulse(bool s2, bool s3) {
26 digitalWrite(S2, s2 ? HIGH : LOW);
27 digitalWrite(S3, s3 ? HIGH : LOW);
28 delay(5);
29 unsigned long total = 0;
30 int count = 0;
31 for (int i = 0; i < 10; i++) {
32 unsigned long t = pulseIn(OUT_PIN, LOW, 50000UL);
33 if (t > 0) {
34 total += t;
35 count++;
36 }
37 }
38 return count > 0 ? total / count : 50000UL;
39}
40
41// Süreyi frekansa çevirip 0-255 arasına ölçekler / Converts the pulse width to frequency and scales it to 0-255
42float toLevel(unsigned long t, float tWhite, float tBlack) {
43 float f = 1.0 / t; // ışık frekansla orantılı / light is proportional to frequency
44 float fWhite = 1.0 / tWhite;
45 float fBlack = 1.0 / tBlack;
46 float level = (f - fBlack) / (fWhite - fBlack) * 255.0;
47 return constrain(level, 0.0, 255.0);
48}
49
50// En yakın referans rengi bulur / Finds the nearest reference color
51const char *classify(float R, float G, float B) {
52 float sum = R + G + B;
53 if (sum < 90) return "Siyah / Black"; // çok az ışık / very little light
54 if (R > 200 && G > 200 && B > 200) return "Beyaz / White";
55 float r = R / sum, g = G / sum, b = B / sum; // parlaklıktan bağımsız oranlar / brightness-independent ratios
56 int best = 0;
57 float bestDist = 1e9;
58 for (int i = 0; i < REF_COUNT; i++) {
59 float d = sq(r - refs[i].r) + sq(g - refs[i].g) + sq(b - refs[i].b); // uzaklığın karesi / squared distance
60 if (d < bestDist) {
61 bestDist = d;
62 best = i;
63 }
64 }
65 if (bestDist > MAX_DIST) return "Bilinmiyor / Unknown";
66 return refs[best].name;
67}
68
69void setup() {
70 pinMode(S0, OUTPUT);
71 pinMode(S1, OUTPUT);
72 pinMode(S2, OUTPUT);
73 pinMode(S3, OUTPUT);
74 pinMode(OUT_PIN, INPUT);
75 digitalWrite(S0, HIGH); // %20 ölçek / 20% scaling
76 digitalWrite(S1, LOW);
77 Serial.begin(9600);
78}
79
80void loop() {
81 float R = toLevel(readPulse(false, false), WHITE_R, BLACK_R);
82 float G = toLevel(readPulse(true, true), WHITE_G, BLACK_G);
83 float B = toLevel(readPulse(false, true), WHITE_B, BLACK_B);
84 float sum = R + G + B;
85 Serial.print("R=");
86 Serial.print(R, 0);
87 Serial.print(" G=");
88 Serial.print(G, 0);
89 Serial.print(" B=");
90 Serial.print(B, 0);
91 if (sum > 0) { // referans için oranlar / ratios for your references
92 Serial.print(" r=");
93 Serial.print(R / sum, 2);
94 Serial.print(" g=");
95 Serial.print(G / sum, 2);
96 Serial.print(" b=");
97 Serial.print(B / sum, 2);
98 }
99 Serial.print(" -> ");
100 Serial.println(classify(R, G, B));
101 delay(500);
102}| Parte del código | Función |
|---|---|
| WHITE_* y BLACK_* | Las duraciones de pulso de blanco y negro medidas en la calibración (µs) |
| toLevel() | Convierte la duración del pulso en frecuencia y la escala a 0–255 |
| refs[] | Proporciones r, g, b de referencia de cada color; cámbialas por tus propias medidas |
| classify() | Primero separa el negro y el blanco y luego busca la referencia más cercana |
| MAX_DIST | Las lecturas que superan esta distancia se consideran "Desconocido" |
Construir una máquina que clasifica objetos por color
El proyecto más popular con el TCS3200 es una máquina que clasifica caramelos de colores, cuentas o piezas de LEGO por color. El mecanismo tiene dos servos. El servo alimentador de arriba gira un disco con un agujero en el que cabe un solo objeto: primero recoge un objeto bajo el tubo de la tolva, luego lo lleva delante del sensor y, tras la lectura, lo deja caer en la rampa de abajo. El servo de la rampa, abajo, gira una rampa inclinada y envía el objeto al recipiente de su color. Si es la primera vez que usas servos, lee antes ¿Qué es un servomotor?.
- Coloca la tolva y un tubo un poco más ancho que los objetos para que caigan de uno en uno sobre el disco alimentador.
- Fija el sensor de modo que vea el objeto del disco a 1–2 cm y ciérralo para que no entre luz exterior.
- Define tres ángulos para el servo alimentador: carga, sensor y descarga. Encuéntralos probando en tu propio mecanismo; conecta el servo alimentador a D9 y el de la rampa a D10.
- Asigna un ángulo del servo de la rampa a cada recipiente de color (por ejemplo, rojo 30°, verde 75°, azul 120° y el resto 165°).
- Calibra dentro de la máquina, con su propia iluminación, y prueba con varios objetos de cada color.
1// TCS3200 ve iki servoyla renk ayırıcı / Color sorter with a TCS3200 and two servos
2#include <Servo.h>
3
4const int S0 = 4, S1 = 5, S2 = 6, S3 = 7, OUT_PIN = 8;
5const int FEEDER_PIN = 9; // besleme servosu / feeder servo
6const int CHUTE_PIN = 10; // yönlendirme servosu / chute servo
7
8const int LOAD_ANGLE = 160; // huninin altı / under the hopper
9const int SENSOR_ANGLE = 95; // sensörün önü / in front of the sensor
10const int DROP_ANGLE = 30; // bırakma deliği / drop hole
11
12// Kalibrasyon süreleri (µs) / Calibration pulse widths (µs)
13const float WHITE_R = 16, WHITE_G = 20, WHITE_B = 18;
14const float BLACK_R = 140, BLACK_G = 170, BLACK_B = 150;
15
16Servo feeder;
17Servo chute;
18
19unsigned long readPulse(bool s2, bool s3) {
20 digitalWrite(S2, s2 ? HIGH : LOW);
21 digitalWrite(S3, s3 ? HIGH : LOW);
22 delay(5);
23 unsigned long total = 0;
24 int count = 0;
25 for (int i = 0; i < 10; i++) {
26 unsigned long t = pulseIn(OUT_PIN, LOW, 50000UL);
27 if (t > 0) {
28 total += t;
29 count++;
30 }
31 }
32 return count > 0 ? total / count : 50000UL;
33}
34
35float toLevel(unsigned long t, float tWhite, float tBlack) {
36 float f = 1.0 / t;
37 float level = (f - 1.0 / tBlack) / (1.0 / tWhite - 1.0 / tBlack) * 255.0;
38 return constrain(level, 0.0, 255.0);
39}
40
41// Baskın kanala göre kutu açısını seçer / Picks the bin angle from the dominant channel
42int binAngle(float R, float G, float B) {
43 if (R + G + B < 90) return 165; // çok koyu: diğer kutusu / too dark: "other" bin
44 if (R > G * 1.3 && R > B * 1.3) return 30; // kırmızı kutusu / red bin
45 if (G > R * 1.3 && G > B * 1.3) return 75; // yeşil kutusu / green bin
46 if (B > R * 1.3 && B > G * 1.3) return 120; // mavi kutusu / blue bin
47 return 165; // karar verilemedi / undecided
48}
49
50void setup() {
51 pinMode(S0, OUTPUT);
52 pinMode(S1, OUTPUT);
53 pinMode(S2, OUTPUT);
54 pinMode(S3, OUTPUT);
55 pinMode(OUT_PIN, INPUT);
56 digitalWrite(S0, HIGH); // %20 ölçek / 20% scaling
57 digitalWrite(S1, LOW);
58 feeder.attach(FEEDER_PIN);
59 chute.attach(CHUTE_PIN);
60 feeder.write(LOAD_ANGLE);
61 delay(500);
62}
63
64void loop() {
65 feeder.write(LOAD_ANGLE); // huniden bir nesne al / take one object from the hopper
66 delay(600);
67 feeder.write(SENSOR_ANGLE); // sensörün önüne getir / bring it to the sensor
68 delay(600); // servo dursun, titreşim geçsin / let the servo settle
69 float R = toLevel(readPulse(false, false), WHITE_R, BLACK_R);
70 float G = toLevel(readPulse(true, true), WHITE_G, BLACK_G);
71 float B = toLevel(readPulse(false, true), WHITE_B, BLACK_B);
72 chute.write(binAngle(R, G, B)); // kanalı doğru kutuya çevir / aim the chute at the right bin
73 delay(400);
74 feeder.write(DROP_ANGLE); // nesneyi kanala bırak / drop the object into the chute
75 delay(600);
76}TCS3200 con ESP32: medir la frecuencia con una interrupción
El mismo código con pulseIn funciona en el ESP32, pero hay un método más estable: en lugar de medir los pulsos uno a uno, contar cuántos llegan en un tiempo fijo. Una interrupción incrementa un contador en cada flanco de subida; si multiplicas por 20 la cuenta al cabo de 50 ms, tienes la frecuencia en hercios. Como este método promedia cientos de pulsos, un solo pulso defectuoso no le afecta. El procesador de 240 MHz del ESP32 atiende sin problemas decenas de miles de interrupciones por segundo con la escala del 20 %; si con luz muy intensa la cuenta crece demasiado, puedes bajar la escala al 2 %. También puedes usar este método en Arduino Uno llevando OUT al pin D2, que admite interrupciones. En el ESP32 no olvides alimentar el módulo desde el pin 3V3.
1// ESP32: kesmeyle TCS3200 frekans ölçümü / ESP32: TCS3200 frequency measurement with an interrupt
2const int S0 = 32, S1 = 33, S2 = 25, S3 = 26, OUT_PIN = 27;
3
4volatile uint32_t pulseCount = 0;
5
6void IRAM_ATTR onPulse() {
7 pulseCount++; // her yükselen kenarda say / count every rising edge
8}
9
10// Seçilen filtrenin frekansını Hz olarak döndürür / Returns the frequency of the selected filter in Hz
11uint32_t readHz(bool s2, bool s3) {
12 digitalWrite(S2, s2 ? HIGH : LOW);
13 digitalWrite(S3, s3 ? HIGH : LOW);
14 delay(5); // çıkış otursun / let the output settle
15 pulseCount = 0;
16 delay(50); // 50 ms boyunca say / count for 50 ms
17 return pulseCount * 20; // 50 ms x 20 = 1 saniye / 1 second
18}
19
20void setup() {
21 Serial.begin(115200);
22 pinMode(S0, OUTPUT);
23 pinMode(S1, OUTPUT);
24 pinMode(S2, OUTPUT);
25 pinMode(S3, OUTPUT);
26 pinMode(OUT_PIN, INPUT);
27 digitalWrite(S0, HIGH); // %20 ölçek / 20% scaling
28 digitalWrite(S1, LOW);
29 attachInterrupt(digitalPinToInterrupt(OUT_PIN), onPulse, RISING);
30}
31
32void loop() {
33 uint32_t r = readHz(false, false); // kırmızı / red
34 uint32_t g = readHz(true, true); // yeşil / green
35 uint32_t b = readHz(false, true); // mavi / blue
36 Serial.print("R: ");
37 Serial.print(r);
38 Serial.print(" Hz G: ");
39 Serial.print(g);
40 Serial.print(" Hz B: ");
41 Serial.print(b);
42 Serial.println(" Hz");
43 delay(300);
44}TCS3200 con Raspberry Pi Pico y MicroPython
En la Pico, el equivalente del pulseIn de Arduino es la función machine.time_pulse_us(): devuelve en microsegundos la duración de un pulso al nivel pedido y un número negativo si se agota el tiempo. Si se llama cuando el pin ya está en ese nivel, empieza a medir de inmediato y puede medir medio pulso; por eso el código espera primero a que termine la parte HIGH y después mide la duración LOW. Como en MicroPython cada llamada a una función tarda unos microsegundos, aquí elegimos la escala del 2 % (S0=0, S1=1): los pulsos son 10 veces más largos y el efecto de ese retraso se reduce. Los valores de calibración se escriben en Hz; con la escala del 2 % es normal ver unos pocos kHz con el papel blanco y unos cientos de Hz con el negro. Alimenta el módulo desde el pin 3V3(OUT) de la Pico; si es tu primera vez con la Pico, ¿Qué es la Raspberry Pi Pico? explica cómo instalar MicroPython.
1# Pico + TCS3200: süreden frekansa ve 0-255 seviyesine / Pico + TCS3200: from pulse width to frequency and a 0-255 level
2from machine import Pin, time_pulse_us
3import time
4
5s0 = Pin(2, Pin.OUT)
6s1 = Pin(3, Pin.OUT)
7s2 = Pin(4, Pin.OUT)
8s3 = Pin(5, Pin.OUT)
9out = Pin(6, Pin.IN)
10
11s0.value(0) # S0=0, S1=1: %2 ölçek / 2% scaling
12s1.value(1)
13
14FILTERS = {"R": (0, 0), "G": (1, 1), "B": (0, 1)} # S2, S3 değerleri / S2, S3 values
15WHITE_HZ = {"R": 3125, "G": 2500, "B": 2778} # beyaz kağıtta Hz / Hz on white paper
16BLACK_HZ = {"R": 357, "G": 294, "B": 333} # siyah kağıtta Hz / Hz on black paper
17
18def read_hz(channel, samples=10):
19 s2.value(FILTERS[channel][0])
20 s3.value(FILTERS[channel][1])
21 time.sleep_ms(5) # çıkış otursun / let the output settle
22 total = 0
23 count = 0
24 for _ in range(samples):
25 time_pulse_us(out, 1, 50000) # HIGH bitsin, LOW başında ol / wait for HIGH to end
26 t = time_pulse_us(out, 0, 50000) # LOW süresi, µs / LOW time, µs
27 if t > 0: # negatif = zaman aşımı / negative = timeout
28 total += t
29 count += 1
30 if count == 0:
31 return 0
32 return 1000000 / (2 * total / count) # f = 1 / (2t)
33
34def level(channel, hz):
35 v = (hz - BLACK_HZ[channel]) / (WHITE_HZ[channel] - BLACK_HZ[channel]) * 255
36 return max(0, min(255, int(v)))
37
38while True:
39 r = level("R", read_hz("R"))
40 g = level("G", read_hz("G"))
41 b = level("B", read_hz("B"))
42 print("R:", r, "G:", g, "B:", b)
43 time.sleep(0.5)¿TCS3200 o TCS34725?
El TCS34725 es un sensor de color más reciente que hace el mismo trabajo por I2C. Mide dentro del propio chip y entrega los resultados como números de 16 bits por canal; Arduino no tiene que medir pulsos. Su diferencia más importante es el filtro de bloqueo de infrarrojos (IR) que lleva sobre los fotodiodos. El TCS3200 no tiene ese filtro; como los fotodiodos de silicio también son sensibles al infrarrojo, las lecturas se desvían con luz rica en IR, como la del sol o la de las bombillas incandescentes. Como la ganancia (1x, 4x, 16x, 60x) y el tiempo de integración (2,4–614 ms) del TCS34725 se ajustan por software, funciona en un rango amplio, desde luz muy tenue hasta luz intensa. Si te interesa saber cómo funciona I2C, consulta el artículo ¿Qué es I2C?.

| Característica | TCS3200 | TCS34725 |
|---|---|---|
| Salida | Frecuencia (onda cuadrada) | I2C, dirección 0x29 |
| Cables de señal | S0–S3, OUT y OE | SDA y SCL (INT y LED opcionales) |
| Resolución | Depende del método y del tiempo de medida | 16 bits por canal |
| Filtro IR | No | Sí (sobre el chip) |
| Ajustes | 3 escalas de frecuencia y apagado | 4 ganancias, tiempo de integración de 2,4–614 ms |
| Alimentación | 2,7–5,5 V | Chip a 3,3 V; módulos con regulador a 3–5 V |
| Iluminación | Normalmente 4 LED blancos | Normalmente 1 LED blanco |
| Carga del procesador | Ocupado mientras mide pulsos | El chip mide, Arduino solo lee |
| Ideal para | Aprender, clasificadores de color sencillos | Color preciso, temperatura de color y medida de lux |
1// TCS34725 ile ham RGBC, renk sıcaklığı ve lüks / Raw RGBC, color temperature and lux with the TCS34725
2#include <Wire.h>
3#include <Adafruit_TCS34725.h>
4
5// 50 ms entegrasyon süresi, 4x kazanç / 50 ms integration time, 4x gain
6Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
7
8void setup() {
9 Serial.begin(9600);
10 if (!tcs.begin()) { // 0x29 adresinde ara / look for it at 0x29
11 Serial.println("TCS34725 bulunamadi / not found");
12 while (true) {
13 delay(1000);
14 }
15 }
16}
17
18void loop() {
19 uint16_t r, g, b, c;
20 tcs.getRawData(&r, &g, &b, &c); // 16 bit ham değerler / 16-bit raw values
21 uint16_t kelvin = tcs.calculateColorTemperature_dn40(r, g, b, c);
22 uint16_t lux = tcs.calculateLux(r, g, b);
23 Serial.print("R: ");
24 Serial.print(r);
25 Serial.print(" G: ");
26 Serial.print(g);
27 Serial.print(" B: ");
28 Serial.print(b);
29 Serial.print(" C: ");
30 Serial.print(c);
31 Serial.print(" K: ");
32 Serial.print(kelvin);
33 Serial.print(" Lux: ");
34 Serial.println(lux);
35 delay(500);
36}Antes de subir el código, instala la biblioteca Adafruit TCS34725 desde el Gestor de bibliotecas; cuando te pregunte por las dependencias, elige instalarlas todas. En Arduino Uno conecta SDA a A4 y SCL a A5; en el ESP32, a GPIO 21 y 22. getRawData() espera el tiempo de integración y devuelve los valores en bruto de rojo, verde, azul y sin filtro (C); calculateColorTemperature_dn40() da la temperatura de color en kelvin y calculateLux(), el nivel de iluminación aproximado. La calibración y la lógica del color más cercano valen igual para este sensor. Si quieres un sensor que, además del color, detecte gestos de la mano y proximidad, el APDS-9960 es una buena alternativa.
Ideas de proyectos con el TCS3200
- Máquina clasificadora de colores: Separa caramelos, cuentas o piezas de LEGO en recipientes distintos según su color.
- Lámpara que copia colores: Reproduce el color del objeto que pones delante del sensor con un LED RGB o una tira WS2812B.
- Robot que lee colores: Enseña a tu robot seguidor de línea a pararse en una marca roja del suelo y a seguir en una verde.
- Brazo robótico que reconoce colores: Usa un brazo robótico para coger cubos y dejar cada color en su propio recipiente.
- Detector de colores que habla: Anuncia el color detectado con un audio pregrabado en un DFPlayer Mini; es una ayuda práctica para personas con discapacidad visual.
- Control del color del agua: Sigue los cambios de color del agua de un recipiente transparente con el tiempo y avisa en un acuario o en un depósito de riego.
Errores frecuentes y soluciones
| Síntoma | Causa probable | Solución |
|---|---|---|
| pulseIn siempre devuelve 0 o el valor de tiempo de espera | OE al aire o en HIGH, S0 y S1 los dos en LOW (apagado) u OUT en el pin equivocado | Conecta OE a GND, pon S0 en HIGH y S1 en LOW, compara el pin OUT con el código |
| Los valores saltan sin parar | Luz ambiente, una lámpara que parpadea o una distancia que cambia | Cubre el sensor con un tubo negro, fija la distancia, promedia varias lecturas |
| Todos los objetos salen del mismo color | Sin calibrar; los canales tienen distinta sensibilidad | Haz la calibración con blanco y negro y vuelve a medir las referencias |
| Los colores se desvían con luz de día | El TCS3200 no tiene filtro IR | Mide dentro de una caja cerrada o usa un TCS34725 |
| Los niveles se quedan pegados en 0 o 255 | El objeto está a otra distancia que en la calibración | Mantén la misma distancia que al calibrar y recalibra si hace falta |
| El ESP32 o la Pico se comportan de forma rara | Módulo alimentado a 5 V, OUT da 5 V | Alimenta el módulo desde 3V3 o usa un convertidor de nivel |
| Las lecturas fallan cuando gira el servo | La corriente del servo hace caer la tensión de alimentación | Usa una fuente de 5 V aparte para los servos y une los GND |
El TCS3200 es un sensor estupendo para aprender cómo la luz se convierte en frecuencia, por qué es necesaria la calibración y cómo se construye un algoritmo de clasificación sencillo. Pasar al TCS34725 cuando necesites más precisión también es fácil, porque la calibración y la lógica del color más cercano que has aprendido siguen valiendo igual. En la app BlueGrays encontrarás proyectos de mezcla de colores con LED RGB, una lámpara mezcladora de colores con ESP32, medición de luz con LDR y proyectos con servomotores, con esquemas de circuito y código paso a paso, y puedes combinarlos con el sensor de color para construir tu propia máquina.
Preguntas frecuentes
¿A qué distancia detecta colores el sensor TCS3200?
Los resultados más estables se obtienen a unos 1–3 cm, porque la luz de los LED del módulo se debilita rápidamente con la distancia. Más importante que la distancia en sí es mantenerla igual en cada lectura, y también debes calibrar a esa distancia. Este sensor no sirve para leer el color de superficies grandes y lejanas.
¿Qué diferencia hay entre el TCS230 y el TCS3200?
El TCS230 es el sensor de color más antiguo del mismo fabricante y el TCS3200 es su versión mejorada. Ambos usan una matriz de fotodiodos de 8×8, salida en frecuencia y la misma lógica de control S0–S3, así que la conexión y el código son los mismos. La mayoría de los módulos que se venden hoy llevan un TCS3200.
¿Por qué pulseIn devuelve 0 con el TCS3200?
pulseIn devuelve 0 cuando no ve ningún pulso dentro del tiempo de espera indicado. Las causas más habituales son el pin OE sin conectar a GND, S0 y S1 los dos en LOW (el sensor entra en modo de apagado) y OUT conectado a un pin distinto del que pone el código. Si delante del sensor está completamente oscuro, la frecuencia baja a unos pocos hercios y con un tiempo de espera corto no se capta ningún pulso.
¿El TCS3200 funciona con ESP32 y Raspberry Pi Pico?
Sí. Como el TCS3200 funciona entre 2,7 y 5,5 V, puedes alimentar el módulo desde el pin 3V3 de la placa, y así el pin OUT también da pulsos de 3,3 V. Si lo alimentas con 5 V, necesitas un divisor de tensión o un convertidor de nivel en la línea OUT. Al medir con MicroPython en la Pico, la escala de frecuencia del 2 % da resultados más precisos.
¿Qué es mejor, el TCS3200 o el TCS34725?
Para medir el color con precisión es mejor el TCS34725: tiene filtro de bloqueo de IR, resolución de 16 bits por canal y ganancia ajustable, y se conecta con solo dos cables I2C. El TCS3200 es una opción muy extendida y suficiente para aprender a medir frecuencias y calibrar, y para construir clasificadores de color sencillos.
¿Cuántos colores puede distinguir el sensor TCS3200?
Con luz controlada y a distancia fija, el TCS3200 separa de forma fiable entre 6 y 8 colores claramente distintos, como rojo, naranja, amarillo, verde, azul, morado, negro y blanco. También se pueden distinguir tonos cercanos, como el verde claro y el oscuro, pero hace falta una calibración más cuidadosa, muchas medidas de referencia por tono y un umbral estricto.
Proyectos para hacer después de leer esto
Ver todos los proyectos
Medir la intensidad de luz con LDR
¿Quieres ver en números cuánta luz hay en tu habitación? El LDR, una pequeña pieza sensible a la luz, mide la luz ambiente y el Arduino escribe el valor en la pantalla del ordenador cada medio segundo

Lectura de la intensidad luminosa con el módulo LDR del ESP32
Visualización en tiempo real en el monitor serie del valor bruto del ADC del módulo LDR y del porcentaje relativo de luz calculado a partir de referencias de oscuridad y claridad. Este porcentaje no es una medición en lux. Explica el funcionamiento de la calibración del módulo. Es recomendable realizarlo antes del Proyecto 10, ya que se utiliza para determinar el valor umbral.

Uso de Led RGB
Dentro de un solo LED se esconden tres colores: el LED RGB se enciende en rojo, luego en verde y luego en azul, cada color medio segundo encendido y medio segundo apagado, y la secuencia vuelve a empe

Transición de color suave con Led RGB
Un solo LED RGB pasa lentamente del rojo al verde, del verde al azul y vuelve al rojo, en un bucle de arcoíris que nunca se detiene. Cada transición dura unos dos segundos y medio, y los amarillos, tu

Lámpara con mezclador de colores ESP32 (3 potenciómetros + LED RGB + OLED)
¡Una lámpara mezcladora de colores inteligente que combina el color que quieras girando tres potenciómetros con el ESP32! A medida que giras los potenciómetros de rojo, verde y azul, el LED RGB de cátodo común cambia de color al instante. En la pantalla OLED SSD1306 se muestran en tiempo real los valores de cada color en un rango de 0 a 255, barras de relleno visuales y el código de color HEX para la web (como #FF8040). Un miniestudio de color profesional: enseña la teoría del color RGB, la lect

Control de LED RGB con ESP32
Generación ilimitada de colores con un solo LED RGB en lugar de 3 LEDs separados. Hacemos transición arco iris estableciendo valores R/G/B con analogWrite() como en Arduino. La teoría del color (como rojo+verde=amarillo) se ve de forma práctica.

Uso del servomotor
El brazo de un pequeño servomotor gira por turnos a tres posiciones: al principio del todo, justo al centro y al final del todo, esperando dos segundos en cada parada. El Arduino le dice al motor en q

TCRT5000 Detección de superficie blanca y negra
Con el pequeño sensor que hace de ojo en los robots sigue líneas, sabrás si el suelo es negro o blanco. El TCRT5000 lanza una luz invisible hacia el suelo y mira cuánta vuelve; sobre blanco se enciend
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

