Componentes · 15 min de lectura

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.

Módulo sensor de color TCS3200
Módulo sensor de color TCS3200: en el centro el chip TCS3200 de 8 patas, en las cuatro esquinas LED blancos que iluminan la superficie; a un lado los pines S0, S1, OE, GND y al otro VCC, OUT, S2, S3.

¿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ísticaValor
ChipTCS3200 (versión anterior TCS230, compatible en pines)
Matriz de fotodiodos8×8 = 64: 16 rojos, 16 verdes, 16 azules, 16 sin filtro
SalidaOnda 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ón2,7–5,5 V
Consumo del chip1,4 mA típico (a esto se suma el consumo de los LED del módulo)
Pines de controlS0, S1 (escala de frecuencia), S2, S3 (filtro de color), OE (habilitación de salida, activo en LOW)
Distancia recomendadaUnos 1–3 cm, la misma en cada lectura
Iluminación4 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.

S0S1Escala de la frecuencia de salida¿Cuándo usarla?
LOWLOWApagado (power-down)Para dormir el sensor en proyectos con batería
LOWHIGH2 % (típico hasta 12 kHz)Procesadores lentos, MicroPython y conteo con interrupciones
HIGHLOW20 % (típico hasta 120 kHz)El ajuste más adecuado para Arduino y pulseIn
HIGHHIGH100 % (típico hasta 600 kHz)Medidas rápidas con un contador por hardware
S2S3Grupo de fotodiodos leído
LOWLOWCon filtro rojo
LOWHIGHCon filtro azul
HIGHLOWSin filtro (clear, luz total)
HIGHHIGHCon filtro verde
La relación entre la duración del pulso y la frecuencia es sencilla: como el ciclo de trabajo es del 50 %, la parte LOW dura medio periodo. Con la fórmula f = 1 / (2 × t) conviertes en frecuencia los microsegundos que da pulseIn. Por ejemplo, si t = 25 µs, f = 1 / (2 × 0,000025 s) = 20 kHz. Con la escala del 20 % y los LED del módulo encendidos, lo normal es ver valores entre 10 y 200 µs.

Conexión del TCS3200: Arduino Uno, ESP32 y Pico

Pin del móduloArduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT), pin 36
GNDGNDGNDGND
S0D4GPIO 32GP2
S1D5GPIO 33GP3
S2D6GPIO 25GP4
S3D7GPIO 26GP5
OUTD8GPIO 27GP6
OEGNDGNDGND
No dejes el pin OE al aire. Es activo en LOW; si queda en HIGH o desconectado, la salida pasa a alta impedancia y pulseIn devuelve 0 todo el rato. Además, los pines del ESP32 y de la Pico trabajan a 3,3 V: si alimentas el módulo con 5 V, el pin OUT da pulsos de 5 V y fuerza la entrada de la placa. En estas placas alimenta el módulo desde 3V3 o pon un divisor de tensión o un convertidor de nivel lógico en la línea OUT.

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

  1. Conecta el módulo como en la tabla anterior; OE a GND y VCC a 5V.
  2. Elige la escala de frecuencia del 20 % poniendo S0 en HIGH y S1 en LOW.
  3. Para el rojo, pon S2 y S3 en LOW y espera unos milisegundos a que la salida se estabilice.
  4. Mide en microsegundos la duración de la parte LOW del pulso con pulseIn(OUT, LOW); promedia 10 lecturas para reducir el ruido.
  5. Repite lo mismo para el verde (S2 HIGH, S3 HIGH) y el azul (S2 LOW, S3 HIGH).
  6. Sigue los resultados en el Monitor Serie a 9600 baudios y pon delante del sensor papeles de distintos colores.
C++ (Arduino IDE)
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.

  1. Fija el sensor en un soporte y ajusta la distancia de medida (por ejemplo, 1,5 cm) para que no cambie.
  2. 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.
  3. 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.
  4. Escribe estos seis números en las constantes WHITE_ y BLACK_ al principio del siguiente código y súbelo.
  5. 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.

C++ (Arduino IDE)
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ódigoFunció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_DISTLas lecturas que superan esta distancia se consideran "Desconocido"
No adivines los valores de referencia, mídelos: pon delante del sensor un objeto de cada color entre 5 y 10 veces, promedia las proporciones r, g, b que aparecen en el Monitor Serie y escríbelas en el array refs[]. Mide con la luz y a la distancia en que trabajará la máquina. Si las lecturas bailan, ayuda promediar varias lecturas o aplicar un filtro de mediana; tienes más detalles en el artículo sobre filtrado de datos de sensores.

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?.

  1. 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.
  2. Fija el sensor de modo que vea el objeto del disco a 1–2 cm y ciérralo para que no entre luz exterior.
  3. 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.
  4. 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°).
  5. Calibra dentro de la máquina, con su propia iluminación, y prueba con varios objetos de cada color.
