Componenti · 14 min di lettura

Sensore di colore TCS3200 con Arduino: collegamento e codice

Come funziona il sensore di colore TCS3200: pin S0–S3, lettura R, G, B con pulseIn, calibrazione su bianco e nero, riconoscimento colori, codice ESP32 e Pico.

Il sensore di colore TCS3200 è il modulo per il riconoscimento dei colori più usato nei progetti Arduino: misura il colore della superficie che ha davanti scomponendolo nelle componenti rossa, verde e blu. Converte la luce catturata da una matrice di fotodiodi direttamente in una frequenza: più luce rossa riflette una superficie, più alta è la frequenza sul canale rosso. Non servono letture analogiche né protocolli di comunicazione particolari; con la funzione pulseIn() di Arduino leggi i valori R, G e B in poche righe. Con questo sensore si costruiscono macchine che smistano caramelle colorate, robot che riconoscono i colori, veicoli che svoltano davanti a segni colorati sul pavimento e lampade che copiano il colore dell'oggetto che metti davanti.

In questa guida vedrai passo dopo passo cosa c'è dentro il sensore, a cosa servono i pin S0–S3, come collegarlo ad Arduino Uno, ESP32 e Raspberry Pi Pico, come fare letture grezze, come eseguire la calibrazione su bianco e nero e un algoritmo che capisce a quale colore corrisponde una lettura. Poi costruiremo la logica di una macchina che smista gli oggetti per colore e, per finire, lo confronteremo con il TCS34725, un sensore che lavora in I2C.

Modulo sensore di colore TCS3200
Modulo sensore di colore TCS3200: al centro il chip TCS3200 a 8 pin, ai quattro angoli LED bianchi che illuminano la superficie; da un lato i pin S0, S1, OE, GND, dall'altro VCC, OUT, S2, S3.

Che cos'è il sensore di colore TCS3200 e come funziona?

Il chip TCS3200, cuore del modulo (la sua versione precedente si chiama TCS230), ha sulla superficie 64 fotodiodi disposti in una griglia 8×8. Sedici hanno un filtro rosso, 16 uno verde, 16 uno blu e gli ultimi 16 sono senza filtro (clear) e vedono la quantità totale di luce. I 16 fotodiodi dello stesso colore sono collegati in parallelo, e i pin S2 e S3 scelgono quale gruppo misurare. Poiché i fotodiodi dei vari colori sono intercalati nella matrice, la luce che cade su un angolo della superficie influisce allo stesso modo su tutti i gruppi di colore.

La piccola corrente prodotta dal gruppo di fotodiodi scelto arriva a un convertitore corrente-frequenza interno al chip. Questo circuito genera un'onda quadra con duty cycle del 50%, la cui frequenza è direttamente proporzionale all'intensità della luce. Quello che misuri, quindi, non è una tensione ma il numero di impulsi al secondo: pochi hertz al buio completo, decine di kilohertz vicino a una superficie bianca. Il bello di un'uscita in frequenza è che resiste bene ai disturbi e si collega a qualsiasi pin digitale di Arduino. Se vuoi solo misurare quanta luce c'è, un sensore di luce LDR è più semplice; il TCS3200 fa lo stesso lavoro separatamente per tre colori.

CaratteristicaValore
ChipTCS3200 (versione precedente TCS230, compatibile nei pin)
Matrice di fotodiodi8×8 = 64: 16 rossi, 16 verdi, 16 blu, 16 senza filtro
UscitaOnda quadra con duty cycle del 50%, frequenza proporzionale alla luce
Frequenza di fondo scala (tipica)600 kHz (100%), 120 kHz (20%), 12 kHz (2%)
Tensione di alimentazione2,7–5,5 V
Assorbimento del chip1,4 mA tipici (a cui si somma la corrente dei LED del modulo)
Pin di controlloS0, S1 (scala di frequenza), S2, S3 (filtro colore), OE (abilitazione uscita, attivo LOW)
Distanza consigliataCirca 1–3 cm, sempre la stessa a ogni lettura
Illuminazione4 LED bianchi sul modulo

Pin S0–S3: scala di frequenza e scelta del filtro colore

