ESP32 - TCS3200D/TCS230 Color Sensor

This guide walks you through connecting a TCS3200D/TCS230 color sensor to ESP32 for accurate RGB color detection and measurement. Learn how to calibrate the sensor and program the ESP32 to read color values from objects.

What you'll learn:

ESP32 with TCS3200D TCS230 color recognition sensor module tutorial

Hardware Used In This Tutorial

1×ESP-WROOM-32 Dev Module
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×TCS3200D/TCS230 Color Recognition Sensor Module
1×Breadboard
1×Jumper Wires
1×Recommended: Screw Terminal Expansion Board for ESP32
1×Recommended: Breakout Expansion Board for ESP32
1×Recommended: Power Splitter for ESP32

Or you can buy the following kits:

1×DIYables ESP32 Starter Kit (ESP32 included)
1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links in this section are Amazon affiliate links, meaning we may earn a commission at no additional cost to you if you make a purchase through them. Additionally, some links direct you to products from our own brand, DIYables .

Introduction to TCS3200D/TCS230 Color Sensor

The TCS3200D/TCS230 employs a 64-photodiode matrix organized in an 8×8 configuration for color identification. This array comprises 16 photodiodes fitted with red optical filters, 16 with green filters, 16 with blue filters, and 16 without filters (clear). The sensor operates by selecting specific filter types and converting the detected light intensity into a frequency-modulated square wave output.

Most sensor modules feature integrated white LED illumination, which maintains measurement consistency by providing a controlled light source independent of ambient conditions.

Pinout

The TCS3200D/TCS230 sensor module provides these connection points:

  • VCC pin: Connect to 3.3V or 5V power supply.
  • GND pin: Connect to ground (0V).
  • S0, S1 pins: Output frequency scaling controls.
  • S2, S3 pins: Color filter selectors.
  • OUT pin: Square-wave frequency output signal.
  • OE pin: Output enable (active LOW). Typically pre-wired to GND on commercial modules. If exposed, connect to GND.
TCS3200 TCS230 color sensor module pinout diagram showing VCC GND S0 S1 S2 S3 OUT pins

How It Works

Sensor operation depends on two configurable parameters: active color filter and output signal strength. Two control pin pairs determine these settings:

S0/S1 pins configure output frequency scaling:

  • S0=LOW, S1=LOW: Sensor powered down
  • S0=LOW, S1=HIGH: Output at 2% of base frequency
  • S0=HIGH, S1=LOW: Output at 20% of base frequency
  • S0=HIGH, S1=HIGH: Output at 100% of base frequency

S2/S3 pins select the active color filter:

  • S2=LOW, S3=LOW: Red filter engaged
  • S2=LOW, S3=HIGH: Blue filter engaged
  • S2=HIGH, S3=LOW: No filter (clear/unfiltered)
  • S2=HIGH, S3=HIGH: Green filter engaged

The OUT pin produces frequency output between roughly 2 Hz and 500 kHz. Frequency magnitude correlates with light intensity—more light yields higher frequency. Using pulseIn() to measure pulse duration gives the inverse—lower pulse width indicates brighter illumination. After calibration, these measurements convert to standard 0-255 RGB values.

Optimizing Measurement Stability

  • Position sensor 1-3 cm from target surface with consistent orientation.
  • Enable built-in white LEDs for standardized illumination.
  • Block external light sources to reduce measurement variability.

Wiring Diagram

ESP32 to TCS3200 color sensor connection layout:

TCS3200 Color SensorESP32
VCC3.3V
GNDGND
S0GPIO 17
S1GPIO 16
S2GPIO 18
S3GPIO 5
OUTGPIO 19
ESP32 and TCS3200 color sensor wiring diagram showing connection between pins

This image is created using Fritzing. Click to enlarge image

If you're unfamiliar with how to supply power to the ESP32 and other components, you can find guidance in the following tutorial: The best way to Power ESP32 and sensors/displays.

ESP32 Code - Sensor Calibration via Pulse Width

Calibration compensates for environmental variables affecting raw sensor readings: LED brightness variations, object distance, surface reflectivity differences, and ambient lighting conditions. These factors introduce measurement errors that must be quantified. The calibration process records minimum and maximum pulse widths for each color channel, creating boundaries for accurate 0–255 RGB mapping in your specific environment.

