Download PDF Parts List View on YouTube Download Code

Today we will look at two different types of color sensors that you can use with an Arduino or other microcontrollers. One of these is an inexpensive device that has been available for years, the other sensor offers improved performance and an I2C interface.


Color sensing is often used in industrial and manufacturing applications for quality control, but there are several other uses for this technology.  Color sensors can be used to build sorting machines, for photographic and lighting applications and even to build a device to solve a Rubik’s Cube!

Your local hardware store likely uses a color sensor to match samples to blend paint.

Color Sensors

While there are some very expensive color sensors used in industrial applications there are also very inexpensive ones used for less stringent applications. We will use a couple of these sensors today with an Arduino.

One of the sensors we are using is a very popular one, the TCS230 (also TCS3200). This sensor is available at Amazon, eBay and probably at your local electronics shop. It is quite inexpensive and pretty easy to use.

The second sensor is a module from Sparkfun, based upon the Intersil ISL29125 sensor chip. This sensor communicates using the I2C bus, making hookup very easy.

We will see how to hookup and calibrate both sensors, and then how to use them to get RGB values. 

Color Sensing Principles

There are a variety of different color sensors, each having specific advantages and disadvantages. Most of them work on the same basic principles.

Before we add a sensor to our Arduino project it would be a good idea to take a look at how some of these sensors work.

How Color Sensors Work

Most color sensors are comprised of an array of light sensors, usually photodiodes or phototransistors. 

Color Sensor Arrays

The light sensors are filtered so that they only accept one of the primary colors red, green or blue. There is also an unfiltered sensor to gauge the relative light level in most sensors.

The sensors are addressed one color at a time, and the light intensity is measured. As there are an array of sensors the results are averaged, and then sent out for processing.  By measuring the relative level of red, green and blue, the color of the object detected by the sensor can be determined.

These devices are far from perfect, and as photodiodes and phototransistors do not respond to every wavelength of light equally the results are not linear between the three colors. These nonlinearities are compensated for in the processing device, which in our case would be an Arduino.

In most applications, it isn’t actually important that the results are nonlinear, or that the output is not true RGB values. Just knowing the readings for the color you are trying to detect is often enough.

Color Sensor Types

While most color sensors consist of an array of color-filtered light sensors their output methods can differ.

  • Analog Outputs – The sensors output analog voltages that correspond to light levels. This is the most basic form of color sensor and is not often used these days.
  • Digital Outputs – The sensor outputs a digital reading of each color intensity. The ISL29125 we will be working with employs this method.
  • Variable-Frequency Outputs – The output is a square wave which changes in frequency in response to the color intensity. The TCS230 sensor uses this method.

Color sensors are available as individual chips, but for our purposes, it is much easier to use modules.

Some color sensor modules employ lenses or light filters to improve their detection abilities and reduce interference from ambient light.

So now that we know a little more about how these devices operate it’s time to put them to work!

TCS230 Color Sensor

The first color sensor we will use is the TCS230, which is also branded as the TCS3200.  This is an inexpensive and widely available device that comes in several different configurations. The module you purchase may not look exactly like the one I used, but it will have the same connections and will function just as well in the experiments.

This sensor has been around for over a decade but is still useful, especially in non-critical applications.

Most modules based upon this sensor include four white LEDs, which are used to illuminate the object being sensed.

TCS230 Light Shield

Some TCS230 and TCS3200 modules have a light shield or lens for improved performance.

The TCS230 operates on a supply voltage of 2.7 to 5.5 volts and provides TTL logic-level outputs.

TCS230 Operation

The TCS230 sensor has four arrays of 16 photodiodes, one array for each of the primary colors plus an unfiltered array.  This gives the sensing element a total of 64 sensing points. Each array is selected independently.

The device outputs a square wave whose frequency changes in correspondence to the intensity of light. You can select the range of frequencies the device will produce by “scaling” the output at 2, 20 or 100 percent. This allows the sensor to be used with a variety of microcontrollers and other devices.

Four input pins on the TCS230 module are used to select the sensing array and the frequency scaling.

TCS230 frequency Scaling and Color Selection Chart

For the Arduino most applications use the 20% scaling.

TCS230 Pinout

The following diagram shows the pinout of a common TCS230 module, as viewed from the top:

TCS230 pinout

Your module may differ a bit from this one, but it should have the same pins.

  • The Output Enable pin is seldom used and on most modules is permanently enabled. 
  • Pins S0 and S1 are used to select the frequency scaling.
  • Pins S2 and S3 are used to select the color array.
  • The Output pin is a TTL level square wave.