Quattro pin di controllo stabiliscono il comportamento del TCS3200. S0 e S1 riducono la frequenza di uscita: al 100% gli impulsi si accorciano fino a pochi microsecondi e mettono alla prova la precisione di misura di Arduino Uno, mentre al 2% si allungano ma ne arrivano meno nello stesso tempo. S2 e S3 scelgono quale filtro colore leggere. Colleghi questi pin a uscite digitali di Arduino e li imposti dal codice prima di ogni lettura.

S0S1Scala della frequenza di uscitaQuando usarla?
LOWLOWSpento (power-down)Per mettere a riposo il sensore nei progetti a batteria
LOWHIGH2% (tipicamente fino a 12 kHz)Processori lenti, MicroPython e conteggio con interrupt
HIGHLOW20% (tipicamente fino a 120 kHz)L'impostazione migliore per Arduino e pulseIn
HIGHHIGH100% (tipicamente fino a 600 kHz)Misure veloci con un contatore hardware
S2S3Gruppo di fotodiodi letto
LOWLOWFiltro rosso
LOWHIGHFiltro blu
HIGHLOWSenza filtro (clear, luce totale)
HIGHHIGHFiltro verde
Il legame tra durata dell'impulso e frequenza è semplice: dato che il duty cycle è del 50%, la parte LOW dura mezzo periodo. Con la formula f = 1 / (2 × t) converti in frequenza i microsecondi restituiti da pulseIn. Per esempio, se t = 25 µs, f = 1 / (2 × 0,000025 s) = 20 kHz. Con la scala al 20% e i LED del modulo accesi, valori tra 10 e 200 µs sono normali.

Collegamento del TCS3200: Arduino Uno, ESP32 e Pico

Pin del moduloArduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT), pin 36
GNDGNDGNDGND
S0D4GPIO 32GP2
S1D5GPIO 33GP3
S2D6GPIO 25GP4
S3D7GPIO 26GP5
OUTD8GPIO 27GP6
OEGNDGNDGND
Non lasciare il pin OE scollegato. È attivo LOW; se resta HIGH o flottante, l'uscita va in alta impedenza e pulseIn restituisce sempre 0. Inoltre i pin di ESP32 e Pico lavorano a 3,3 V: se alimenti il modulo a 5 V, il pin OUT genera impulsi a 5 V e mette sotto stress l'ingresso della scheda. Su queste schede alimenta il modulo dal 3V3 oppure metti un partitore di tensione o un convertitore di livello logico sulla linea OUT.

I quattro LED bianchi del modulo illuminano la superficie sempre allo stesso modo, così i risultati restano più coerenti anche quando cambia la luce della stanza. Alcune schede hanno un pin LED separato per accendere e spegnere i LED, su altre i LED si accendono appena arriva l'alimentazione; controlla le serigrafie della tua scheda. Per ottenere i risultati migliori, avvolgi il sensore in un tubo o in un cartoncino nero, porta l'oggetto sempre alla stessa distanza ed evita le superfici lucide e riflettenti. Puoi verificare la piedinatura della tua scheda con lo strumento Pinout.

Passo dopo passo: leggere R, G e B con pulseIn

  1. Collega il modulo come nella tabella sopra; OE a GND e VCC a 5V.
  2. Scegli la scala di frequenza al 20% impostando S0 su HIGH e S1 su LOW.
  3. Per il rosso, metti S2 e S3 su LOW e attendi qualche millisecondo che l'uscita si stabilizzi.
  4. Misura in microsecondi la durata della parte LOW dell'impulso con pulseIn(OUT, LOW); fai la media di 10 letture per ridurre il rumore.
  5. Ripeti per il verde (S2 HIGH, S3 HIGH) e il blu (S2 LOW, S3 HIGH).
  6. Segui i risultati nel Monitor seriale a 9600 baud e metti davanti al sensore fogli di colori diversi.
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}

