Sensor de cor TCS3200 com Arduino: ligações, calibração e código
Como funciona o sensor de cor TCS3200: ajustes de S0–S3, leitura de R, G e B com pulseIn, calibração de branco e preto, separação por cores e código para ESP32, Pico e TCS34725.
O sensor de cor TCS3200 é o módulo de detecção de cor mais usado em projetos Arduino: ele mede a cor da superfície à sua frente separando-a em componentes vermelho, verde e azul. Ele converte a luz captada por uma matriz de fotodiodos direto em uma frequência: quanto mais luz vermelha uma superfície reflete, maior a frequência no canal vermelho. Não há leitura analógica nem protocolo de comunicação especial; você lê os valores de R, G e B em poucas linhas com o comando pulseIn() do Arduino. Máquinas que separam balas, robôs que reconhecem cores, veículos que mudam de direção em marcas coloridas no chão e luminárias que copiam a cor de um objeto colocado na frente delas são todos feitos com este sensor.
Neste guia você vai ver, passo a passo, o que há dentro do sensor, para que servem os pinos S0–S3, como ligá-lo a um Arduino Uno, a um ESP32 e a um Raspberry Pi Pico, como fazer leituras brutas, como fazer uma calibração de branco e preto e um algoritmo que descobre a qual cor uma leitura pertence. Depois vamos montar a lógica de uma máquina que separa objetos por cor e, por fim, comparar com o TCS34725, um sensor que funciona por I2C.