C++ (Arduino IDE)
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}
Alimentar los servos desde el pin 5V de Arduino puede hacer que la tensión caiga al moverse y que la placa se reinicie; esa caída también estropea las lecturas de color. Alimenta los dos servos con una fuente de 5 V aparte y une su GND con el GND de Arduino. No midas mientras un servo se mueve; como en el código, añade una breve pausa cuando el servo llegue a su posición.

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.

C++ (Arduino IDE)
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.

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?.

Módulo sensor de color I2C TCS34725
Módulo sensor de color TCS34725: en el centro el chip sensor de color con filtro IR, a su lado un LED blanco; pines LED, INT, SDA, SCL, 3V3, GND y VIN.
CaracterísticaTCS3200TCS34725
SalidaFrecuencia (onda cuadrada)I2C, dirección 0x29
Cables de señalS0–S3, OUT y OESDA y SCL (INT y LED opcionales)
ResoluciónDepende del método y del tiempo de medida16 bits por canal
Filtro IRNoSí (sobre el chip)
Ajustes3 escalas de frecuencia y apagado4 ganancias, tiempo de integración de 2,4–614 ms
Alimentación2,7–5,5 VChip a 3,3 V; módulos con regulador a 3–5 V
IluminaciónNormalmente 4 LED blancosNormalmente 1 LED blanco
Carga del procesadorOcupado mientras mide pulsosEl chip mide, Arduino solo lee
Ideal paraAprender, clasificadores de color sencillosColor preciso, temperatura de color y medida de lux
C++ (Arduino IDE)
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íntomaCausa probableSolución
pulseIn siempre devuelve 0 o el valor de tiempo de esperaOE al aire o en HIGH, S0 y S1 los dos en LOW (apagado) u OUT en el pin equivocadoConecta OE a GND, pon S0 en HIGH y S1 en LOW, compara el pin OUT con el código
Los valores saltan sin pararLuz ambiente, una lámpara que parpadea o una distancia que cambiaCubre el sensor con un tubo negro, fija la distancia, promedia varias lecturas
Todos los objetos salen del mismo colorSin calibrar; los canales tienen distinta sensibilidadHaz la calibración con blanco y negro y vuelve a medir las referencias
Los colores se desvían con luz de díaEl TCS3200 no tiene filtro IRMide dentro de una caja cerrada o usa un TCS34725
Los niveles se quedan pegados en 0 o 255El objeto está a otra distancia que en la calibraciónMantén la misma distancia que al calibrar y recalibra si hace falta
El ESP32 o la Pico se comportan de forma raraMódulo alimentado a 5 V, OUT da 5 VAlimenta el módulo desde 3V3 o usa un convertidor de nivel
Las lecturas fallan cuando gira el servoLa corriente del servo hace caer la tensión de alimentaciónUsa una fuente de 5 V aparte para los servos y une los GND
Las superficies brillantes y reflectantes (metal, plástico pulido, papel satinado) devuelven la luz de los LED directamente al sensor y hacen que los colores parezcan más pálidos de lo que son. Inclinar un poco el sensor en lugar de colocarlo totalmente perpendicular, o trabajar con objetos mates, reduce mucho el problema. Si solo necesitas distinguir el negro del blanco, el TCRT5000 es una opción más sencilla y rápida.

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.

Ver todos los proyectos
Medir la intensidad de luz con LDR
#11Principiante

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

4.6(81)
139
Lectura de la intensidad luminosa con el módulo LDR del ESP32
#113Principiante

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.

4.6(36)
55
Uso de Led RGB
#39Principiante
Premium

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

4.9(73)
98
Transición de color suave con Led RGB
#40Principiante
Premium

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

4.8(58)
76
Lámpara con mezclador de colores ESP32 (3 potenciómetros + LED RGB + OLED)
#138Avanzado
Premium

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

4.7(6)
10
Control de LED RGB con ESP32
#111Principiante

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.

4.6(29)
51
Uso del servomotor
#35Principiante
Premium

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

4.7(48)
67
TCRT5000 Detección de superficie blanca y negra
#78Intermedio
Premium

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

4.7(40)
49