Il punto più importante di questo codice è che il numero letto è inversamente proporzionale alla luce: più il valore è piccolo, più luce arriva da quel colore. Con un foglio rosso davanti vedrai per esempio "R: 24 G: 68 B: 52"; il numero più piccolo è sul canale rosso. Il timeout di 50.000 µs passato a pulseIn evita che il codice aspetti il secondo intero previsto di default quando non arriva nessun impulso; se non viene catturato alcun impulso, la funzione restituisce 50.000, che significa "molto buio". Se hai difficoltà a leggere l'uscita seriale, dai un'occhiata alla guida al Monitor seriale di Arduino.

Calibrazione su bianco e nero: trasformare i valori grezzi in 0–255

I valori grezzi da soli ingannano, perché i tre gruppi di fotodiodi non hanno la stessa sensibilità e i LED bianchi del modulo non emettono tutti i colori in egual misura. Per questo anche un foglio bianchissimo dà numeri diversi sui tre canali. La calibrazione elimina queste differenze e porta ogni canale tra 0 (nero) e 255 (bianco); è la stessa idea del bilanciamento del bianco di una fotocamera. Calibra dove il sensore lavorerà davvero, con la stessa luce e alla stessa distanza; una calibrazione fatta sulla scrivania non vale dentro il contenitore della macchina.

  1. Fissa il sensore su un supporto e regola la distanza di misura (per esempio 1,5 cm) in modo che non cambi.
  2. Metti davanti un foglio bianco liscio, leggi più volte i valori R, G e B con il codice sopra e annota le medie come riferimento del bianco; sono i valori più piccoli.
  3. Metti nello stesso punto un foglio nero opaco o del feltro e annota le letture come riferimento del nero; sono i valori più grandi.
  4. Scrivi questi sei numeri nelle costanti WHITE_ e BLACK_ all'inizio del codice seguente e caricalo.
  5. Controlla che i tre canali siano vicini a 255 sul foglio bianco e vicini a 0 sul nero; altrimenti ripeti la misura con la stessa luce e la stessa distanza.

Attenzione a un errore presente in molti esempi: convertire direttamente la durata dell'impulso in 0–255 con map() non dà il risultato giusto, perché la luce è proporzionale alla frequenza e non alla durata dell'impulso. Il modo corretto è convertire prima la durata in frequenza (1/t) e poi scalare: livello = (f − f_nero) / (f_bianco − f_nero) × 255. Vediamo un esempio: hai misurato 20 µs sul bianco, 200 µs sul nero e l'oggetto dà 40 µs. map() lo trasforma in 226, mentre il metodo della frequenza dà 113. La frequenza dell'oggetto è esattamente metà di quella del bianco e, sottratto il livello del nero, corrisponde a circa il 44 % della scala, cioè a 113; map(), invece, mostra i colori molto più chiari di quanto siano e rende difficile distinguere le tonalità scure.

Algoritmo di riconoscimento: di che colore è questa lettura?

I valori R, G, B calibrati dipendono ancora dalla quantità di luce: se lo stesso oggetto rosso si avvicina un po' al sensore, i tre valori salgono insieme. Per risolvere, dividiamo ogni valore per la somma: r = R / (R + G + B), e lo stesso per g e b. Queste proporzioni di colore restano quasi costanti anche se distanza e luminosità cambiano un po'. Poi le confronti con proporzioni di riferimento misurate e salvate una volta per ogni colore, e scegli il vicino più prossimo. Per il confronto basta sommare i quadrati delle differenze; più questo numero è piccolo, più i colori si somigliano. Se anche il riferimento più vicino supera una certa soglia, il risultato è "sconosciuto". Se la luce totale è molto bassa l'oggetto è considerato nero, se tutti e tre i canali sono molto alti è bianco; questi due casi non si distinguono con le proporzioni, quindi vengono controllati per primi.

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 codiceFunzione
WHITE_* e BLACK_*Le durate degli impulsi su bianco e nero misurate durante la calibrazione (µs)
toLevel()Converte la durata dell'impulso in frequenza e la scala tra 0 e 255
refs[]Proporzioni r, g, b di riferimento di ogni colore; sostituiscile con le tue misure
classify()Prima separa nero e bianco, poi cerca il riferimento più vicino
MAX_DISTLe letture oltre questa distanza vengono considerate "Sconosciuto"
Non tirare a indovinare i valori di riferimento, misurali: metti un oggetto di ogni colore davanti al sensore 5–10 volte, fai la media delle proporzioni r, g, b mostrate nel Monitor seriale e scrivile nell'array refs[]. Misura con la luce e alla distanza in cui lavorerà la macchina. Se le letture oscillano, aiuta fare la media di più letture o applicare un filtro mediano; trovi i dettagli nell'articolo sul filtraggio dei dati dei sensori.

