Tim Plays With the TCS34725 Colour Sensor.
by Palingenesis in Circuits > Arduino
44 Views, 1 Favorites, 0 Comments
Tim Plays With the TCS34725 Colour Sensor.
Ever wanted your project to see colours the way you do? šš In this Instructable, Iāll show you how I paired a TCS34725 colour sensor with a SK9822 RGB LED to build a tiny colourāreading module that calibrates itself every time it powers on ā just like old camcorders with their white lens caps š„āŖ.
The sensor reads the colour of whatever surface you point it at, the LED provides a stable light source, and a simple āwhiteācap calibrationā locks in accurate colour even in unpredictable lighting. The best part? I also built a Windows application that displays the live colour readings on your PC in real time, so you can see exactly what the sensor sees š»šØ.
With a bit of smart code and a splash of LED magic, youāll get stable, accurate colour readings you can use in anything from sorting robots to full 3D scanners š¤š.
Supplies
Supplies
The exact parts you need will depend on how you build your setup. I developed and tested this project using an Arduino Nano mounted on a breakout board with a 3Dāprinted holder and an I2C LCD, but this Instructable is written as if youāre assembling everything on a solderless breadboard (and Iāll include a Fritzing diagram).
TCS34725 Colour Sensor Module
Any breakout version will work ā Adafruit, eBay, AliExpress, etc. This is the main colourāsensing component.
- eBay, Adafruit or AliExpress.
SK9822 Intelligent RGB LED
I used a single SMD LED on a breakout board, but you can make life easier by using a short strip section. These LEDs give you a stable, controllable light source for calibration and colour capture.
- eBay, Adafruit or AliExpress.
5V Logic Microcontroller (Arduinoācompatible)
The project is written using the Arduino IDE and standard Arduino libraries. Any 5āvolt Arduinoācompatible board will work (Uno, Nano, Pro Mini 5V, etc.). I used an Arduino Nano.
- eBay, Adafruit or AliExpress.
I2C 1602 LCD (16Ć2)
This is optional but very helpful for debugging and seeing live RGB values. Look for the version with the I2C backpack.
- eBay, Adafruit or AliExpress.
Solderless Breadboard + Jumper Wires
Any standard breadboard kit will do. Youāll need enough wires to connect the sensor, LED, and LCD to your microcontroller.
- eBay, Adafruit or AliExpress.
USB Cable + 5V Power Source
For powering and programming the Arduino.
Software
The companion application for this project is available on the Microsoft Store ā no warnings from Windows about unknown publishers! You can download it here:
š§© Fritzing Setup
This is the full wiring layout for the project, built exactly as youād assemble it on a solderless breadboard. The diagram shows how the Arduino Nano, TCS34725 colour sensor, SK9822 LED, and I2C 1602 LCD all connect together šāØ.
The TCS34725 is placed off to the side with long wires so you can position it over different surfaces while keeping the rest of the circuit stable šØš. The SK9822 is wired as a single LED module, giving you a clean, controlled light source for colour calibration š”š.
Everything runs from 5 V logic, and the I2C LCD plugs straight into the Nanoās SDA/SCL pins, keeping the wiring tidy and beginnerāfriendly š§¼š. If you follow this layout, your hardware will match the code perfectly ā no surprises, no magic smoke šš„.
š§ Firmware Overview
This project runs on an Arduinoācompatible microcontroller and brings together three key elements: the TCS34725 colour sensor, a SK9822 RGB LED, and a Windows application that displays the detected colour in real time šØš». The firmware handles everything from reading raw sensor data to applying whiteābalance correction, mapping values into a calibrated range, and sending clean RGB output over serial.
The code is written in the Arduino IDE and uses wellāmaintained openāsource libraries ā credit where credit is due š. If youāre new to the Arduino ecosystem, full installation and setup instructions can be found at: Arduino Docs
Each part of the firmware has a specific job, so in the next steps weāll break the sketch down into clear sections:
- š¦ Definitions & Libraries ā what each include, constant, and setting is for
- āļø Setup() ā how the sensor, LED, LCD, and serial interface are initialised
- š Loop() ā how each reading is processed, calibrated, displayed, and transmitted
- š§© Helper Functions ā SK9822 control, colour mapping, white balance, serial output, etc.
By the end of this section, youāll understand exactly how the firmware works and how each part contributes to stable, accurate colour capture ā whether youāre experimenting on a breadboard or feeding colours into a 3D scanner šØļøš.
The ".ino" File needs to be placed in a folder of the same name without the extension.
Downloads
Libraries & Definitions š¦
This section sets up everything the firmware needs before the Arduino even reaches setup(). These are the building blocks that make the rest of the project work smoothly. Each library, constant, and definition has a specific purpose, and understanding them makes the later steps much easier to follow.
š Included Libraries
These three libraries give the project its core functionality:
- Wire.h ā enables I2C communication. Both the TCS34725 sensor and the I2C LCD rely on this bus.
- LiquidCrystal_I2C.h ā drives the 1602 LCD using only two wires (SDA/SCL). Credit: johnrickman
- Adafruit_TCS34725.h ā handles the colour sensor, including integration time, gain, and raw RGBC readings. Credit: Adafruit
These libraries save a huge amount of work ā instead of manually handling registers and timing, you get clean, readable functions that ājust workā š.
š¤ LCD Setup
- 0x27 is the most common I2C address for 1602 LCD backpacks.
- 16, 2 means 16 characters Ć 2 rows. This gives you a simple way to display live RGB values while testing.
š” LED Brightness (PWM)
This is the onāboard white LED on many TCS34725 modules. Youāre not using it for illumination (the SK9822 handles that), so brightness is set to 0.
āŖ White Balance Offset
This shifts all three colour channels equally. Itās your āwhiteācap calibrationā adjustment ā similar to how cameras correct for warm or cool lighting. A negative value pulls the colours slightly darker and more neutral.
šØ PerāChannel Colour Gains
These correct the sensorās natural bias. The TCS34725 doesnāt respond equally to all wavelengths, and your SK9822 LED mix isnāt perfectly neutral either. These gains let you fineātune each channel so white looks white and colours look balanced.
š§ TCS34725 Sensor Settings
- 50ms integration time ā fast enough for realātime scanning
- 4Ć gain ā boosts sensitivity without saturating the sensor
These settings give a good balance between speed and accuracy.
š SK9822 LED Definitions
- DI and CI are the SK9822ās data and clock pins
- LED_GLOBAL_BRIGHTNESS controls the internal SK9822 brightness (0ā31)
- LED_R/G/B_LEVEL define the calibrated white mix you created
This LED is your controlled light source, which is essential for stable colour readings.
šļø Raw and Processed Colour Variables
- r, g, b, c ā raw 16ābit sensor readings
- R8, G8, B8 ā processed 8ābit values for display and serial output
- hexColor ā webāstyle #RRGGBB string
- PNG32 ā 32ābit ARGB value for your Windows app
These give you multiple ways to use the colour data depending on your needs.
š Calibration Range
You only use Range_max (from the white reference). Range_min stays at zero because youāre not tracking black ā a deliberate design choice for scannerāstyle stability.
š” SK9822 LED Control
The SK9822 is your controlled light source, and it plays a huge role in getting stable, repeatable colour readings from the TCS34725. Instead of relying on ambient light (which changes constantly), the SK9822 gives you a consistent, calibrated illumination every time the sensor takes a reading. This is exactly how professional colour meters and 3D scanners maintain accuracy.
The firmware includes three small but important functions that handle everything the SK9822 needs: sending data frames, updating the LED colour, and initialising the LED hardware.
š How the SK9822 Works (Quick Overview)
The SK9822 uses a simple clock + data protocol:
- CI ā Clock input
- DI ā Data input
Each LED receives a 32ābit frame:
- 3 bits: 111 (start of frame)
- 5 bits: global brightness (0ā31)
- 8 bits: Blue
- 8 bits: Green
- 8 bits: Red
This is why the code sends the colour bytes in B, G, R order ā it matches the SK9822ās internal format.
šØ Sending a Frame
This function builds and sends the 32ābit LED frame:
- prefix sets the global brightness
- The next three bytes set Blue ā Green ā Red
This is the lowestālevel function ā everything else builds on top of it.
šļø Updating the LED Colour
This function handles the full SK9822 update sequence:
- Sends 4 zero bytes (start frame)
- Sends the LED frame
- Sends 4 bytes of 0xFF (end frame)
Even though youāre only using one LED, the SK9822 protocol always expects these start/end frames.
This is where your calibrated āwhiteā mix is applied:
These values give you a neutral white illumination, tuned specifically for your sensor and enclosure.
š¦ SK9822 Initialisation
This prepares the LED pins and ensures the LED starts off before you set the calibrated white level.
š Why This Matters for Colour Accuracy
The SK9822 is the heart of your colour stability:
- It removes ambientālight variability
- It ensures every reading uses the same spectrum
- It makes your whiteācap calibration meaningful
- It gives you consistent results across different rooms, times of day, and materials
Without this LED, the TCS34725 would give wildly different readings depending on the environment. With it, you get scannerāgrade consistency.
šØ Colour Processing Functions
This part of the firmware is where the raw sensor readings are transformed into clean, stable, displayāready RGB values. The TCS34725 gives you raw 16ābit RGBC data, but that data needs several processing steps before it becomes a usable colour. These functions handle normalisation, white balance, perāchannel correction, and conversion to 8ābit output.
Each function plays a specific role in making your colour readings consistent and scannerāready.
š Mapping Raw Values Into a Range
This converts a raw 16ābit reading into a 0.0ā1.0 floatingāpoint value.
- minVal is fixed at 0 in your design
- maxVal is captured from the white reference during startup
- The result is a brightnessānormalised value that behaves consistently across different lighting conditions
This is the foundation of your āwhiteācap calibrationā system.
āŖ White Balance Offset
This shifts all three channels equally. Itās your manual whiteābalance correction ā similar to how cameras compensate for warm or cool lighting.
A negative offset darkens the channels slightly and helps neutralise overly warm illumination.
šļø PerāChannel Gains
These gains correct the sensorās spectral bias and the LEDās colour mix.
- The TCS34725 responds differently to red, green, and blue
- Your SK9822 āwhiteā mix isnāt perfectly neutral
- These multipliers let you fineātune each channel so white looks white and colours look natural
This is essential for accurate colour reproduction.
šļø Clamping and 8āBit Conversion
After normalisation and correction, the values are still floatingāpoint numbers. This function:
- Clamps them to the valid range
- Converts them into 8ābit integers
- Produces values suitable for:
- LCD display
- Serial output
- Your Windows colour viewer
- PNG32 ARGB formatting
This is the final step before the colour is ready to use.
š Why These Functions Matter
Together, these functions:
- Stabilise brightness
- Correct colour temperature
- Balance the sensorās response
- Convert raw data into usable RGB
- Ensure consistent results across sessions
- Make the system suitable for 3D scanning and colour capture
They turn the TCS34725 from a noisy raw sensor into a proper colourāmeasurement device.
āļø Setup()
The setup() function is where the entire system comes to life. This is the oneātime initialisation stage that prepares the LCD, the TCS34725 sensor, the SK9822 LED, the serial interface, and your calibration reference. Once this runs, the firmware is ready to start taking stable, repeatable colour readings.
š Starting Serial & I2C
- Serial.begin(115200) opens the USB serial connection so your Windows app can receive colour data in real time.
- Wire.begin() starts the I2C bus, which both the LCD and TCS34725 rely on.
This is the communication backbone of the project.
š„ļø Initialising the LCD
The LCD is brought online and displays a simple start-up message. This gives you immediate visual confirmation that the firmware is running.
š” Disabling the OnāBoard LED
Many TCS34725 breakout boards include a bright white LED. Youāre not using it ā the SK9822 provides your controlled illumination ā so this sets it to 0 brightness.
- Instead of connecting the allocated pin on the microcontroller to LED Pin on the Sensor Module, I have just connected the LED Pin on the sensor module to GND.
š Checking the TCS34725 Sensor
If the sensor isnāt detected:
- A message appears on the LCD
- A message is printed to serial
- The firmware halts
This prevents the system from running with invalid data.
š Initialising the SK9822 LED
- The LED pins are configured
- The LED is set to your calibrated āwhiteā mix
- A short delay ensures the LED stabilises before taking the first reading
This is essential for your whiteācap calibration.
āŖ Capturing the White Reference
This is the heart of your calibration system:
- A single reading is taken from the white surface
- Range_max is set based on the clear channel
- This becomes the brightness ceiling for the entire session
This is exactly how professional colour meters and scanners initialise themselves.
š§© What Setup() Achieves
By the time setup() finishes:
- The LCD is ready
- The sensor is verified
- The SK9822 is producing calibrated white light
- The system has captured its white reference
- The serial link is open
- All variables are initialised
From this point on, the firmware can take stable, consistent colour readings ā ready for the main loop.
š Loop()
The loop() function is the beating heart of the firmware. Once the system has been initialised and calibrated in setup(), the loop runs continuously, taking fresh readings from the TCS34725, processing them, displaying them, and sending them to your Windows application. Every pass through the loop produces one complete colour sample.
šØ 1st ā Read Raw Sensor Values
The TCS34725 returns four 16ābit values:
- R ā red channel
- G ā green channel
- B ā blue channel
- C ā clear (overall brightness)
These are the untouched, unprocessed sensor readings. Everything else in the loop builds on this data.
š 2nd ā Normalise the Raw Values
This converts the raw values into 0.0ā1.0 floats, using:
- Range_min = 0
- Range_max captured from the white reference in setup()
This step stabilises brightness so your readings donāt drift with environmental changes.
āŖ 3rd ā Apply White Balance
This shifts all three channels equally using your WB_OFFSET. It corrects for warm/cool lighting and helps keep whites neutral.
šļø 4th ā Apply PerāChannel Gains
Each channel is multiplied by its gain value:
- Corrects the sensorās uneven spectral response
- Compensates for the SK9822ās LED colour mix
- Helps ensure that white looks white and colours look natural
This is your fineātuning stage.
šļø 5th ā Convert to 8āBit RGB
This clamps the values to 0ā1 and converts them into 0ā255 integers. These are the values used for:
- LCD display
- Serial output
- PNG32 formatting
- Your Windows colour viewer
This is the final usable colour.
š§± 6th ā Build PNG32 and Web Hex Formats
Two formats are generated:
- PNG32 (ARGB) ā used by your Windows app
- Web hex (#RRGGBB) ā humanāfriendly and easy to debug
This makes the colour data flexible and portable.
š„ļø 7th ā Update the LCD
The LCD shows:
- R
- G
- B
This gives you instant feedback while testing on the bench.
š» 8th ā Send Data to the Windows App
This prints:
- Calibration range
- Raw RGBC values
- PNG32
- Web hex
Your Windows application reads this stream and displays a live colour swatch.
ā±ļø 9th ā Loop Delay
A short delay keeps the update rate smooth and prevents overwhelming the serial port.
š What Loop() Achieves
Every cycle of the loop:
- Reads fresh sensor data
- Normalises it
- Applies white balance
- Applies channel gains
- Converts to 8ābit
- Displays it
- Sends it to the PC
This creates a stable, realātime colourācapture pipeline, perfect for experiments, robotics, or feeding colour into your 3D scanner.
š» Serial Output for the Windows App
The Send_To_Serial() function is a special part of your firmware because it acts as the communication bridge between the Arduino and the Windows colourāviewer application. Unlike the LCD output, which is just for human eyes, the serial output must follow a strict, predictable format so the PC software can parse each value correctly and display the right colour swatch.
This step explains why the format matters and how the notes in the code define the exact structure the Windows app expects.
š§¾ Why the Serial Format Must Be Exact
The Windows application isnāt āguessingā what the Arduino is sending. It reads the serial stream lineābyāline and looks for specific patterns:
- Range_min: and Range_max:
- RAW R: G: B: C:
- PNG32:
- WEB:
If any of these labels change ā even slightly ā the PC parser would no longer know:
- where each value begins
- where it ends
- which number belongs to which channel
- how to reconstruct the colour
Thatās why my comment block is so important: it documents the contract between the Arduino and the Windows app.
š The Function Itself
Each block is designed to be machineāreadable:
- The first line gives the calibration range
- The second line gives the raw sensor values
- The third line gives the 32ābit ARGB colour
- The fourth line gives the webāstyle hex colour
The Windows app reads these lines in order and updates the colour swatch instantly.
š§ Why This Matters for Your Project
Because my Windows application is going to be part of a larger 3Dāscanner ecosystem, the serial format becomes a protocol ā a fixed language both sides must speak. This ensures:
- consistent colour capture
- predictable parsing
- no mismatched values
- no corrupted colour data
- smooth realātime updates
It also means anyone using this Instructable can build the same PC tool or extend it, knowing exactly what the Arduino sends.
š In Summary
You can describe this step like this:
The Send_To_Serial() function outputs the colour data in a strict, structured format that a Windows application expects. Each line begins with a specific label (such as RAW R: or WEB:), allowing the PC software to parse the values correctly and display the colour swatch. Changing this format would break compatibility, so the output must remain exactly as shown.
šŖ Timās TCS34725 Colour Decoder (Windows Application)
This final step ties the whole project together. The firmware youāve built is designed to stream clean, structured colour data over USB, and Timās TCS34725 Colour Decoder is the Windows application that reads that stream and turns it into a live colour swatch on your PC. Itās the visual frontāend of your colourācapture system, and it makes testing, tuning, and experimenting far easier than relying on raw numbers alone.
šÆ What the Application Does
The Windows app listens to the Arduinoās serial output and extracts:
- Range_min / Range_max
- Raw RGBC values
- PNG32 ARGB value
- Web hex colour (#RRGGBB)
It then displays:
- A live colour swatch
- The numeric RGB values
- The hex code
- The ARGB value
This gives you instant visual confirmation of what the sensor is seeing, which is especially useful when calibrating the LED mix, adjusting gains, or testing different materials.
I have placed this Application on my Microsoft Store.
- (Currently awaiting Approval on the Store)
- This means no nagging messages of: "Unknown Publisher I want to stop you installing it" from Windows.
- My Microsoft Store
To use the application
- Plug the USB from the microcontroller into your PB.
- In the application choose the COM port that the USB is connected to.
- Click connect.