The sensor itself can be seen at the center of the module, surrounded by the four LEDs. The LEDs are illuminated when power is applied to the module.

TCS230 Arduino Hookup

Hooking up the TCS 230 to an Arduino is very simple. Every pin with the exception of Output Enable is used, and the module can be safely powered from the Arduino’s 5-volt output.

Here is the hookup I used for the experiments with the TCS230:

TCS230 Arduino Hookup

None of the pins used on the Arduino are critical as the module does not require PWM or other pin-specific features, so If you want to use different pins you can safely do so. Just make sure to change the pin numbers in the code to reflect any changes you make to the wiring.

You may also use a different Arduino other than the Uno I used.

Once you have the sensor connected to the Arduino it’s time to write some code!

TCS230 Calibration Code

We will actually be using two sketches to work with the TCS230 color sensor.

  • A sketch to get the raw data from the sensor so that we can record it.
  • A sketch that uses the data we recorded to display RGB values for the color being sensed.

Both sketches will use the same hardware hookup.

Here is our calibration sketch:

The sketch addresses the TCS230 sensor color-by-color and reads the pulse width of the Output pin.  This is then displayed on the serial monitor. You may use these values with a white and black test sample to determine the minimum and maximum pulse width.

Remember, pulse width is the inverse of frequency, so a shorter pulse width corresponds to a higher frequency.

The sketch starts by defining the pins used to connect the TCS230. If you used different pins you will need to modify these definitions accordingly.

Next, some variables are defined to represent the pulse widths of the red, green and blue sensors.

In the setup, we define the S0-S3 pins as outputs. These pins will be used to select the frequency scaling and the color we wish to address.

The sensors Output pin is defined as an input to the Arduino, this is where we will receive the square wave.

Next, the S0 and S1 pins are used to set the frequency scaling to 20%, which is a common value when using an Arduino with this color sensor.

Finally, we set up the serial monitor. You can change the baud rate if you wish to match your serial monitor.

In the loop, we call three functions to get the pulse width. Let’s examine one of these functions first.

The getRedPW function gets the red pulse width. It starts by setting the S2 and S3 pins to select the red output. This is the only way in which this function differs from its green and blue counterparts.

Next, an integer is defined to represent the pulse width.

The pulse width is then determined using the Arduino pulseIn function. This function measures the pulse width, the way we have it configured it measures the width of the LOW part of the pulse.  The result is the time in milliseconds.

This value is then returned and the function ends.

Back in the loop we call the three functions to read the color pulse widths, adding a 200 ms delay between them to allow the sensor to stabilize.  We then print the values to the serial monitor and repeat the loop.

Calibrating the Sensor

Load the sketch to your Arduino and mount the sensor so it is facing the objects you wish to measure.

You will need to start out by finding a reference object for white and black. These should produce readings at both the maximum and minimum values for all three colors.

TCS230 Calibration

I used black and white sheets of craft paper, which aren’t really “reference” standards but they will do for testing purposes.  You will also get the best results in a dark room, or at least by shading the sensor from ambient light.

Record the readings you get at both extremes. You may need to allow the sensor to stabilize for a few seconds before you can read it.

Once you have your readings you can move on to the next sketch.

Getting RGB Values from the TCS230

You can use the readings from the first experiment “as-is” in many applications. If you are trying to detect a specific color and you have a sample of it that may be all you’ll need.

However it can be useful to get actual RGB values from the sensor.

  • You might want to drive an RGB LED or other display with the values you obtain.
  • You may want to record the values in an EEPROM or SD Card. This will be easier with RGB values as they are a series of 8-bit integers.
  • You might want to match the color to a known standard.

The next sketch is an attempt to get RGB values from the TCS230 color sensor.

Most of this sketch should look familiar as the majority of it is the same as the previous sketch.

The six calibration values you obtained from the first sketch are entered in the top of the sketch, replace the “0” with your actual values.

There are also three new variables defined for the RGB values we want to output.

The Setup for this sketch is identical to the previous one.

In the loop, we read each of the values using the same functions we used in the previous sketch. We then use an Arduino map function to change these to RGB values, using our calibration values as a reference. 

Note the format of the map function, we are reversing the range as our functions bring back pulse width, not frequency.

Finally, we output the values to the serial monitor.