Costruire una macchina che smista gli oggetti per colore

Il progetto più amato con il TCS3200 è una macchina che smista caramelle colorate, perline o pezzi LEGO in base al colore. Il meccanismo usa due servo. Il servo di alimentazione, in alto, fa ruotare un disco con un foro in cui entra un solo oggetto: prima prende un oggetto sotto il tubo della tramoggia, poi lo porta davanti al sensore e, dopo la lettura, lo lascia cadere nello scivolo sottostante. Il servo dello scivolo, in basso, ruota uno scivolo inclinato e manda l'oggetto nel contenitore del suo colore. Se usi i servo per la prima volta, leggi prima Che cos'è un servomotore?.

  1. Sistema la tramoggia e un tubo leggermente più largo degli oggetti, in modo che cadano uno alla volta sul disco di alimentazione.
  2. Fissa il sensore in modo che veda l'oggetto sul disco da 1–2 cm e chiudilo perché non entri luce esterna.
  3. Stabilisci tre angoli per il servo di alimentazione: carico, sensore e scarico. Trovali per tentativi sul tuo meccanismo; collega il servo di alimentazione a D9 e quello dello scivolo a D10.
  4. Assegna un angolo del servo dello scivolo a ogni contenitore di colore (per esempio rosso 30°, verde 75°, blu 120°, tutto il resto 165°).
  5. Calibra dentro la macchina, con la sua illuminazione, e prova con più oggetti di ogni colore.
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}
Alimentare i servo dal pin 5V di Arduino può far crollare la tensione durante il movimento e riavviare la scheda; questo calo falsa anche le letture di colore. Alimenta i due servo con una sorgente a 5 V separata e collega il suo GND al GND di Arduino. Non misurare mentre un servo si muove; come nel codice, aggiungi una breve pausa dopo che il servo ha raggiunto la posizione.

TCS3200 con ESP32: misurare la frequenza con un interrupt

Lo stesso codice con pulseIn funziona anche su ESP32, ma esiste un metodo più stabile: invece di misurare gli impulsi uno per uno, contare quanti ne arrivano in un tempo fisso. Un interrupt incrementa un contatore a ogni fronte di salita; moltiplicando per 20 il conteggio dopo 50 ms ottieni la frequenza in hertz. Dato che questo metodo fa la media di centinaia di impulsi, un singolo impulso disturbato non lo influenza. Il processore a 240 MHz dell'ESP32 regge senza problemi decine di migliaia di interrupt al secondo con la scala al 20%; se con luce molto forte il conteggio diventa eccessivo, puoi scendere al 2%. Puoi usare lo stesso metodo anche su Arduino Uno spostando OUT sul pin D2, che supporta gli interrupt. Sull'ESP32 ricorda di alimentare il modulo dal 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 e MicroPython

Sul Pico l'equivalente del pulseIn di Arduino è la funzione machine.time_pulse_us(): restituisce in microsecondi la durata di un impulso al livello richiesto e un numero negativo in caso di timeout. Se viene chiamata quando il pin è già a quel livello, inizia subito a misurare e può misurare solo mezzo impulso; per questo il codice aspetta prima che finisca la parte HIGH e poi misura la durata LOW. Poiché in MicroPython ogni chiamata di funzione richiede qualche microsecondo, qui abbiamo scelto la scala al 2% (S0=0, S1=1): gli impulsi diventano 10 volte più lunghi e l'effetto di questo ritardo si riduce. I valori di calibrazione si scrivono in Hz; con la scala al 2% è normale vedere qualche kHz sul foglio bianco e qualche centinaio di Hz sul nero. Alimenta il modulo dal pin 3V3(OUT) del Pico; se è la prima volta che usi il Pico, Che cos'è il Raspberry Pi Pico? spiega come installare 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?