O que é o sensor de cor TCS3200 e como ele funciona?
O chip TCS3200 no coração do módulo (a versão mais antiga se chama TCS230) tem 64 fotodiodos em uma grade de 8×8 na superfície. Dezesseis deles ficam sob filtros vermelhos, 16 sob verdes, 16 sob azuis, e os outros 16 não têm filtro (clear) e veem a quantidade total de luz. Os 16 fotodiodos de cada cor são ligados em paralelo, e os pinos S2 e S3 escolhem qual grupo é medido. Como os fotodiodos de cores diferentes estão intercalados na matriz, a luz que cai em um canto da superfície afeta igualmente todos os grupos de cor.
A pequena corrente produzida pelo grupo de fotodiodos selecionado vai para um conversor de corrente em frequência dentro do chip. Esse circuito gera uma onda quadrada com ciclo de trabalho de 50%, e a frequência da onda é diretamente proporcional à intensidade da luz. Então o que você mede não é uma tensão, e sim o número de pulsos por segundo: alguns hertz no escuro total, dezenas de quilohertz perto de uma superfície branca. A vantagem de uma saída em frequência é que ela é robusta contra ruído e pode ser ligada a qualquer pino digital do Arduino. Se você só quer medir a intensidade da luz, um sensor de luz LDR é uma opção mais simples; o TCS3200 faz o mesmo trabalho separadamente para três cores.
| Característica | Valor |
|---|---|
| Chip | TCS3200 (versão antiga TCS230, compatível nos pinos) |
| Matriz de fotodiodos | 8×8 = 64: 16 vermelhos, 16 verdes, 16 azuis, 16 sem filtro |
| Saída | Onda quadrada com ciclo de trabalho de 50%, frequência proporcional à luz |
| Frequência de fundo de escala (típica) | 600 kHz (100%), 120 kHz (20%), 12 kHz (2%) |
| Tensão de alimentação | 2,7–5,5 V |
| Corrente do chip | 1,4 mA típica (a corrente dos LEDs do módulo vem por cima) |
| Pinos de controle | S0, S1 (escala de frequência), S2, S3 (filtro de cor), OE (habilitação da saída, ativo em LOW) |
| Distância recomendada | Cerca de 1–3 cm, a mesma em todas as leituras |
| Iluminação | 4 LEDs brancos no módulo |
Pinos S0–S3: escala de frequência e escolha do filtro de cor
Quatro pinos de controle definem como o TCS3200 se comporta. S0 e S1 reduzem a frequência de saída: em 100% os pulsos encolhem para alguns microssegundos e forçam os limites de precisão de medição do Arduino Uno, enquanto em 2% os pulsos ficam mais longos, mas chegam menos deles no mesmo tempo. S2 e S3 escolhem qual filtro de cor é lido. Você liga esses pinos às saídas digitais do Arduino e os ajusta pelo código antes de cada leitura.
| S0 | S1 | Escala da frequência de saída | Quando usar |
|---|---|---|---|
| LOW | LOW | Desligado (power down) | Para pôr o sensor para dormir em projetos com bateria |
| LOW | HIGH | 2% (tipicamente até 12 kHz) | Processadores lentos, MicroPython e contagem por interrupção |
| HIGH | LOW | 20% (tipicamente até 120 kHz) | O melhor ajuste para Arduino e pulseIn |
| HIGH | HIGH | 100% (tipicamente até 600 kHz) | Medições rápidas com um contador de hardware |
| S2 | S3 | Grupo de fotodiodos lido |
|---|---|---|
| LOW | LOW | Filtro vermelho |
| LOW | HIGH | Filtro azul |
| HIGH | LOW | Sem filtro (clear, luz total) |
| HIGH | HIGH | Filtro verde |
Ligações do TCS3200: Arduino Uno, ESP32 e Pico
| Pino do módulo | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 3V3 | 3V3(OUT), pino 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 |
Os quatro LEDs brancos do módulo iluminam a superfície do mesmo jeito em toda leitura, então os resultados ficam mais consistentes mesmo quando a iluminação da sala muda. Algumas placas têm um pino LED separado para ligar e desligar os LEDs, enquanto em outras os LEDs acendem assim que a alimentação é ligada; confira as marcações da sua placa. Para os melhores resultados, envolva o sensor em um tubo preto ou em papelão, traga o objeto sempre à mesma distância e evite superfícies brilhantes e reflexivas. Você pode conferir a disposição dos pinos da sua placa na ferramenta Pinagem.
Passo a passo: lendo R, G e B com pulseIn
- Ligue o módulo como na tabela acima; ligue o OE ao GND e o VCC ao 5V.
- Escolha a escala de frequência de 20% pondo S0 em HIGH e S1 em LOW.
- Para o vermelho, ponha S2 e S3 em LOW e espere alguns milissegundos para a saída se estabilizar.
- Meça em microssegundos a duração da parte em LOW do pulso com pulseIn(OUT, LOW); faça a média de 10 leituras para reduzir o ruído.
- Repita o mesmo para o verde (S2 HIGH, S3 HIGH) e para o azul (S2 LOW, S3 HIGH).
- Acompanhe os resultados no Monitor Serial em 9600 baud e ponha folhas de papel de cores diferentes na frente do sensor.
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}O ponto mais importante deste código é que o número lido é inversamente proporcional à luz: quanto menor o valor, mais luz vem daquela cor. Quando você mostra uma folha vermelha, vai ver uma saída como “R: 24 G: 68 B: 52”; o menor número está no canal vermelho. O tempo limite de 50.000 µs passado ao pulseIn impede o código de esperar o 1 segundo padrão quando nenhum pulso chega; se nenhum pulso for captado, a função retorna 50.000, o que significa “muito escuro”. Se tiver dificuldade para ler a saída serial, dê uma olhada no guia do Monitor Serial do Arduino.
Calibração de branco e preto: transformando valores brutos em 0–255
Os valores brutos, sozinhos, enganam, porque os três grupos de fotodiodos não têm a mesma sensibilidade e os LEDs brancos do módulo não emitem todas as cores por igual. Por isso, até uma folha perfeitamente branca dá números diferentes nos três canais. A calibração elimina essas diferenças e coloca cada canal entre 0 (preto) e 255 (branco); é a mesma ideia do balanço de branco de uma câmera. Faça a calibração onde o sensor vai trabalhar de verdade, com a mesma luz e na mesma distância; uma calibração feita na sua mesa não vale dentro do gabinete da máquina.
- Monte o sensor em um suporte fixo e defina a distância de medição (por exemplo, 1,5 cm) de modo que ela não mude.
- Ponha uma folha branca lisa na frente dele, leia os valores de R, G e B várias vezes com o código acima e anote as médias como a referência de branco; estes são os menores valores.
- Ponha uma folha preta fosca ou um feltro no mesmo lugar e anote as leituras como a referência de preto; estes são os maiores valores.
- Ponha esses seis números nas constantes WHITE_ e BLACK_ no topo do código abaixo e carregue.
- Confira se os três canais marcam perto de 255 no papel branco e perto de 0 no preto; se não, repita a medição com a mesma luz e a mesma distância.
Cuidado com um erro presente em muitos exemplos: converter a largura do pulso direto para 0–255 com map() não dá o resultado certo, porque a luz é proporcional à frequência, não à largura do pulso. O jeito correto é converter primeiro a largura em frequência (1/t) e depois escalar: nível = (f − f_preto) / (f_branco − f_preto) × 255. Vejamos um exemplo: você mediu 20 µs no branco, 200 µs no preto, e o objeto deu 40 µs. O map() transforma isso em 226, enquanto o método da frequência dá 113. A frequência do objeto é exatamente metade da do branco e, descontado o nível do preto, isso corresponde a cerca de 44% da escala, ou 113; o map(), por outro lado, mostra as cores muito mais claras do que são e dificulta distinguir tons escuros.
Algoritmo de classificação de cores: qual cor é esta leitura?
Os valores calibrados de R, G e B ainda dependem da quantidade de luz: quando o mesmo objeto vermelho chega um pouco mais perto do sensor, os três valores sobem juntos. Para corrigir isso, dividimos cada valor pelo total: r = R / (R + G + B), e o mesmo para g e b. Essas proporções de cor ficam quase constantes mesmo quando a distância e o brilho mudam um pouco. Depois você as compara com proporções de referência medidas e salvas uma vez para cada cor e escolhe o vizinho mais próximo. Para a comparação, basta somar os quadrados das diferenças entre as proporções; quanto menor esse número, mais parecidas são as cores. Se até a referência mais próxima estiver mais longe que um certo limite, o resultado é “desconhecido”. Se a luz total for muito baixa, o objeto é tratado como preto e, se os três canais forem muito altos, como branco; esses dois casos não podem ser distinguidos pelas proporções, então são verificados primeiro.
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 do código | O que faz |
|---|---|
| WHITE_* e BLACK_* | As larguras de pulso de branco e preto que você mediu na calibração (µs) |
| toLevel() (conversão para nível) | Converte a largura do pulso em frequência e a escala para 0–255 |
| refs[] (referências) | Proporções r, g, b de referência de cada cor; troque pelas suas próprias medições |
| classify() (classificação) | Separa primeiro o preto e o branco e depois acha a referência mais próxima |
| MAX_DIST (distância máxima) | Leituras mais distantes que isso contam como “Unknown” (desconhecida) |
Montando uma máquina que separa objetos por cor
O projeto mais popular com o TCS3200 é uma máquina que separa por cor balas coloridas, miçangas ou peças de LEGO. O mecanismo tem dois servos. O servo alimentador de cima gira um disco com um furo em que cabe exatamente um objeto: primeiro ele pega um objeto embaixo do tubo do funil, depois o leva para a frente do sensor e, depois da leitura, o solta na calha de baixo. O servo da calha de baixo gira uma calha inclinada para mandar o objeto para o recipiente da cor dele. Se é a primeira vez que você usa servos, leia antes O que é um servo motor?.
- Monte o funil e um tubo um pouco mais largo que os objetos, para que eles caiam um de cada vez no disco alimentador.
- Monte o sensor de modo que ele veja o objeto no disco a 1–2 cm de distância e feche-o para não entrar luz de fora.
- Escolha três ângulos para o servo alimentador: carga, sensor e descarga. Encontre-os por tentativa no seu próprio mecanismo; ligue o servo alimentador ao D9 e o servo da calha ao D10.
- Atribua um ângulo a cada recipiente de cor para o servo da calha (por exemplo, vermelho 30°, verde 75°, azul 120°, todo o resto 165°).
- Calibre dentro da máquina, com a iluminação da própria máquina, e teste com vários objetos de cada cor.
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 com ESP32: medindo a frequência com interrupção
O mesmo código com pulseIn roda no ESP32, mas há um método mais estável: em vez de cronometrar os pulsos um por um, conte quantos pulsos chegam em um tempo fixo. Uma interrupção incrementa um contador a cada borda de subida; multiplique a contagem depois de 50 ms por 20 e você tem a frequência em hertz. Como esse método faz a média de centenas de pulsos, um único pulso ruim não o afeta. O processador de 240 MHz do ESP32 aguenta com folga dezenas de milhares de interrupções por segundo na escala de 20%; se a contagem ficar grande demais com luz muito forte, você pode baixar a escala para 2%. Você também pode usar o mesmo método no Arduino Uno passando o OUT para o D2, que suporta interrupções. No ESP32, não esqueça de alimentar o módulo pelo pino 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 com Raspberry Pi Pico e MicroPython
No Pico, o equivalente ao pulseIn do Arduino é a função machine.time_pulse_us(): ela retorna em microssegundos a duração de um pulso no nível pedido e um número negativo em caso de tempo esgotado. Se for chamada com o pino já nesse nível, ela começa a cronometrar na hora e pode medir meio pulso; por isso o código primeiro espera a parte em HIGH terminar e depois mede o tempo em LOW. Como cada chamada de função no MicroPython leva alguns microssegundos, escolhemos aqui a escala de 2% (S0=0, S1=1): os pulsos ficam 10 vezes mais longos e o efeito desse atraso diminui. Os valores de calibração são escritos em Hz; na escala de 2%, é normal ver alguns kHz no papel branco e algumas centenas de Hz no preto. Alimente o módulo pelo pino 3V3(OUT) do Pico; se você é novo no Pico, O que é o Raspberry Pi Pico? explica como instalar o 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 ou TCS34725?
O TCS34725 é um sensor de cor mais novo que faz o mesmo trabalho por I2C. Ele faz a medição dentro do chip e devolve os resultados como números de 16 bits por canal, então o Arduino não precisa cronometrar pulsos. A diferença mais importante é o filtro de bloqueio de infravermelho (IR) sobre os fotodiodos. O TCS3200 não tem esse filtro; como os fotodiodos de silício também são sensíveis ao infravermelho, as leituras se desviam com luz rica em IR, como a do sol ou de lâmpadas incandescentes. Como o ganho (1x, 4x, 16x, 60x) e o tempo de integração (2,4–614 ms) do TCS34725 podem ser ajustados por software, ele funciona em uma faixa ampla, de luz muito fraca a forte. Se tem curiosidade sobre como o I2C funciona, veja o artigo O que é I2C?.

