Documentation

ShillehTek GY-31 TCS3200 RGB Color Recognition Sensor for Arduino Projects | ShillehTek Product Manual
Documentation / ShillehTek GY-31 TCS3200 RGB Color Recognition Sensor for Arduino Projects | ShillehTek Product Manual

ShillehTek GY-31 TCS3200 RGB Color Recognition Sensor for Arduino Projects | ShillehTek Product Manual

manualshillehtek

Overview

The GY-31 TCS3200 is a programmable color light-to-frequency converter that lets your microcontroller "see" colors. The chip combines an 8x8 array of silicon photodiodes with a configurable current-to-frequency converter, outputting a square wave whose frequency is proportional to the intensity of red, green, blue, or unfiltered light reflected from the surface in front of it.

The GY-31 breakout adds 4 white LEDs to illuminate the target, mounting holes, and a clean 8-pin header. Pair it with an Arduino, ESP32, Raspberry Pi, or Pico to read RGB values, sort objects by color, build a line follower that distinguishes track colors, or trigger events when a specific hue is detected.

Because the output is a frequency rather than an analog voltage, the TCS3200 works on both 3.3V and 5V microcontrollers without level conversion — any digital input can read it.

At a Glance

Sensor IC
TCS3200 / TCS230
Operating Voltage
2.7V - 5.5V
Output
Square wave (frequency)
Pin Count
8 pins
Illumination
4 white LEDs (on-board)
Pins
VCC, GND, OUT, S0-S3, LED

Specifications

Parameter Value
Sensor IC TAOS TCS3200 (or compatible TCS230)
Operating Voltage 2.7V - 5.5V DC
Operating Current ~20 mA (with LEDs on)
Photodiode Array 8 x 8 (16 red, 16 green, 16 blue, 16 clear)
Color Filters R, G, B, and Clear (no filter)
Output Type Square wave, frequency proportional to light
Output Frequency Scaling Power down / 2% / 20% / 100% (S0/S1)
Color Selection Programmable via S2 / S3 pins
Communication Direct digital (any GPIO that can read frequency)
On-board LEDs 4 white, controllable via LED pin
Dimensions ~28 x 28 mm

Pinout Diagram

GY-31 TCS3200 RGB color sensor pinout diagram showing GND, OUT (frequency output), S2 and S3 (color filter select), VCC, S0 and S1 (output frequency scaling), and LED control pins

Wiring Guide

Arduino Wiring

The TCS3200 outputs a digital square wave, so any Arduino digital pin can read it. Powering at 5V gives the strongest LED illumination and matches Arduino's logic levels directly.

TCS3200 Pin Arduino Pin
VCC 5V
GND GND
S0 D4
S1 D5
S2 D6
S3 D7
OUT D8
LED 5V (or any GPIO to dim/blink)
Tip: Tying LED directly to VCC keeps the on-board white LEDs lit constantly. If you want to control them in code, connect LED to a GPIO and drive it HIGH/LOW.

ESP32 Wiring

The TCS3200's frequency output is digital and works perfectly with the ESP32's 3.3V GPIO. Power the module from the ESP32's 5V (VIN) pin so the on-board LEDs are bright enough.

TCS3200 Pin ESP32 Pin Details
VCC VIN (5V) For brighter LEDs
GND GND
S0 GPIO 18
S1 GPIO 19
S2 GPIO 21
S3 GPIO 22
OUT GPIO 23 3.3V output is safe
LED VIN or any GPIO
Info: The TCS3200's OUT pin is 3.3V tolerant when powered at 5V — its output amplitude follows VCC, but the ESP32 input pins handle the swing without damage in normal conditions. If you are paranoid, run VCC at 3.3V instead; the LEDs will be slightly dimmer.

Raspberry Pi Wiring

The Pi's GPIO is 3.3V. To stay on the safe side, power the TCS3200 from 3.3V so the OUT signal also swings at 3.3V. Reading the frequency requires careful timing on Linux — see the Python example below.

TCS3200 Pin Raspberry Pi Pin
VCC Pin 1 (3.3V)
GND Pin 6 (GND)
S0 Pin 11 (GPIO 17)
S1 Pin 13 (GPIO 27)
S2 Pin 15 (GPIO 22)
S3 Pin 16 (GPIO 23)
OUT Pin 18 (GPIO 24)
LED Pin 1 (3.3V)
Tip: Use the lowest output frequency scaling (S0=L, S1=H = 2%) so the Pi's Linux scheduler can keep up with timing the pulse. Higher scalings produce frequencies the Pi may struggle to count accurately.

Raspberry Pi Pico Wiring

The Pico runs on 3.3V GPIO. As with the Pi, power TCS3200 from 3.3V or use the Pico's VBUS (5V from USB) pin if you want brighter LEDs and a divider on OUT.

TCS3200 Pin Pico Pin
VCC 3V3 (OUT)
GND GND
S0 GP10
S1 GP11
S2 GP12
S3 GP13
OUT GP14
LED 3V3 (OUT)
Info: The Pico's time_pulse_us() function in MicroPython is a simple way to measure pulse width without writing your own counter routine.

Code Examples

Arduino - Read R, G, B Frequencies

tcs3200_arduino.ino
// GY-31 TCS3200 - Read raw red, green, blue frequencies on Arduino
// S0/S1 set frequency scaling. S2/S3 select which color filter is active.
// Lower frequency on a color = more of that color reflected.

const int S0  = 4;
const int S1  = 5;
const int S2  = 6;
const int S3  = 7;
const int OUT = 8;

