TCS3200 Renk Sensörü: Arduino ile Renk Algılama ve Kalibrasyon
TCS3200 renk sensörü nasıl çalışır? S0–S3 ayarları, pulseIn ile R, G, B okuma, beyaz-siyah kalibrasyonu, renk ayırma algoritması, ESP32, Pico ve TCS34725 kodu.
TCS3200 renk sensörü, önündeki yüzeyin rengini kırmızı, yeşil ve mavi bileşenlerine ayırarak ölçen ve Arduino projelerinde en çok kullanılan renk algılama modülüdür. Bir fotodiyot dizisinin yakaladığı ışığı doğrudan frekansa çevirir: yüzey ne kadar çok kırmızı ışık yansıtırsa kırmızı kanalın frekansı o kadar yükselir. Analog okuma ya da özel bir haberleşme protokolü gerekmez; Arduino'nun pulseIn() komutuyla birkaç satırda R, G ve B değerlerini okuyabilirsin. Renkli şeker ayıran makineler, renk tanıyan robotlar, yerdeki renkli işaretlere göre yön değiştiren araçlar ve önüne tutulan nesnenin rengini kopyalayan lambalar bu sensörle yapılır.
Bu rehberde sensörün içinde neler olduğunu, S0–S3 pinlerinin ne işe yaradığını, Arduino Uno, ESP32 ve Raspberry Pi Pico bağlantısını, ham okumayı, beyaz-siyah kalibrasyonunu ve okunan değerden hangi renk olduğunu bulan bir algoritmayı adım adım göreceksin. Ardından renklerine göre nesne ayıran bir makinenin mantığını kuracak, son olarak da I2C ile çalışan TCS34725 sensörüyle karşılaştırma yapacağız.