/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-tcs3200d-tcs230-color-sensor */ // Define color sensor pins #define PIN_S0 17 // The ESP32 pin connected to the S0 of the color module #define PIN_S1 16 // The ESP32 pin connected to the S1 of the color module #define PIN_S2 18 // The ESP32 pin connected to the S2 of the color module #define PIN_S3 5 // The ESP32 pin connected to the S3 of the color module #define PIN_sensorOut 19 // The ESP32 pin connected to the OUT of the color module // Variables for Color Pulse Width Measurements int redPW = 0; int greenPW = 0; int bluePW = 0; // Variables to track min and max pulse widths for calibration int redMin = 10000, redMax = 0; int greenMin = 10000, greenMax = 0; int blueMin = 10000, blueMax = 0; void setup() { // Set S0 - S3 as outputs pinMode(PIN_S0, OUTPUT); pinMode(PIN_S1, OUTPUT); pinMode(PIN_S2, OUTPUT); pinMode(PIN_S3, OUTPUT); // Set Pulse Width scaling to 20% digitalWrite(PIN_S0, HIGH); digitalWrite(PIN_S1, LOW); // Set Sensor output as input pinMode(PIN_sensorOut, INPUT); // Setup Serial Monitor Serial.begin(9600); Serial.println("=== TCS3200 Calibration ==="); Serial.println("Point the sensor at different objects (white, black, colors)."); Serial.println("Min and Max values are tracked automatically."); Serial.println("When values look stable, note them down for the next code."); Serial.println("------------------------------------------"); } void loop() { // Read Red Pulse Width redPW = getRedPW(); // Delay to stabilize sensor delay(200); // Read Green Pulse Width greenPW = getGreenPW(); // Delay to stabilize sensor delay(200); // Read Blue Pulse Width bluePW = getBluePW(); // Delay to stabilize sensor delay(200); // Update min and max values if (redPW < redMin) redMin = redPW; if (redPW > redMax) redMax = redPW; if (greenPW < greenMin) greenMin = greenPW; if (greenPW > greenMax) greenMax = greenPW; if (bluePW < blueMin) blueMin = bluePW; if (bluePW > blueMax) blueMax = bluePW; // Print the pulse width values with min/max Serial.print("Red PW = "); Serial.print(redPW); Serial.print(" - Green PW = "); Serial.print(greenPW); Serial.print(" - Blue PW = "); Serial.println(bluePW); Serial.print(" Min -> R:"); Serial.print(redMin); Serial.print(" G:"); Serial.print(greenMin); Serial.print(" B:"); Serial.println(blueMin); Serial.print(" Max -> R:"); Serial.print(redMax); Serial.print(" G:"); Serial.print(greenMax); Serial.print(" B:"); Serial.println(blueMax); Serial.println("------------------------------------------"); delay(1000); } // Function to read Red Pulse Widths int getRedPW() { // Set sensor to read Red only digitalWrite(PIN_S2, LOW); digitalWrite(PIN_S3, LOW); // Read the Pulse Width int PW = pulseIn(PIN_sensorOut, LOW); // Return the value return PW; } // Function to read Green Pulse Widths int getGreenPW() { // Set sensor to read Green only digitalWrite(PIN_S2, HIGH); digitalWrite(PIN_S3, HIGH); // Read the Pulse Width int PW = pulseIn(PIN_sensorOut, LOW); // Return the value return PW; } // Function to read Blue Pulse Widths int getBluePW() { // Set sensor to read Blue only digitalWrite(PIN_S2, LOW); digitalWrite(PIN_S3, HIGH); // Read the Pulse Width int PW = pulseIn(PIN_sensorOut, LOW); // Return the value return PW; }

Quick Instructions

  • If this is the first time you use ESP32, see how to setup environment for ESP32 on Arduino IDE.
  • Copy the calibration code into Arduino IDE
  • Click the Upload button on Arduino IDE to upload code to ESP32
  • Open Serial Monitor (set baud rate to 9600)
  • Point sensor at different colored objects: white paper, black surface, and various colors
  • Monitor the Min/Max values as they auto-update
  • After values stabilize (10-20 seconds), note down all six calibration numbers
COM6
Send
=== TCS3200 Calibration === Point the sensor at different objects (white, black, colors). Min and Max values are tracked automatically. When values look stable, note them down for the next code. ------------------------------------------ Red PW = 42 - Green PW = 55 - Blue PW = 60 Min -> R:42 G:55 B:60 Max -> R:42 G:55 B:60 ------------------------------------------ Red PW = 210 - Green PW = 185 - Blue PW = 172 Min -> R:42 G:55 B:60 Max -> R:210 G:185 B:172 ------------------------------------------ Red PW = 44 - Green PW = 57 - Blue PW = 61 Min -> R:42 G:55 B:60 Max -> R:210 G:185 B:172 ------------------------------------------
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Example calibration results from the output:

  • RedMin = 42, redMax = 210
  • GreenMin = 55, greenMax = 185
  • BlueMin = 60, blueMax = 172

ESP32 Code - Reading RGB Color Values