Load the sketch and observe the results with different color samples. You’ll want to check your black and white references first, to see how close they are. You can make minor adjustments to the calibration values if required.

The readings should correspond to the RGB values of the item being scanned.

ISL29125 RGB Light Sensor

The ISL29125 is a newer color sensor with greater accuracy than the TCS230. It uses a 16-bit digital representation of each color instead of outputting a variable frequency.

The sensor I’m using is from Sparkfun, but other manufacturers make ISL29125 sensors as well.

ISL29125 Operation

The ISL29126 is a single-chip programmable color sensor with an I2C output.  This makes it easy to interface to common microcontrollers and microcomputers.

In addition to a color sensor output it also has an interrupt output that can be programmed to trigger when specific colors (or color ranges) are detected.  The programming is done by writing to the three internal registers in the sensor using the I2C bus.

ISL29125 Pinout

Here is the pinout of the Sparkfun ISL29125 color sensor module:

ISL29125 Color Sensor - Front View

This is a 3.3-volt device and it is NOT 5-volt tolerant!  Applying 5-volt power or logic signals to this device will destroy it.  To use it with a 5-volt logic microcontroller such as an Arduino Uno, you’ll need to use a logic level converter.

In addition to the power and ground pins there is also a connection for the I2C line, plus an interrupt output.

Note that the I2C line is pulled up using two resistors included on the module. If you want to remove these pullup resistors you’ll have to cut two traces on the hback of the sensor, as illustrated here.

ISL29125 Color Sensor - Rear View

Unlike the TCS230 the sensor does not have white LEDs integrated into it, so you’ll need to provide your own source of illumination.

ISL29125 Arduino Hookup

Here is the hookup I used to interface the ISL29125 with an Arduino Uno.

ISL29125 Arduino Hookup

As I’m using a 5-volt microcontroller I needed to use a 2-channel level converter. If you decide to use a 3.3-volt microcontroller, such as a 3.3-volt Arduino Pro Mini,. Then you won’t need the converter.

I didn’t use the interrupt output in my experiments, but the Spoarkfun library does come with an example for using it. If you wish to use it then connect it to an interrupt pin on the Arduino, such as pin 2. You won’t need a logic-level convertor for this line as it is an output, and 3.3-volts falls within the usable threshold for 5-volt logic.

I also hooked up four while LEDs to provide a source of illumination, but if you have another way of lighting up your target then you can eliminate them.  They are hooked up to the 5-volt output on the Arduino with 330 ohm dropping resistors.

Once you have everything hooked up and have double-checked your wiring it’;s time to get some code.

ISL29125 Library and Sample Code

Sparkfun has provided a library for using the ISL29125 module, and you’ll need to download and install it.

The library is in a ZIP archive, and it will be necessary to add it to your Arduino IDE. the easiest way of doing this is as follows:

  • Download the Sparkfun ISL29125 library ZIP file.  Make a note of the location you saved it in.
  • Open the Arduino IDE.
  • Click the Sketch menu item at the top of the screen.
  • Select Include Library. A sub-menu will open up.
  • Select Add ZIP Library. This will open up a file dialog box.
  • Use the dialog box to select the library ZIP file. Then click OK to install the library

Once the library is installed you can proceed.

The library comes with three sample sketches, which you can find as follows:

  • Open the Arduino IDE (which you probably have still open from the last step)
  • Click the File menu on the top menu bar.
  • Scroll down and highlight Examples. A sub-menu will open up.
  • Scroll down below the Examples from Custom Libraries section and look for the SFE_ISL29125_Library menu item.
  • There are three example sketches for the ISL29125 here.

The three examples are as follows:

  • ISL29125_basics – This example shows you how to get the color values from the sensor and display them on the serial monitor. We will be using a slightly modified version of this example to calibrate our sensor.
  • ISL29125_interrupts – This example shows you how to program and use the ISL29125 interrupt feature. You’ll need to make an additional connection from the Interrupt output to your Arduino.
  • ISL29125_RGB_LED – This is an interesting sketch that lights up an RGB LED, which you can then use to calibrate the sensor!  It cycles the RGB LED through its primary colors and displays the readings on the serial monitor.

Let’s open the ISL29125_basics sketch and take a look at it.

Modifying the Basic Sketch

The ISL29125_basics sketch reads the sensor and then displays its output on the serial monitor. It makes use of the custom Sparkfun library you just installed.  You may use this sketch to write your own code for the ISL29125.