TCS3200 renk sensörü nedir, nasıl çalışır?
Modülün kalbi olan TCS3200 yongasının (eski sürümünün adı TCS230) yüzeyinde 8×8 düzende 64 fotodiyot bulunur. Bunların 16'sının üzerinde kırmızı, 16'sının üzerinde yeşil, 16'sının üzerinde mavi filtre vardır; kalan 16'sı ise filtresizdir (clear) ve ışığın toplam miktarını görür. Aynı renkteki 16 fotodiyot birbirine paralel bağlıdır ve hangi grubun ölçüleceğini S2 ile S3 pinleri seçer. Farklı renkteki fotodiyotlar dizide iç içe dağıtıldığı için yüzeyin bir köşesine düşen ışık bütün renk gruplarını eşit etkiler.
Seçilen fotodiyot grubunun ürettiği küçük akım, yonganın içindeki akım-frekans dönüştürücüsüne gider. Bu devre, görev döngüsü %50 olan bir kare dalga üretir ve dalganın frekansı ışık şiddetiyle doğru orantılıdır. Yani ölçtüğün şey bir gerilim değil, saniyedeki darbe sayısıdır: tam karanlıkta birkaç hertz, beyaz bir yüzeye yakın tutulduğunda onlarca kilohertz görürsün. Frekans çıkışının güzel yanı, gürültüye dayanıklı olması ve Arduino'nun herhangi bir dijital pinine bağlanabilmesidir. Yalnızca ışığın ne kadar güçlü olduğunu ölçmek istiyorsan LDR ışık sensörü daha basit bir seçenektir; TCS3200 ise aynı işi üç renk için ayrı ayrı yapar.
| Özellik | Değer |
|---|---|
| Yonga | TCS3200 (eski sürümü TCS230, pin uyumlu) |
| Fotodiyot dizisi | 8×8 = 64 adet: 16 kırmızı, 16 yeşil, 16 mavi, 16 filtresiz |
| Çıkış | %50 görev döngülü kare dalga, frekans ışıkla doğru orantılı |
| Tam ölçek frekansı (tipik) | 600 kHz (%100), 120 kHz (%20), 12 kHz (%2) |
| Besleme gerilimi | 2,7–5,5 V |
| Yonganın akımı | Tipik 1,4 mA (modüldeki LED'lerin akımı buna eklenir) |
| Kontrol pinleri | S0, S1 (frekans ölçeği), S2, S3 (renk filtresi), OE (çıkış etkin, aktif LOW) |
| Önerilen ölçüm mesafesi | Yaklaşık 1–3 cm, her ölçümde aynı |
| Aydınlatma | Modülde 4 beyaz LED |
S0–S3 pinleri: frekans ölçeği ve renk filtresi seçimi
TCS3200'ün davranışını dört kontrol pini belirler. S0 ve S1 çıkış frekansını küçültür: %100 ölçekte darbeler birkaç mikrosaniyeye kadar kısalır ve Arduino Uno'nun ölçüm hassasiyetini zorlar; %2 ölçekte ise darbeler uzar ama aynı sürede daha az darbe gelir. S2 ve S3 ise hangi renk filtresinin okunacağını seçer. Bu pinleri Arduino'nun dijital çıkışlarına bağlar, her ölçümden önce koddan ayarlarsın.
| S0 | S1 | Çıkış frekansı ölçeği | Ne zaman kullanılır? |
|---|---|---|---|
| LOW | LOW | Güç kesik (power-down) | Pilli projede sensörü uyutmak için |
| LOW | HIGH | %2 (tipik en fazla 12 kHz) | Yavaş işlemciler, MicroPython ve kesmeyle sayım |
| HIGH | LOW | %20 (tipik en fazla 120 kHz) | Arduino ve pulseIn için en uygun ayar |
| HIGH | HIGH | %100 (tipik en fazla 600 kHz) | Donanım sayıcılı hızlı ölçümler |
| S2 | S3 | Okunan fotodiyot grubu |
|---|---|---|
| LOW | LOW | Kırmızı filtreli |
| LOW | HIGH | Mavi filtreli |
| HIGH | LOW | Filtresiz (clear, toplam ışık) |
| HIGH | HIGH | Yeşil filtreli |
TCS3200 bağlantısı: Arduino Uno, ESP32 ve Pico
| Modül pini | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 3V3 | 3V3(OUT), pin 36 |
| GND | GND | GND | GND |
| S0 | D4 | GPIO 32 | GP2 |
| S1 | D5 | GPIO 33 | GP3 |
| S2 | D6 | GPIO 25 | GP4 |
| S3 | D7 | GPIO 26 | GP5 |
| OUT | D8 | GPIO 27 | GP6 |
| OE | GND | GND | GND |
Modüldeki dört beyaz LED, yüzeyi her ölçümde aynı ışıkla aydınlatır; bu sayede oda ışığı değişse bile sonuçlar daha tutarlı olur. Bazı kartlarda LED'leri açıp kapatmaya yarayan ayrı bir LED pini vardır, bazılarında ise LED'ler besleme verildiği anda yanar; kendi kartının üzerindeki yazılara bak. En iyi sonucu almak için sensörün çevresini siyah bir boru ya da kartonla sar, ölçülecek nesneyi her seferinde aynı mesafeye getir ve parlak, yansıtıcı yüzeylerden kaçın. Kartının pin dizilimini Pinout aracında kontrol edebilirsin.
Adım adım: pulseIn ile R, G ve B okumak
- Modülü yukarıdaki tablodaki gibi bağla; OE'yi GND'ye, VCC'yi 5V'a bağla.
- S0'ı HIGH, S1'i LOW yaparak %20 frekans ölçeğini seç.
- Kırmızı için S2 ve S3'ü LOW yap ve çıkışın oturması için birkaç milisaniye bekle.
- pulseIn(OUT, LOW) ile darbenin LOW kısmının süresini mikrosaniye olarak ölç; gürültüyü azaltmak için 10 ölçümün ortalamasını al.
- Aynı işlemi yeşil (S2 HIGH, S3 HIGH) ve mavi (S2 LOW, S3 HIGH) için tekrarla.
- Sonuçları Seri Monitör'de 9600 baud ile izle ve sensörün önüne farklı renkte kağıtlar tut.
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}Bu kodda en önemli nokta, okunan sayının ışıkla ters orantılı olmasıdır: değer küçüldükçe o renkten gelen ışık artar. Kırmızı bir kağıt tuttuğunda örneğin "R: 24 G: 68 B: 52" gibi bir çıktı görürsün; en küçük sayı kırmızı kanaldadır. pulseIn'e verilen 50.000 µs'lik zaman aşımı, darbe gelmediğinde kodun varsayılan 1 saniye boyunca beklemesini önler; hiç darbe yakalanamazsa fonksiyon 50.000 döndürür ve bu "çok karanlık" anlamına gelir. Seri port çıktısını okumakta zorlanıyorsan Arduino Serial Monitor rehberine göz at.
Beyaz-siyah kalibrasyonu: ham değerleri 0–255'e çevirmek
Ham değerler tek başına yanıltıcıdır, çünkü üç fotodiyot grubunun hassasiyeti aynı değildir ve modüldeki beyaz LED'ler her rengi eşit miktarda yaymaz. Bu yüzden bembeyaz bir kağıt bile üç kanalda farklı sayılar verir. Kalibrasyon, bu farkları ortadan kaldırıp her kanalı 0 (siyah) ile 255 (beyaz) arasına yerleştirmektir; fotoğraf makinelerindeki beyaz dengesiyle aynı fikirdir. Kalibrasyonu sensörün gerçekten çalışacağı yerde, aynı ışık ve mesafede yapmalısın; masada yaptığın kalibrasyon kutunun içinde geçerli olmaz.
- Sensörü sabit bir tutucuya yerleştir ve ölçüm mesafesini (örneğin 1,5 cm) değişmeyecek şekilde ayarla.
- Önüne düz beyaz bir kağıt koy, yukarıdaki kodla R, G ve B değerlerini birkaç kez oku ve ortalamalarını beyaz referansı olarak not et; bunlar en küçük değerlerdir.
- Aynı yere mat siyah bir kağıt ya da keçe koy ve okunan değerleri siyah referansı olarak not et; bunlar en büyük değerlerdir.
- Bu altı sayıyı aşağıdaki kodun başındaki WHITE_ ve BLACK_ sabitlerine yaz ve kodu yükle.
- Beyaz kağıtta üç kanalın da 255'e, siyahta 0'a yakın çıktığını kontrol et; çıkmıyorsa ölçümü aynı ışık ve mesafede tekrarla.
Burada pek çok örnekte yapılan bir hataya dikkat: darbe süresini map() ile doğrudan 0–255'e çevirmek doğru sonuç vermez, çünkü ışık darbe süresiyle değil frekansla orantılıdır. Doğru yol, önce süreyi frekansa (1/t) çevirip sonra ölçeklemektir: seviye = (f − f_siyah) / (f_beyaz − f_siyah) × 255. Bir örnekle bakalım: beyazda 20 µs, siyahta 200 µs ölçtün ve nesne 40 µs verdi. map() bu değeri 226'ya çevirir; frekans yöntemi ise 113 bulur. Nesnenin frekansı beyazdakinin tam yarısıdır ve siyah seviyesi çıkarıldığında bu, ölçeğin yaklaşık %44'üne, yani 113'e karşılık gelir; map() ise renkleri olduklarından çok daha açık gösterir ve koyu tonları birbirinden ayırmayı zorlaştırır.
Renk ayırma algoritması: okunan değer hangi renk?
Kalibre edilmiş R, G, B değerleri hâlâ ışık miktarına bağlıdır: aynı kırmızı nesne sensöre biraz yaklaştığında üç değer birlikte artar. Bunu çözmek için her değeri toplama böleriz: r = R / (R + G + B), g ve b de aynı şekilde. Bu renk oranları, mesafe ve parlaklık biraz değişse bile hemen hemen sabit kalır. Ardından her renk için bir kez ölçüp kaydettiğin referans oranlarla karşılaştırır ve en yakın komşuyu seçersin. Karşılaştırma için oran farklarının karelerini toplamak yeterlidir; bu sayı ne kadar küçükse renkler o kadar benzerdir. En yakın referans bile belirli bir eşikten uzaksa sonuç "bilinmiyor" olur. Toplam ışık çok düşükse nesne siyah, üç kanal da çok yüksekse beyaz kabul edilir; bu iki durum oranlarla ayırt edilemediği için önce kontrol edilir.
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}| Kod bölümü | Görevi |
|---|---|
| WHITE_* ve BLACK_* | Kalibrasyonda ölçtüğün beyaz ve siyah darbe süreleri (µs) |
| toLevel() | Darbe süresini frekansa çevirip 0–255 arasına ölçekler |
| refs[] | Her rengin referans r, g, b oranları; kendi ölçümlerinle değiştir |
| classify() | Önce siyahı ve beyazı ayırır, sonra en yakın referansı bulur |
| MAX_DIST | Bu uzaklığı aşan ölçümler "Bilinmiyor" sayılır |
Renklerine göre nesne ayıran makine yapmak
TCS3200'ün en sevilen projesi; renkli şekerleri, boncukları ya da LEGO parçalarını renklerine göre ayıran makinedir. Mekanizma iki servodan oluşur. Üstteki besleme servosu, üzerinde tek bir nesnenin sığacağı delik bulunan bir diski döndürür: önce huni borusunun altından bir nesne alır, sonra onu sensörün önüne getirir ve ölçümden sonra alttaki kanala bırakır. Alttaki yönlendirme servosu ise eğik bir kanalı döndürerek nesneyi kendi rengine ait kutuya yollar. Servoları ilk kez kullanacaksan önce Servo Motor Nedir? yazısına göz at.
- Huniyi ve nesnelerden biraz geniş bir boruyu, nesneleri tek tek besleme diskine düşürecek şekilde yerleştir.
- Sensörü, diskin üzerindeki nesneyi 1–2 cm mesafeden görecek biçimde sabitle ve çevresini dış ışık girmeyecek şekilde kapat.
- Besleme servosu için üç açı belirle: yükleme, sensör ve bırakma. Açıları kendi mekanizmanda deneyerek bul; besleme servosunu D9'a, yönlendirme servosunu D10'a bağla.
- Yönlendirme servosu için her renk kutusuna bir açı ata (örneğin kırmızı 30°, yeşil 75°, mavi 120°, diğerleri 165°).
- Kalibrasyonu makinenin içinde, makinenin kendi ışığıyla yap ve her renkten birkaç nesneyle dene.
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}ESP32 ile TCS3200: kesmeyle frekans ölçmek
ESP32'de aynı pulseIn kodu çalışır, ama daha kararlı bir yöntem de var: darbe süresini tek tek ölçmek yerine belirli bir sürede kaç darbe geldiğini saymak. Bir kesme (interrupt) her yükselen kenarda sayacı bir artırır; 50 ms sonunda sayaçtaki değeri 20 ile çarpınca frekansı hertz olarak bulursun. Bu yöntem yüzlerce darbenin ortalamasını aldığı için tek bir bozuk darbeden etkilenmez. ESP32'nin 240 MHz'lik işlemcisi %20 ölçekte saniyede on binlerce kesmeyi rahatça karşılar; çok parlak ışıkta sayı aşırı büyürse ölçeği %2'ye düşürebilirsin. Aynı yöntemi Arduino Uno'da da OUT'u kesme destekleyen D2 pinine taşıyarak kullanabilirsin. ESP32'de modülü 3V3 pininden beslemeyi unutma.
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}Raspberry Pi Pico ve MicroPython ile TCS3200
Pico'da Arduino'daki pulseIn'in karşılığı machine.time_pulse_us() fonksiyonudur: istenen seviyedeki darbenin süresini mikrosaniye olarak verir, zaman aşımında ise negatif bir sayı döndürür. Pin zaten istenen seviyedeyken çağrılırsa ölçüme hemen başlar ve yarım bir darbe ölçebilir; bu yüzden kod önce HIGH kısmın bitmesini bekler, sonra LOW süresini ölçer. MicroPython'da her fonksiyon çağrısı birkaç mikrosaniye sürdüğü için burada %2 ölçeği (S0=0, S1=1) seçtik: darbeler 10 kat uzar ve bu gecikmenin etkisi küçülür. Kalibrasyon değerleri Hz olarak yazılır; %2 ölçekte beyaz kağıtta birkaç kHz, siyahta birkaç yüz Hz görmek normaldir. Modülü Pico'nun 3V3(OUT) pininden besle; Pico'yu ilk kez kullanıyorsan Raspberry Pi Pico Nedir? yazısı MicroPython kurulumunu anlatıyor.
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 mü, TCS34725 mi?
TCS34725, aynı işi I2C üzerinden yapan daha yeni bir renk sensörüdür. Ölçümü yonganın içinde yapar ve sonuçları kanal başına 16 bitlik sayılar olarak verir; Arduino'nun darbe ölçmesi gerekmez. En önemli farkı, fotodiyotlarının üzerinde kızılötesi (IR) engelleyici filtre bulunmasıdır. TCS3200'de bu filtre yoktur; silikon fotodiyotlar kızılötesine de duyarlı olduğu için güneş ışığı ya da akkor ampul gibi IR'si bol ortamlarda ölçümler kayar. TCS34725'in kazancı (1x, 4x, 16x, 60x) ve entegrasyon süresi (2,4–614 ms) yazılımla ayarlanabildiği için çok loş ışıktan parlak ışığa kadar geniş bir aralıkta çalışır. I2C'nin nasıl çalıştığını merak ediyorsan I2C nedir? yazısına bakabilirsin.