Il TCS34725 è un sensore di colore più recente che fa lo stesso lavoro in I2C. Esegue la misura all'interno del chip e fornisce i risultati come numeri a 16 bit per canale; Arduino non deve misurare impulsi. La differenza più importante è il filtro che blocca l'infrarosso (IR) posto sopra i fotodiodi. Il TCS3200 non ha questo filtro; poiché i fotodiodi al silicio sono sensibili anche all'infrarosso, le letture derivano con luce ricca di IR come quella del sole o delle lampadine a incandescenza. Dato che guadagno (1x, 4x, 16x, 60x) e tempo di integrazione (2,4–614 ms) del TCS34725 si impostano via software, funziona in un intervallo ampio, dalla luce molto fioca a quella intensa. Se ti interessa sapere come funziona l'I2C, leggi l'articolo Che cos'è l'I2C?.

Modulo sensore di colore I2C TCS34725
Modulo sensore di colore TCS34725: al centro il chip del sensore di colore con filtro IR, accanto un LED bianco; pin LED, INT, SDA, SCL, 3V3, GND e VIN.
CaratteristicaTCS3200TCS34725
UscitaFrequenza (onda quadra)I2C, indirizzo 0x29
Fili di segnaleS0–S3, OUT e OESDA e SCL (INT e LED opzionali)
RisoluzioneDipende dal metodo e dal tempo di misura16 bit per canale
Filtro IRNoSì (sul chip)
Impostazioni3 scale di frequenza e spegnimento4 guadagni, tempo di integrazione 2,4–614 ms
Alimentazione2,7–5,5 VChip a 3,3 V; moduli con regolatore 3–5 V
IlluminazioneDi solito 4 LED bianchiDi solito 1 LED bianco
Carico sul processoreOccupato mentre misura gli impulsiIl chip misura, Arduino si limita a leggere
Ideale perImparare, smistatori di colori sempliciColore preciso, temperatura di colore e misura in 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}

Prima di caricare il codice, installa la libreria Adafruit TCS34725 dal Gestore librerie; quando ti chiede delle dipendenze, scegli di installarle tutte. Su Arduino Uno collega SDA ad A4 e SCL ad A5; sull'ESP32 ai GPIO 21 e 22. getRawData() attende il tempo di integrazione e restituisce i valori grezzi di rosso, verde, blu e senza filtro (C); calculateColorTemperature_dn40() fornisce la temperatura di colore in kelvin e calculateLux() il livello di illuminazione approssimativo. La calibrazione e la logica del colore più vicino valgono allo stesso modo anche per questo sensore. Se vuoi un sensore che, oltre al colore, rilevi anche i gesti della mano e la prossimità, l'APDS-9960 è una buona alternativa.

Idee di progetto con il TCS3200

  • Macchina smistatrice di colori: Separa caramelle, perline o pezzi LEGO in contenitori diversi in base al colore.
  • Lampada che copia i colori: Riproduci il colore dell'oggetto che metti davanti al sensore con un LED RGB o una striscia WS2812B.
  • Robot che legge i colori: Insegna al tuo robot segui linea a fermarsi su un segno rosso sul pavimento e a ripartire su uno verde.
  • Braccio robotico che riconosce i colori: Usa un braccio robotico per prendere dei cubi e lasciare ogni colore nel proprio contenitore.
  • Rilevatore di colori parlante: Annuncia il colore rilevato con un messaggio preregistrato su un DFPlayer Mini; un aiuto pratico per le persone ipovedenti.
  • Controllo del colore dell'acqua: Segui nel tempo i cambiamenti di colore dell'acqua in un contenitore trasparente e lancia un avviso per un acquario o una cisterna di irrigazione.

Errori comuni e soluzioni