void setup() {
  Serial.begin(9600);
  pinMode(S0, OUTPUT); pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT); pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);

  // Set frequency scaling to 20% (S0=H, S1=L)
  digitalWrite(S0, HIGH);
  digitalWrite(S1, LOW);
}

unsigned long readColor(int s2, int s3) {
  digitalWrite(S2, s2);
  digitalWrite(S3, s3);
  delay(50);
  return pulseIn(OUT, LOW);  // microseconds per low half-cycle
}

void loop() {
  unsigned long red   = readColor(LOW,  LOW);
  unsigned long blue  = readColor(LOW,  HIGH);
  unsigned long green = readColor(HIGH, HIGH);

  Serial.print("R="); Serial.print(red);
  Serial.print("  G="); Serial.print(green);
  Serial.print("  B="); Serial.println(blue);

  delay(300);
}

ESP32 - Print Color Name (Calibrated)

tcs3200_esp32.ino
// ESP32 + TCS3200: read R/G/B and guess a color name
// Calibrate MIN/MAX values by holding white and black under the sensor and
// noting the printed values, then update the constants below.

const int S0 = 18, S1 = 19, S2 = 21, S3 = 22, OUT = 23;

// Calibration -- replace with your own readings
const int R_MIN = 30, R_MAX = 250;
const int G_MIN = 35, G_MAX = 270;
const int B_MIN = 30, B_MAX = 240;

void setup() {
  Serial.begin(115200);
  pinMode(S0, OUTPUT); pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT); pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);
  digitalWrite(S0, HIGH); digitalWrite(S1, LOW);  // 20% scaling
}

int read(int s2, int s3) {
  digitalWrite(S2, s2); digitalWrite(S3, s3);
  delay(50);
  return pulseIn(OUT, LOW);
}

int normalize(int v, int lo, int hi) {
  int n = map(v, lo, hi, 255, 0);
  return constrain(n, 0, 255);
}

void loop() {
  int r = normalize(read(LOW,  LOW),  R_MIN, R_MAX);
  int g = normalize(read(HIGH, HIGH), G_MIN, G_MAX);
  int b = normalize(read(LOW,  HIGH), B_MIN, B_MAX);

  String name = "?";
  if (r > 180 && g < 100 && b < 100) name = "RED";
  else if (g > 150 && r < 120 && b < 120) name = "GREEN";
  else if (b > 150 && r < 120 && g < 150) name = "BLUE";
  else if (r > 200 && g > 200 && b > 200) name = "WHITE";
  else if (r < 60 && g < 60 && b < 60)    name = "BLACK";

  Serial.printf("R=%3d  G=%3d  B=%3d  -> %s\n", r, g, b, name.c_str());
  delay(400);
}

Raspberry Pi Pico - MicroPython

tcs3200_pico.py
# GY-31 TCS3200 on Raspberry Pi Pico (MicroPython)
# Wiring: S0=GP10 S1=GP11 S2=GP12 S3=GP13 OUT=GP14

from machine import Pin, time_pulse_us
import time

S0 = Pin(10, Pin.OUT); S1 = Pin(11, Pin.OUT)
S2 = Pin(12, Pin.OUT); S3 = Pin(13, Pin.OUT)
OUT = Pin(14, Pin.IN)

# 20% frequency scaling
S0.value(1); S1.value(0)

def read(s2, s3):
    S2.value(s2); S3.value(s3)
    time.sleep_ms(50)
    return time_pulse_us(OUT, 0, 30000)  # microseconds per low half-cycle

while True:
    r = read(0, 0)
    b = read(0, 1)
    g = read(1, 1)
    print("R={:4d}  G={:4d}  B={:4d}".format(r, g, b))
    time.sleep(0.3)

Frequently Asked Questions

What do the S0 and S1 pins do?
S0 and S1 set the output frequency scaling: 0/0 powers the chip down, 0/1 = 2%, 1/0 = 20%, 1/1 = 100%. Slower microcontrollers (Arduino Uno, Raspberry Pi) work best at 2% or 20%; faster ones (ESP32, Pico) can handle 100% for finer resolution.
What do S2 and S3 do?
They select which photodiode color filter is active: 0/0 = red, 0/1 = blue, 1/0 = clear (no filter), 1/1 = green. You sweep through them in code, reading OUT for each setting, to get the R/G/B values.
Why do my color readings drift under different lighting?
Ambient light hits the sensor in addition to the on-board LEDs. Calibrate by holding a white card and a black card under the sensor in the same lighting conditions you'll use, record the highest and lowest readings, and map your live values into 0-255 from there. Recalibrate any time the lighting changes significantly.
Why does my Raspberry Pi report wildly different RGB values than my Arduino does?
Linux on the Pi cannot time short pulses with the same precision as a bare-metal Arduino. Use the lowest scaling (2%) so the pulses are slower and easier to count. For best accuracy on a Pi, use the pigpio library which can time GPIO transitions in hardware.
Can I turn off the on-board LEDs?
Yes — wire the LED pin to a GPIO and drive it LOW to turn the LEDs off, HIGH to turn them on. Driving the LED pin from a GPIO instead of VCC also lets you flash them or PWM them for dimmer illumination.
Does the TCS3200 work behind glass or plastic?
Yes, but the cover material absorbs and reflects some of the LED light, so calibration becomes essential. Place the sensor as close to the glass as possible and keep ambient light out by using a small enclosure or hood around the sensor head.
What is the ideal target distance?
About 5-15 mm from the surface. Too close and the LEDs over-saturate the photodiodes; too far and ambient light dominates. A small spacer or 3D-printed shroud helps keep the distance consistent.

Related Tutorials