| Özellik | TCS3200 | TCS34725 |
|---|---|---|
| Çıkış | Frekans (kare dalga) | I2C, adres 0x29 |
| Sinyal kabloları | S0–S3, OUT ve OE | SDA ve SCL (isteğe bağlı INT ve LED) |
| Çözünürlük | Ölçüm yöntemine ve süresine bağlı | Kanal başına 16 bit |
| IR filtresi | Yok | Var (yonganın üzerinde) |
| Ayarlar | 3 frekans ölçeği ve güç kesme | 4 kazanç, 2,4–614 ms entegrasyon süresi |
| Besleme | 2,7–5,5 V | Yonga 3,3 V; regülatörlü modüller 3–5 V |
| Aydınlatma | Genellikle 4 beyaz LED | Genellikle 1 beyaz LED |
| İşlemci yükü | Darbe ölçerken meşgul | Yonga ölçer, Arduino yalnızca okur |
| Kime uygun? | Öğrenme, basit renk ayırıcılar | Hassas renk, renk sıcaklığı ve lüks ölçümü |
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}Kodu yüklemeden önce Kütüphane Yöneticisi'nden Adafruit TCS34725 kütüphanesini kur; bağımlılıkları sorduğunda hepsini kurmayı seç. Arduino Uno'da SDA'yı A4'e, SCL'yi A5'e, ESP32'de ise GPIO 21 ve 22'ye bağlarsın. getRawData() entegrasyon süresi kadar bekleyip ham kırmızı, yeşil, mavi ve filtresiz (C) değerlerini döndürür; calculateColorTemperature_dn40() renk sıcaklığını Kelvin olarak, calculateLux() ise yaklaşık aydınlık düzeyini verir. Kalibrasyon ve en yakın renk mantığı bu sensörde de aynen geçerlidir. Renkle birlikte el hareketlerini ve yakınlığı da algılayan bir sensör istiyorsan APDS-9960 iyi bir alternatiftir.
TCS3200 ile proje fikirleri
- Renk ayıran makine: Şeker, boncuk ya da LEGO parçalarını renklerine göre ayrı kutulara ayır.
- Renk kopyalayan lamba: Sensörün önüne tuttuğun nesnenin rengini bir RGB LED ya da WS2812B şerit ile yeniden oluştur.
- Renk okuyan robot: Çizgi izleyen robotuna yerdeki kırmızı işarette durmayı, yeşilde yola devam etmeyi öğret.
- Renk tanıyan robot kol: Bir robot kolla küpleri alıp her rengi kendi kutusuna bırak.
- Rengi sesli söyleyen cihaz: Okunan rengi bir DFPlayer Mini ile önceden kaydedilmiş sesle söyle; görme engelliler için kullanışlı bir yardımcı olur.
- Su rengi takibi: Saydam bir kaptaki suyun rengindeki değişimi zamanla izleyip akvaryum ya da sulama deposu için uyarı ver.
Sık yapılan hatalar ve çözümleri
| Belirti | Olası neden | Çözüm |
|---|---|---|
| pulseIn hep 0 ya da zaman aşımı değeri döndürüyor | OE boşta ya da HIGH, S0 ve S1 ikisi de LOW (güç kesik) ya da OUT yanlış pinde | OE'yi GND'ye bağla, S0'ı HIGH, S1'i LOW yap, OUT pinini kodla karşılaştır |
| Değerler sürekli zıplıyor | Oda ışığı, titreyen lamba ya da değişen mesafe | Sensörü siyah boruyla kapat, mesafeyi sabitle, birkaç ölçümün ortalamasını al |
| Her nesne aynı renk çıkıyor | Kalibrasyon yapılmamış; kanalların hassasiyeti farklı | Beyaz-siyah kalibrasyonu yap, referansları yeniden ölç |
| Gün ışığında renkler kayıyor | TCS3200'de IR filtresi yok | Ölçümü kapalı bir kutuda yap ya da TCS34725 kullan |
| Seviyeler hep 0 ya da 255'e yapışıyor | Nesne kalibrasyondakinden farklı mesafede | Mesafeyi kalibrasyondakiyle aynı tut, gerekirse yeniden kalibre et |
| ESP32 ya da Pico garip davranıyor | Modül 5 V ile beslenmiş, OUT 5 V veriyor | Modülü 3V3'ten besle ya da seviye dönüştürücü kullan |
| Servo dönünce ölçümler bozuluyor | Servo akımı besleme gerilimini düşürüyor | Servolara ayrı 5 V kaynak kullan, GND'leri birleştir |
TCS3200; ışığın frekansa nasıl dönüştüğünü, kalibrasyonun neden gerekli olduğunu ve basit bir sınıflandırma algoritmasının nasıl kurulduğunu öğrenmek için harika bir sensördür. Daha hassas ölçüm gerektiğinde TCS34725'e geçmek de kolaydır, çünkü öğrendiğin kalibrasyon ve en yakın renk mantığı aynen geçerlidir. BlueGrays uygulamasında RGB LED ile renk karıştırma, ESP32 renk mikser lambası, LDR ile ışık ölçme ve servo motor projelerini devre şemaları ve adım adım kodlarıyla bulabilir, renk sensörünü bu projelerle birleştirerek kendi makineni kurabilirsin.
Sıkça sorulan sorular
TCS3200 renk sensörü kaç cm mesafeden okur?
En kararlı sonuçlar yaklaşık 1–3 cm mesafede alınır, çünkü modüldeki LED'lerin ışığı uzaklaştıkça hızla zayıflar. Mesafeden daha önemlisi, onu her ölçümde aynı tutmaktır; kalibrasyonu da aynı mesafede yapmalısın. Uzaktaki büyük yüzeylerin rengini okumak için bu sensör uygun değildir.
TCS230 ile TCS3200 arasındaki fark nedir?
TCS230, aynı üreticinin daha eski renk sensörüdür; TCS3200 onun geliştirilmiş sürümüdür. İkisi de 8×8 fotodiyot dizisi, frekans çıkışı ve aynı S0–S3 kontrol mantığını kullanır, bu yüzden bağlantı ve kodlar ortaktır. Bugün satılan modüllerin büyük çoğunluğunda TCS3200 bulunur.
TCS3200 ile pulseIn neden 0 döndürüyor?
pulseIn, verilen zaman aşımı içinde darbe göremezse 0 döndürür. En sık nedenler OE pininin GND'ye bağlanmamış olması, S0 ve S1'in ikisinin de LOW kalması (sensör güç kesme moduna geçer) ve OUT'un koddakinden farklı bir pine bağlanmasıdır. Sensörün önü tamamen karanlıksa frekans birkaç hertz'e düşer ve kısa bir zaman aşımında darbe yakalanamaz.
TCS3200 ESP32 ve Raspberry Pi Pico ile çalışır mı?
Evet. TCS3200 2,7–5,5 V arasında çalıştığı için modülü kartın 3V3 pininden besleyebilirsin; böylece OUT pini de 3,3 V seviyesinde darbe verir. Modülü 5 V ile beslersen OUT hattına gerilim bölücü ya da seviye dönüştürücü koyman gerekir. Pico'da MicroPython ile ölçüm yaparken %2 frekans ölçeği daha doğru sonuç verir.
TCS3200 mü TCS34725 mi daha iyi?
Hassas renk ölçümü için TCS34725 daha iyidir: IR engelleyici filtresi, kanal başına 16 bitlik çözünürlüğü ve ayarlanabilir kazancı vardır, üstelik yalnızca iki I2C kablosuyla bağlanır. TCS3200 ise frekans ölçümünü ve kalibrasyonu öğrenmek ve basit renk ayırıcılar yapmak için yeterli ve yaygın bir seçimdir.
TCS3200 kaç farklı rengi ayırt edebilir?
Kontrollü ışıkta ve sabit mesafede TCS3200; kırmızı, turuncu, sarı, yeşil, mavi, mor, siyah ve beyaz gibi birbirinden belirgin biçimde farklı 6–8 rengi güvenilir şekilde ayırır. Açık ve koyu yeşil gibi yakın tonları ayırmak da mümkündür, ama daha dikkatli kalibrasyon, her ton için çok sayıda referans ölçümü ve sıkı bir eşik gerektirir.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
Ldr İle Işık Şiddeti Okuma
Odanın ne kadar aydınlık olduğunu sayıyla görmek ister misin? Işığa duyarlı küçük bir parça olan LDR ortam ışığını ölçer ve Arduino bu değeri yarım saniyede bir bilgisayar ekranına yazar. Elinle üstün