SintomoCausa probabileSoluzione
pulseIn restituisce sempre 0 o il valore di timeoutOE scollegato o HIGH, S0 e S1 entrambi LOW (spento) oppure OUT sul pin sbagliatoCollega OE a GND, metti S0 su HIGH e S1 su LOW, confronta il pin OUT con il codice
I valori saltano di continuoLuce ambiente, una lampada che sfarfalla o una distanza che cambiaScherma il sensore con un tubo nero, fissa la distanza, fai la media di più letture
Ogni oggetto risulta dello stesso coloreManca la calibrazione; i canali hanno sensibilità diverseEsegui la calibrazione su bianco e nero, misura di nuovo i riferimenti
I colori derivano con la luce del giornoIl TCS3200 non ha il filtro IRMisura dentro una scatola chiusa oppure usa un TCS34725
I livelli restano bloccati a 0 o 255L'oggetto è a una distanza diversa da quella della calibrazioneMantieni la stessa distanza della calibrazione, ricalibra se serve
ESP32 o Pico si comportano in modo stranoModulo alimentato a 5 V, OUT esce a 5 VAlimenta il modulo dal 3V3 o usa un convertitore di livello
Le letture sballano quando il servo si muoveLa corrente del servo abbassa la tensione di alimentazioneSorgente a 5 V separata per i servo, GND in comune
Le superfici lucide e riflettenti (metallo, plastica laccata, carta patinata) rimandano la luce dei LED direttamente nel sensore e fanno sembrare i colori più pallidi di quanto siano. Inclinare leggermente il sensore invece di tenerlo perfettamente perpendicolare, oppure lavorare con oggetti opachi, riduce molto il problema. Se devi solo distinguere il nero dal bianco, il TCRT5000 è una scelta più semplice e veloce.

Il TCS3200 è un sensore ottimo per capire come la luce diventa frequenza, perché la calibrazione è indispensabile e come si costruisce un semplice algoritmo di classificazione. Passare al TCS34725 quando ti serve più precisione è facile, perché la calibrazione e la logica del colore più vicino che hai imparato restano valide così come sono. Nell'app BlueGrays trovi progetti di miscelazione dei colori con LED RGB, una lampada miscelatrice di colori con ESP32, la misura della luce con LDR e progetti con servomotori, con schemi elettrici e codice passo dopo passo; combinali con il sensore di colore per costruire la tua macchina.

Domande frequenti

A che distanza il sensore TCS3200 riconosce i colori?

I risultati più stabili si ottengono a circa 1–3 cm, perché la luce dei LED del modulo si indebolisce rapidamente con la distanza. Più della distanza in sé conta mantenerla uguale a ogni lettura, e anche la calibrazione va fatta a quella distanza. Questo sensore non è adatto a leggere il colore di superfici grandi e lontane.

Che differenza c'è tra TCS230 e TCS3200?

Il TCS230 è il sensore di colore più vecchio dello stesso produttore e il TCS3200 è la sua versione migliorata. Entrambi usano una matrice di fotodiodi 8×8, un'uscita in frequenza e la stessa logica di controllo S0–S3, quindi collegamento e codice sono identici. La maggior parte dei moduli in vendita oggi monta un TCS3200.

Perché pulseIn restituisce 0 con il TCS3200?

pulseIn restituisce 0 quando non vede alcun impulso entro il timeout indicato. Le cause più comuni sono il pin OE non collegato a GND, S0 e S1 entrambi su LOW (il sensore entra in modalità di spegnimento) e OUT collegato a un pin diverso da quello del codice. Se davanti al sensore è completamente buio, la frequenza scende a pochi hertz e con un timeout breve non si cattura nessun impulso.

Il TCS3200 funziona con ESP32 e Raspberry Pi Pico?

Sì. Dato che il TCS3200 lavora tra 2,7 e 5,5 V, puoi alimentare il modulo dal pin 3V3 della scheda; così anche il pin OUT genera impulsi a 3,3 V. Se lo alimenti a 5 V, serve un partitore di tensione o un convertitore di livello sulla linea OUT. Misurando con MicroPython sul Pico, la scala di frequenza al 2% dà risultati più precisi.

Meglio il TCS3200 o il TCS34725?

Per una misura precisa del colore è meglio il TCS34725: ha un filtro che blocca l'IR, una risoluzione di 16 bit per canale e un guadagno regolabile, e si collega con soli due fili I2C. Il TCS3200 resta una scelta diffusa e più che sufficiente per imparare la misura di frequenza e la calibrazione e per costruire semplici smistatori di colori.