| Característica | TCS3200 | TCS34725 |
|---|---|---|
| Saída | Frequência (onda quadrada) | I2C, endereço 0x29 |
| Fios de sinal | S0–S3, OUT e OE | SDA e SCL (INT e LED opcionais) |
| Resolução | Depende do método e do tempo de medição | 16 bits por canal |
| Filtro IR | Não | Sim (no chip) |
| Ajustes | 3 escalas de frequência e desligamento | 4 ganhos, tempo de integração de 2,4–614 ms |
| Alimentação | 2,7–5,5 V | Chip de 3,3 V; módulos com regulador de 3–5 V |
| Iluminação | Geralmente 4 LEDs brancos | Geralmente 1 LED branco |
| Carga no processador | Ocupado enquanto cronometra os pulsos | O chip mede, o Arduino só lê |
| Ideal para | Aprender, separadores de cor simples | Medição precisa de cor, temperatura de cor e 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 carregar o código, instale a biblioteca Adafruit TCS34725 pelo Gerenciador de Bibliotecas; quando ela perguntar sobre as dependências, escolha instalar todas. No Arduino Uno, ligue o SDA ao A4 e o SCL ao A5; no ESP32, use os GPIO 21 e 22. getRawData() espera o tempo de integração e retorna os valores brutos de vermelho, verde, azul e sem filtro (C); calculateColorTemperature_dn40() dá a temperatura de cor em kelvin, e calculateLux() um nível de luz aproximado. A calibração e a lógica da cor mais próxima valem do mesmo jeito para este sensor. Se você quer um sensor que detecte gestos e proximidade além da cor, o APDS-9960 é uma boa alternativa.
Ideias de projetos com o TCS3200
- Máquina separadora de cores: separe balas, miçangas ou peças de LEGO em recipientes diferentes por cor.
- Luminária que copia cores: reproduza a cor do objeto que você põe na frente do sensor com um LED RGB ou uma fita WS2812B.
- Robô que lê cores: ensine o seu robô seguidor de linha a parar em uma marca vermelha no chão e seguir em uma verde.
- Braço robótico que reconhece cores: use um braço robótico para pegar cubos e soltar cada cor no próprio recipiente.
- Detector de cores falante: anuncie a cor detectada com um som pré-gravado em um DFPlayer Mini; é uma ajuda prática para pessoas com deficiência visual.
- Monitor da cor da água: acompanhe ao longo do tempo as mudanças de cor da água em um recipiente transparente e dispare um aviso para um aquário ou um reservatório de irrigação.
Erros comuns e como corrigir
| Sintoma | Causa provável | Solução |
|---|---|---|
| O pulseIn sempre retorna 0 ou o valor do tempo limite | OE solto ou em HIGH, S0 e S1 ambos em LOW (desligado) ou OUT no pino errado | Ligue o OE ao GND, ponha S0 em HIGH e S1 em LOW, compare o pino OUT com o código |
| Os valores ficam pulando | Luz do ambiente, uma lâmpada que pisca ou uma distância que muda | Proteja o sensor com um tubo preto, fixe a distância, faça a média de várias leituras |
| Todo objeto aparece com a mesma cor | Sem calibração; os canais têm sensibilidades diferentes | Faça a calibração de branco e preto, meça as referências de novo |
| As cores se desviam com a luz do dia | O TCS3200 não tem filtro IR | Meça dentro de uma caixa fechada ou use um TCS34725 |
| Os níveis ficam presos em 0 ou 255 | O objeto está em uma distância diferente da usada na calibração | Mantenha a mesma distância da calibração, recalibre se preciso |
| O ESP32 ou o Pico se comporta de forma estranha | Módulo alimentado com 5 V, o OUT sai com 5 V | Alimente o módulo pelo 3V3 ou use um conversor de nível |
| As leituras erram quando o servo se move | A corrente do servo derruba a tensão de alimentação | Use uma fonte de 5 V separada para os servos e una os GNDs |
O TCS3200 é um ótimo sensor para aprender como a luz vira frequência, por que a calibração importa e como montar um algoritmo de classificação simples. Passar para o TCS34725 quando você precisar de mais precisão também é fácil, porque a calibração e a lógica da cor mais próxima que você aprendeu continuam iguais. No app BlueGrays você encontra projetos de mistura de cores com LED RGB, luminária misturadora de cores com ESP32, medição de luz com LDR e servo motor, com esquemas de circuito e código passo a passo, e pode combiná-los com o sensor de cor para montar a sua própria máquina.
Perguntas frequentes
A que distância o sensor de cor TCS3200 detecta a cor?
Os resultados mais estáveis vêm a cerca de 1–3 cm, porque a luz dos LEDs do módulo enfraquece rápido com a distância. Mais importante que a distância em si é mantê-la igual em todas as leituras, e você também deve calibrar nessa distância. Este sensor não serve para ler a cor de superfícies grandes ao longe.
Qual é a diferença entre o TCS230 e o TCS3200?
O TCS230 é o sensor de cor mais antigo do mesmo fabricante, e o TCS3200 é a versão melhorada. Os dois usam uma matriz de fotodiodos de 8×8, saída em frequência e a mesma lógica de controle S0–S3, então as ligações e o código são os mesmos. A maioria dos módulos vendidos hoje traz o TCS3200.
Por que o pulseIn retorna 0 com o TCS3200?
O pulseIn retorna 0 quando não vê um pulso dentro do tempo limite dado. As causas mais comuns são o pino OE não estar ligado ao GND, S0 e S1 deixados ambos em LOW (o que põe o sensor no modo desligado) e o OUT ligado a um pino diferente do que está no código. Se a frente do sensor estiver totalmente escura, a frequência cai para alguns hertz e nenhum pulso é captado em um tempo limite curto.
O TCS3200 funciona com o ESP32 e o Raspberry Pi Pico?
Sim. Como o TCS3200 funciona com 2,7–5,5 V, você pode alimentar o módulo pelo pino 3V3 da placa, e assim o pino OUT também gera pulsos de 3,3 V. Se alimentar o módulo com 5 V, você precisa de um divisor de tensão ou de um conversor de nível na linha OUT. Ao medir com MicroPython no Pico, a escala de frequência de 2% dá resultados mais precisos.
Qual é melhor, o TCS3200 ou o TCS34725?
Para medir cor com precisão, o TCS34725 é melhor: ele tem filtro de bloqueio de IR, resolução de 16 bits por canal e ganho ajustável, e se liga com só dois fios I2C. O TCS3200 é uma escolha comum e perfeitamente adequada para aprender medição de frequência e calibração e para montar separadores de cor simples.
Quantas cores o TCS3200 consegue distinguir?
Com iluminação controlada e distância fixa, o TCS3200 separa com segurança 6–8 cores claramente diferentes, como vermelho, laranja, amarelo, verde, azul, roxo, preto e branco. Distinguir tons próximos, como verde-claro e verde-escuro, também é possível, mas exige uma calibração mais cuidadosa, muitas leituras de referência para cada tom e um limite apertado.
Projetos para montar depois desta leitura
Ver todos os projetos
Medição da intensidade da luz com LDR
Quer ver a luminosidade do seu quarto em números? O LDR, um pequeno componente sensível à luz, mede a luz ambiente, e o Arduino exibe o valor na tela do computador a cada meio segundo. Cubra o sensor