ESP32 LDR Modülü ile Işık Şiddeti Okuma
LDR modülünün ham ADC değerini ve karanlık/aydınlık referanslarına göre hesaplanan göreli ışık yüzdesini Serial Monitor'da gerçek zamanlı izleme. Bu yüzde lux ölçümü değildir. Modülün kalibrasyon mantığını öğretir. Proje 10'un öncesinde yapılması ideal; çünkü eşik değerini belirlemek için kullanılır.

RGB Led Kullanımı
Tek bir LED'in içinde üç renk saklı: RGB LED önce kırmızı, sonra yeşil, sonra mavi yanar; her renk yarım saniye yanıp yarım saniye söner ve sıra baştan başlar. Arduino'ya bir RGB LED ve üç direnç bağl

RGB Led İle Yumuşak Renk Geçişi
Tek bir RGB LED kırmızıdan yeşile, yeşilden maviye, maviden yeniden kırmızıya yavaşça geçer ve bu gökkuşağı döngüsü hiç durmaz. Her geçiş iki buçuk saniye kadar sürer; aradaki sarı, turkuaz ve mor ton

ESP32 Renk Mikser Lambası (3 Pot + RGB LED + OLED)
ESP32 ile 3 potansiyometre çevirerek istediğin rengi karıştıran akıllı bir renk mikser lambası! Kırmızı, yeşil ve mavi potansiyometreleri çevirdikçe ortak katot RGB LED anlık olarak renk değiştirir. SSD1306 OLED ekranda her renk için 0-255 aralığında değer, görsel dolgu barları ve HEX web renk kodu (#FF8040 gibi) canlı olarak gösterilir. Mini bir profesyonel renk stüdyosu — RGB renk teorisi, ADC analog okuma, PWM ile parlaklık kontrolü ve I2C ekran tasarımını tek projede öğretir. Grafik tasarımc

ESP32 RGB LED Kontrolü
3 ayrı LED yerine tek RGB LED ile sınırsız renk üretme. Arduino'daki gibi analogWrite() ile R/G/B değerlerini ayarlayarak gökkuşağı geçişi yaparız. Renk teorisi (red+green=yellow gibi) pratik olarak görülür.

Servo Motor Kullanım
Küçük bir servo motorun kolu sırayla üç konuma döner: en başa, tam ortaya ve en sona, her durakta iki saniye bekleyerek. Arduino motora hangi açıda durması gerektiğini söyler, motor da oraya gidip ora

TCRT5000 Siyah Beyaz Zemin Tespiti
Çizgi izleyen robotların gözü olan küçük bir sensörle zeminin siyah mı beyaz mı olduğunu anlarsın. TCRT5000 sensörü zemine gözle görülmeyen bir ışık gönderip ne kadarının geri döndüğüne bakar; beyaz z
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 200'den fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