The ISL29125 provides a 16-bit output for each color,and the sketch has been written to display this in hexadecimal.  It can easily be modified to display the output in decimal, which I have done in the example below:

This is a very simple sketch, thanks to the functionality of the Sparkfun library.

We start by including the Arduino Wire library to communicate with I2C. This library is built-in to your Arduino IDE.

Next we include the Sparkfun SFE_ISL29125 library that you just installed.

We define an object called RGB_sensor to represent our ISL29125 sensor.

In the Setup we initialize both the serial monitor and the sensor.

The Loop is very simple. We read each of the colors with the library functions and then print them to the serial monitor.

This is where I changed the code, using “DEC” instead of “HEX” to display the results in decimal. I only did this because I find decimal a bit easier to understand, but you don’t really  need to do this if you’re comfortable reading hex.

Calibrating the ISL29125

The calibration procedure tha tI used was identical to the one used with the TCS230. And as I placed all of my components on a solderless breadboard this entailed mounting the breadboard upside down!

ISL29125 on upside-down breadboard

Load the sketch and open your serial monitor. Make sure to set it for the correct baud rate or all you’ll see is gibberish!

Once again you can use a black and a white sample to get the values. Note that in this case the values will make more sense as you are reading actual 16-bit light values and not pulse width.

Once you have your calibration values in hand we can move on to the next, and final, sketch.

Getting RGB Values from the ISL29125

Our last sketch will do the same thing we did with the TCS230 – obtain RGB color values from the ISL29125 color sensor.

You’ll see a lot of the previous sketches in this sketch. It starts off the same way the Basic sketch we just ran does, by including the libraries for I2C and the ISL29125 sensor.

Now we have a section for the calibration values. Plug in the values you obtained during the calibration process.

We declare a few values to represent the RGB values. These are 8-bit integers.

The setup is identical to the previous sketch, initializing the sensor and serial monitor. I kept the same baud rate, but you can change it to suit your preference.

In the loop we read the sensor values, which will be 16-bit unsigned integers.  We then use an Arduino Map function to convert these to a range of 0-255 to represent the RGB values, which are held in three integers.

You might think we are finished here, but we are not.  Because the ISL29125 outputs a 16-bit number it is possible that the Map function will produce a value below zero or above 255.

One way of resolving this would be to simply adjust the calibration values, making the low ones lower and the high ones higher.

Instead of doing that I employed an Arduino Constrain function. As its name would imply this function constrains the value of a variable within a specified range, which in our case is 0-255.

Constrain should be used on its own and not as part of another function, so it wasn’t possible to use the Map and Constrain functions together.

The final value is printed to the serial monitor.

ISL29125 Color Test

Load the sketch to your Arduino and give it a try. I found it to be quite accurate, hopefully you’ll achieve the same results.


Both of these color sensors have a number of applications in your Arduino projects.  While the ISL29125 is more accurate and easier to use the TCS230 is very inexpensive and will suffice for non-critical applications.

So I’m interested – what application do you see for color sensors? Leave a comment below or, even better, make a post on the DroneBot Workshop Forums and show us your idea and project.

And show off your true colors!


Parts List

Here are some components that you might need to complete the experiments in this article. Please note that some of these links may be affiliate links, and the DroneBot Workshop may receive a commission on your purchases. This does not increase the cost to you and is a method of supporting this ad-free website.




Code used in this article – All of the sketches used in the article in a handy ZIP file.

PDF Document – A PDF version of the article, suitable for printing and using in your workshop.

ISL29125 at Sparkfun – A Sparkfun tutorial for using the ISL29125.

ISL29125 Library – The library for the ISL29125 sensor in ZIP format.



Color Sensing with Arduino
Color Sensing with Arduino
Article Name
Color Sensing with Arduino
Learn to use two different color sensors with an Arduino. Shows how to calibrate and use the TCS230 and ISL29125 color sensors
Publisher Name
DroneBot Workshop
Publisher Logo
Notify of

Inline Feedbacks
View all comments
Robert Mehlma
4 years ago

Hello Bill,
Thanks for your excellent videos and articles. You explainations are very usefull to me.
I have also seen your last video about color detecting.

You use the sensors to detect the color of surfaces.
Is it also possible to detect with this sensors the color of a LED? The LED has three colors, green, red and orange. Orange is less important.
I want to build a instrument that shows me remotly the state of a device.

Continue making my life with Arduinos and sensors easier.


4 years ago