Leitura da intensidade da luz com módulo LDR e ESP32
Acompanhe em tempo real no Monitor Serial o valor bruto do ADC do módulo LDR e a porcentagem relativa de luz calculada a partir de referências de escuridão e claridade. Essa porcentagem não é uma medida em lux. O projeto ensina a lógica de calibração do módulo. É ideal fazê-lo antes do projeto 10, pois ajuda a determinar o valor do limiar.

Uso de LED RGB
Três cores se escondem em um único LED: o LED RGB acende primeiro em vermelho, depois em verde e, por fim, em azul. Cada cor fica acesa por meio segundo e apagada por meio segundo antes de o ciclo rec

Transição suave de cores com LED RGB
Um único LED RGB muda lentamente do vermelho para o verde, do verde para o azul e de volta para o vermelho, repetindo esse ciclo de arco-íris sem parar. Cada transição leva cerca de dois segundos e me

Luminária com mistura de cores e ESP32 (3 potenciômetros + LED RGB + OLED)
Uma luminária inteligente que permite misturar a cor que você quiser girando três potenciômetros com o ESP32! Ao girar os potenciômetros de vermelho, verde e azul, o LED RGB de cátodo comum muda de cor em tempo real. O display OLED SSD1306 mostra os valores de cada cor na faixa de 0–255, barras de preenchimento e o código HEX da cor para a web, como #FF8040.

Controle de LED RGB com ESP32
Gere inúmeras cores com um único LED RGB em vez de 3 LEDs separados. Como no Arduino, ajustamos os valores R/G/B com analogWrite() para criar uma transição de arco-íris. Você vê a teoria das cores na prática, como vermelho + verde = amarelo.

Uso de servo motor
O braço de um pequeno servo motor gira para três posições em sequência: o início, o meio e o fim do percurso, esperando dois segundos em cada parada. O Arduino informa ao motor em qual ângulo ficar, e

Detecção de superfícies pretas e brancas com TCRT5000
Com o pequeno sensor que funciona como o olho dos robôs seguidores de linha, você identifica se o piso é preto ou branco. O TCRT5000 emite luz invisível em direção ao piso e verifica quanto dela é ref
Mais artigos
App BlueGrays
Monte este circuito passo a passo pelo celular
Esquema do circuito, código e lista de componentes em uma só tela. Mais de 200 projetos com Arduino, ESP32 e Pico prontos para montar.
Escaneie com seu celular
Aponte a câmera para o código para abrir a loja de aplicativos do seu celular.
ou abrir a loja