Quanti colori può distinguere il sensore TCS3200?

Con luce controllata e distanza fissa, il TCS3200 separa in modo affidabile 6–8 colori nettamente diversi, come rosso, arancione, giallo, verde, blu, viola, nero e bianco. Si possono distinguere anche tonalità vicine, come verde chiaro e verde scuro, ma servono una calibrazione più accurata, molte misure di riferimento per ogni tonalità e una soglia stretta.

Vedi tutti i progetti
Misurare l'intensità luminosa con LDR
#11Principiante

Misurare l'intensità luminosa con LDR

Vuoi vedere quanto è luminosa la tua stanza sotto forma di numero? L'LDR, un piccolo componente sensibile alla luce, misura la luce ambiente e l'Arduino scrive il valore sullo schermo del computer ogn

4.6(81)
139
Lettura dell'intensità luminosa con il modulo LDR ESP32
#113Principiante

Lettura dell'intensità luminosa con il modulo LDR ESP32

Monitoraggio in tempo reale sul Serial Monitor del valore grezzo dell'ADC del modulo LDR e della percentuale relativa di luce calcolata dai valori di riferimento al buio e alla luce. Questa percentuale non è una misurazione in lux. Spiega il principio di calibrazione del modulo. È consigliabile eseguirlo prima del Progetto 10, poiché serve a determinare il valore di soglia.

4.6(36)
55
Utilizzo dei LED RGB
#39Principiante
Premium

Utilizzo dei LED RGB

Dentro un solo LED si nascondono tre colori: il LED RGB si accende rosso, poi verde, poi blu, ogni colore acceso per mezzo secondo e spento per mezzo secondo, e poi il giro ricomincia. Ti bastano un L

4.9(73)
98
Transizione cromatica omogenea con LED RGB
#40Principiante
Premium

Transizione cromatica omogenea con LED RGB

Un solo LED RGB passa lentamente dal rosso al verde, dal verde al blu e torna al rosso, in un giro di arcobaleno che non si ferma mai. Ogni passaggio dura circa due secondi e mezzo, e il giallo, il tu

4.8(58)
76
Lampada con miscelatore di colori ESP32 (3 potenziometri + LED RGB + OLED)
#138Avanzato
Premium

Lampada con miscelatore di colori ESP32 (3 potenziometri + LED RGB + OLED)

Una lampada mista colori intelligente che, ruotando i 3 potenziometri con l'ESP32, permette di miscelare il colore desiderato! Man mano che si ruotano i potenziometri rosso, verde e blu, il LED RGB a catodo comune cambia colore istantaneamente. Sul display OLED SSD1306 vengono visualizzati in tempo reale i valori compresi tra 0 e 255 per ogni colore, le barre di riempimento visive e il codice colore HEX (#FF8040, ad esempio). Un mini studio di colore professionale: insegna la teoria dei colori R

4.7(6)
10
Controllo LED RGB ESP32
#111Principiante

Controllo LED RGB ESP32

Generazione illimitata di colori con un singolo LED RGB invece di 3 LED separati. La transizione arcobaleno avviene impostando i valori R/G/B con analogWrite() come in Arduino. La teoria dei colori (come rosso+verde=giallo) viene vista in pratica.

4.6(29)
51
Utilizzo del servomotore
#35Principiante
Premium

Utilizzo del servomotore

Il braccio di un piccolo servomotore ruota a turno in tre posizioni: tutto all'inizio, esattamente a metà e tutto alla fine, aspettando due secondi a ogni fermata. L'Arduino dice al motore a quale ang

4.7(48)
67
TCRT5000 Rilevamento di superfici bianche e nere
#78Intermedio
Premium

TCRT5000 Rilevamento di superfici bianche e nere

Con il piccolo sensore che fa da occhio ai robot seguilinea capisci se il pavimento è nero o bianco. Il TCRT5000 manda una luce invisibile verso il pavimento e controlla quanta ne torna indietro; sul

4.7(40)
49