Hello Bill,
I like your videos and your style of coding as it similar to something I am used to. your videos have been very helpful. what changes do i have to make to the code and the serial monitor if i wanted to use 3 sensors?

4 years ago

I dont see how the TCS230 is less precise than the other one..

Zanu Angga
4 years ago

Hey Bill,
actually i use the CJMU-29125 one, can it use the same program as ISL29125?
and can i use the bi-directional logic converter?
thanks for your reply

Zanu Angga
4 years ago

Hey Bill,
actually i use the CJMU-29125 one, can it use the same program as ISL29125?
and can i use the bi-directional logic converter?
thanks for your reply

Verboczki Alexandru-Cosmin
4 years ago


I have hooked us all the wires, and download the program to the arduino, but I can only see the max value 65535 (and i have put also and “else” section besides the if(RGB_sensor.init()) that shows that the sensor it is initialized, with the opposite message, and it gives me the else branch at each start. What should be wrong? I observe that the #include ” ” is not working but #include < > works.

Thank you!

Verboczki Alexandru-Cosmin
3 years ago


i have resolved the problem… I was using an Arduino Mega ADK, and it have a SDA and a SCL pins allready on the board, so the A4 and A5 pins does not work.

Anway, how can I make, I guess from the libraries, to get signal from two such sensors on to a single Arduino board?

Thank you!

Verboczki Alexandru-Cosmin
3 years ago

Hello, So I have managed to make it work somehow with a multiplexor, but, it works only with two sensors, if the initializing is made with one logic gate connected, and then when îs disconnected, it reades the other sensor. But if i connect a second logic gate to the multiplexor, it gives only 0 on the monitor on each color, like it is uninitialize, or it can not connect to it, of i remoce the sensor on the monitor screen I have the max value. The same problem is if i start the initialize without any logic gate connected,… Read more »

3 years ago


This is interesting. Would it be possible to use these sensors in a diplay color calibration setup?

Best regards


Verboczki Alexandru-Cosmin
3 years ago
Reply to  vito

Hello, how do you want to calibrate the display color? If you want to use it to measure the actual color of the display I think it is pretty accurate, you can make a fixing device together with a optic fiber string în The middle that should direct the Light exavtly on The sensor, it can concentrate the light a lot better on a single spot.

Henk Barkhof
3 years ago

You are doing such a good job. Simple and clear explanations Thanks for your great work !!


Geoffrey Brian Tucker
3 years ago
Hariharan K
3 years ago

Great Tutorial Sir!

I would like to know that,
1. Is there any way to use this ISL 29125 as an Optical Receiver(or a Photodiode)?
2. How is this different from a photodiode? Any Internal details of the color sensor die available?
3. What is the maximum sensing distance up to which ISL 29125 sensor can sense correctly?

Thanks and regards,

Henk Barkhof
3 years ago

I made this following your workshop but I got 3 crazy figures like 638 , 440 ,328.
How dows this relate to RGB values ??

3 years ago
Reply to  Henk Barkhof

Those are the 16 bit values, you have to Change the range to 0, 255.

2 years ago

Hey Bill Perfect Presentation as always one thing missing is the connection of the OE Pin to GND most of my students ignore connecting Digital PINs that are expected to be “0” and I keep telling them that ” Only dogs who Pee keep a leg at the air” one must connect any digital pin to VCC on GNG . its true that in most cases the Non-Connected PIN will be interpreted as “0” ( That is why the sensor is producing an output – the OE is active LOW) but if you slightly touch the Arduino pins with your… Read more »

Pierre Van Overmeire
11 months ago

Love it articleHave to admit that the indicated codes in the video are in line with the correct color interpretation. 
Made a rectangle in CorelDRAW to match the correct color with the codes in your video. According to your codes, they do not match the correct RGB codes. 
Don’t know if I can put a picture in this forum With the view of the RGB codes.

Bang Yu
7 months ago

Hello Bill,
I like your videos and I have a question for you.When I installed a 5-megapixel lens on TCS230, the pulse width became abnormally large. How can I adjust it to get a better effect?

3 months ago

My intention is to build a soda bottle lids color sorter, and donate it to an NGO that sells recycling material. They get funds to care stray cats and dogs in Sao Paulo, Brazil’s largest city.
I’m graduating in Electronics Engineering and this wil be part of my course conclusion paper.
How can I get your permission to use this in that paper?
Please, let me know if you agree.
Thank you for the excellent contents of the channel.