/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-tcs3200d-tcs230-color-sensor */ // Define color sensor pins #define PIN_S0 17 // The ESP32 pin connected to the S0 of the color module #define PIN_S1 16 // The ESP32 pin connected to the S1 of the color module #define PIN_S2 18 // The ESP32 pin connected to the S2 of the color module #define PIN_S3 5 // The ESP32 pin connected to the S3 of the color module #define PIN_sensorOut 19 // The ESP32 pin connected to the OUT of the color module // Calibration Values // Replace these values with your actual calibration data from the previous step int redMin = 0; // Red minimum pulse width int redMax = 0; // Red maximum pulse width int greenMin = 0; // Green minimum pulse width int greenMax = 0; // Green maximum pulse width int blueMin = 0; // Blue minimum pulse width int blueMax = 0; // Blue maximum pulse width // Variables for Color Pulse Width Measurements int redPW = 0; int greenPW = 0; int bluePW = 0; // Variables for final Color values int redValue; int greenValue; int blueValue; void setup() { // Set S0 - S3 as outputs pinMode(PIN_S0, OUTPUT); pinMode(PIN_S1, OUTPUT); pinMode(PIN_S2, OUTPUT); pinMode(PIN_S3, OUTPUT); // Set Pulse Width scaling to 20% digitalWrite(PIN_S0, HIGH); digitalWrite(PIN_S1, LOW); // Set Sensor output as input pinMode(PIN_sensorOut, INPUT); // Setup Serial Monitor Serial.begin(9600); } void loop() { // Read Red value redPW = getRedPW(); // Map to value from 0-255 redValue = map(redPW, redMin, redMax, 255, 0); // Delay to stabilize sensor delay(200); // Read Green value greenPW = getGreenPW(); // Map to value from 0-255 greenValue = map(greenPW, greenMin, greenMax, 255, 0); // Delay to stabilize sensor delay(200); // Read Blue value bluePW = getBluePW(); // Map to value from 0-255 blueValue = map(bluePW, blueMin, blueMax, 255, 0); // Delay to stabilize sensor delay(200); // Print output to Serial Monitor Serial.print("Red = "); Serial.print(redValue); Serial.print(" - Green = "); Serial.print(greenValue); Serial.print(" - Blue = "); Serial.println(blueValue); } // Function to read Red Pulse Widths int getRedPW() { // Set sensor to read Red only digitalWrite(PIN_S2, LOW); digitalWrite(PIN_S3, LOW); // Read the Pulse Width int PW = pulseIn(PIN_sensorOut, LOW); // Return the value return PW; } // Function to read Green Pulse Widths int getGreenPW() { // Set sensor to read Green only digitalWrite(PIN_S2, HIGH); digitalWrite(PIN_S3, HIGH); // Read the Pulse Width int PW = pulseIn(PIN_sensorOut, LOW); // Return the value return PW; } // Function to read Blue Pulse Widths int getBluePW() { // Set sensor to read Blue only digitalWrite(PIN_S2, LOW); digitalWrite(PIN_S3, HIGH); // Read the Pulse Width int PW = pulseIn(PIN_sensorOut, LOW); // Return the value return PW; }

Quick Instructions

  • Find the calibration constants at the top of the code:
int redMin = 0; // Red minimum pulse width int redMax = 0; // Red maximum pulse width int greenMin = 0; // Green minimum pulse width int greenMax = 0; // Green maximum pulse width int blueMin = 0; // Blue minimum pulse width int blueMax = 0; // Blue maximum pulse width
  • Replace all six zeros with your actual calibration values. For example (using redMin = 42, redMax = 210, greenMin = 55, greenMax = 185, blueMin = 60, blueMax = 172):
int redMin = 42; int redMax = 210; int greenMin = 55; int greenMax = 185; int blueMin = 60; int blueMax = 172;
  • Copy the above code and open with Arduino IDE
  • Click Upload button on Arduino IDE to upload code to ESP32
  • Place a colored object in front of the sensor
  • See the result on Serial Monitor
COM6
Send
Red = 210 - Green = 35 - Blue = 20 Red = 25 - Green = 200 - Blue = 40 Red = 30 - Green = 45 - Blue = 215
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Output now displays standard 0-255 RGB values. Shorter pulse widths (brighter illumination) yield higher RGB numbers; longer pulse widths (dimmer conditions) produce lower values.

Project Applications

With functional RGB reading capability, explore these project possibilities:

  • Automated color sorting: Categorize items by hue (red, green, blue identification)
  • Color comparison system: Verify color matching between objects
  • Chromatic line tracking: Build robots that follow colored paths
  • Manufacturing quality check: Identify defective units through color deviation
  • Color-triggered response: Activate buzzers or indicators upon detecting specific colors

Video Tutorial

Making video is a time-consuming work. If the video tutorial is necessary for your learning, please let us know by subscribing to our YouTube channel , If the demand for video is high, we will make the video tutorial.

Learn More

※ OUR MESSAGES