Der sprechende Farbdetektor mit DFPlayer und TCS3200 - [Teil 2]


In the first part of this blog series we have put the MP3 player into operation for the voice output. In addition, we have added a user input with a button and a potentiometer. In the second part we now want to connect and test the color sensor. I will show you which libraries are available and what to pay attention to when operating the sensor. Come on Let's go.

What we need

Number Component
1 TCS3200 Color Sensor Module
1 DFPlayer Mini MP3 Player Module
1 Mikro-SD card
1 Arduino Nano V3.0
1 Microphone (Max 3 W)
Connecting cable
Resistance 1 KOhm
Variable resistance (potentiometer)
1 Push button
Computer with Arduino IDE and internet connection
External voltage source (recommended), 7 - 12 V
Color reference cards

I assume that you have built the circuit from Part 1 and inserted the SD card with the voice files in the SD slot of the MP3 player. We will not need these components yet, but it is advantageous if the circuit is already constructed as we need it at the end. So we will supplement you through the color sensor.

DFPlayer Mini Pins Arduino Nano Pins
RX over 1 KOhm at D11 (TX)
TX D10 (RX)
SPK_1 Red (Plus)
SPK_2 Black (Minus)
Potentiometer Arduino Nano Pins
2 (middle) A0
3 +5V
Pushbutton Arduino Nano Pins
1 D12

For a function test, we invite the program from Part 1 to the Arduino:

Complete source code: 1.2DfplayerStarting soundPotionTaster.ino

Color sensor

The TCS3200 color sensor consists of a photodiodes arranged in the grid. There are always four in the square arranged. Three of them are equipped with a color filter in red, green or blue. A photodiode does not contain a color filter. Of these quartets there are 16 evenly distributed on the sensor surface, so a total of 64 photodiodes.

The diodes with the same color filters are connected to each other. This grid of diodes is the actual color sensor that is soldered to the breakoutboard. In addition, there are four white LEDs that illuminate the object. The light is reflected and thrown back to the photodiodes which produce a voltage out of the light. The color filters then ensure that each color group accommodates only one color. With the connections S2 and S3, the photodiode groups can be activated and deactivated. There are four combinations, so that always a group is turned on with the same color.

S2 S3 Color
HIGH LOW Clear (without filter)


The generated voltage of each photodiode group is converted to a rectangular oscillation with a voltage-frequency converter. Depending on the color of the object changes its frequency. One receives a frequency value from each of the color groups. This must then be converted into meaningful RGB values.

Other connections are S0 and S1. They serve a frequency divider with which the output frequency scales and the sensor can also be disabled.

S0 S1 Output frequency scaling
LOW LOW Disabled

Pin Vcc and GND serve the power supply which may be between 2.7 and 5.5V. At the out-pin, the measured frequency we can measure at the Arduino. The PIN OE (OUTPUT ENABLE) activates or deactivates the output of the sensor. He is Low Active. If nothing is available at this entrance, the sensor is active by default. So you can turn out the program out the output to e.g. to connect multiple sensors that should not interfere with each other. Otherwise you can leave it free, or connect with GND.

Technical details of the sensor can be found in data sheet.


We add the color sensor in our circuit as follows:


TCS3200 Pins Arduino Nano Pins
S0 D4
S1 D8
S2 D6
S3 D7

As you may recognize, the pins are not completely chronologically arranged. That also has its reason. One of the libraries I will show later requires the output to pin D5. So everything is uniform and we do not have to change every time, I also leave that for the other examples that I will show.

Things we have to pay attention to

The sensor also takes up the ambient light. Of course, this changes the measured values. In addition, the distance of the sensor to the measurement object (recommended are between 1 and 3 cm) decisive. It is advisable to construct a locked box so that the fault factors remain as constant as possible. Then it is possible to calibrate the sensor and to adjust it to its environment. I I spontaneously made a slightly tinker from black paper.

You can still see a narrow paper strip I have laid around the sensor. In my opinion, too much light radiates from the LEDs directly to the sensor. I have found some models for 3D printing at Thingiverse, which are also thought of it (here and here).

Of course you can also design a housing as a 3D model, in which the rest of the electronics has space. It is important that so little light can hit the sensor from the outside and the distance to the measured surface remains the same. It would offer to use a weaning flashlight. There, the same is the battery for mobile power supply.

Without libraries

I found different variants during my research to the TSC3200 (and also the TCS230, the predecessor model) to program this component with the Arduino. Before I immediately show the two libraries I have found, I would like to go back to how the communication between the micro controller and the sensor works.

As mentioned above, the pins S2 and S3 are responsible for the wiring of the photo diodes. There are four color groups whose diodes (red, green, blue and clear without filter) are activated by one of the combinations of S2 and S3. The sensor then generates a uniform rectangular signal at the output. Its pulse width (i.e. the time of a "oscillation") must then be measured with the Arduino. For this purpose, no additional library is required. Let's try it first without.

We define our Arduino Pins as constants:

#define s0 4
#define S1 8
#define S2 6
#define S3 7
#define oe 3 // low = enabled
#define tcs_in 5

Then we need some variables for the colors. In addition, I want to format the issue on the serial monitor. I solve with a string buffer:

int rot = 0;
int gruen = 0;
int blau = 0;
int klar = 0;
char serialBuffer[55];

in the set up() Let's initialize the serial monitor (also here again make sure that the same baud rate is set there):

void setup()
  pinMode(S0, OUTPUT); //S0
  pinMode(S1, OUTPUT); //S1
  pinMode(S2, OUTPUT); //S2
  pinMode(S3, OUTPUT); //S3
  pinMode(OE, OUTPUT); //S3
  pinMode(TCS_IN, INPUT); //OUT

  // Sensor Output aktivieren
  digitalWrite(OE, LOW);
  // Frequenzteiler auf 20%
  digitalWrite(S0, HIGH);
  digitalWrite(S1, LOW);

The inputs of the color sensor S0 to S3, as well as OE are entrances there. Thus, you can set as outputs on the Arduino. The sensor output is an input on the Arduino. To put the PIN for OE again on low, you just have to do if it is connected. Since he is Active Low, you can also leave it unconnected and then does not have to initialize it. It is also possible to connect it to the GND pin, but not necessarily necessary.

The frequency divider we set (as in the table shown above) to 20%.

In the Loop ()-Function we will now activate the individual color groups one after the other and measure the values ​​at the input. So that we can better compare this data, I have added an interruption:

// Auf Eingabe warten
  while (Serial.available() == 0) {
    if (Serial.available() != 0) {
  // Serial Puffer loeschen
  while ( != -1) {}

When you open the serial monitor, you can simply press the Enter key in the input field. Then a measurement series is performed. For the next values, you must press the button again. The following is the wiring of the photo diodes and the measurement at the entrance of the Arduinos:

  // LOW / LOW = rote Photodiode 
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);
  // Frequenz messen
  rot = pulseIn(TCS_IN, digitalRead(TCS_IN) == HIGH ? LOW : HIGH);
  // LOW / HIGH = blaue Photodiode
  digitalWrite(S3, HIGH);
  blau = pulseIn(TCS_IN, digitalRead(TCS_IN) == HIGH ? LOW : HIGH);
  // HIGH / HIGH = Gruene Photodiode
  digitalWrite(S2, HIGH);
  gruen = pulseIn(TCS_IN, digitalRead(TCS_IN) == HIGH ? LOW : HIGH);
  // HIGH / LOW = Photodiode ohne Filter
  digitalWrite(S3, LOW);
  klar = pulseIn(TCS_IN, digitalRead(TCS_IN) == HIGH ? LOW : HIGH);    
  // Ausgabe
  sprintf(serialBuffer, "Rot: %4d Gruen: %4d Blau: %4d Klar: %4d", rot, gruen, blau, klar);

S2 and S3 are first set to LOW / LOW, then S3 to HIGH. S2 remains LOW, which results in LOW / HIGH. Then S2 is set to HIGH, which results in HIGH / HIGH, because S3 is not changed. Finally, S3 is set to LOW without changing S2, which gives HIGH / LOW. Compare the combinations with the table shown above for each color. I only swapped green with clear here so that only one digital pin needs to be changed at a time in the sequence, which means less time for commands for the processor.

Finally, the values ​​are output on the serial monitor. For this I use the formatted edition, but not on the Arduino Nano Serial.Printf () works. A small detour goes here via the formatted output in a char array that will be sent to the serial monitor.

Complete source code: 2.0TCS3200Test.ino

Download the program to the Arduino, hold the sensor to a color area of ​​your choice and press ENTER in the input field of the serial monitor. Then see the color values. Switch the color area and press the Enter key again. Then change the color values.

I have scanned red, green, blue, black and white and get the following results:

Now we have to interpret the values ​​first. Each line is a color scan. Let's look at the first line. These values ​​represent the red color of my reference card. A full red assembled, from the three color values ​​in additive form in 8 bits would be 255, 0, 0 (R, G, B). We will only achieve such ideal colors. This is that these output values ​​are not 8 bits. In addition, we can see that the rotary part is lower than the shares for green and blue. The next line is the green reference card. Here we see that the shares are green and blue. That would usually be a turquoise rather. For the Blue Reference Card we see that the values ​​for the blue share are lower. If we measure the black area, the values ​​are much higher. White gives very low values. This can be concluded that lighter colorants per color channel mean low values.

The function pulseIn() Measures the time between state changes on a pin. So the output values ​​are not voltage values ​​that can be used e.g. with analogRead () receives. These are frequencies. The lower the frequency, the brighter the color value. For the color red, this means that the proportion of red reflected light is the brightest and thus has the lowest value.

From this one could now write a program that recognizes colors for us. Since it is also more than 8 bits, you can portray the color differences much finer. If you change the frequency scaling, you can even influence this resolution. For this project, however, simple colors and the program are sufficient to write, I also leave outside.

With libraries

We now want to make our talking color detector to pronounce the colors. How does he know that it is red and what if the color values ​​differ a little? After all, red is not red. For this we would have to implement a calibration in the program. In addition, we would need a weighting if the colors differ slightly.

We do not have to program these things myself. Here we now come to the libraries. The work has already done someone and we now want to test their examples. We install the libraries MD_TCS230 from majicDesigns and tcs3200 from Panjkrc from the library management:

If you enter the search box "TCS", the appropriate results appear. We are now available to these libraries and their supplied examples. Click on "info" in library management on the respective entry leads you to the descriptions and source texts on GitHub. However, a mistake has crept into the link of majicsDesigns. You can reach the GITHUB page with this link.

Let's start with the MDTCS230 library. It works, among other things, with the successor model TCS3200, which is now available. There are four examples included. With the projects "SimpleBTCS230 "and" SimpleNB_TCS230 "will be shown a comparison between blocking and non-blocking in connection with this sensor. I do not want to go on it. However, try it yourself once. Pay attention to the pins used.

Let's open the example "Calibrate_TSC230". Here will notice that a library name is used "FreqCount.h". This must be installed:

We change the pins numbers in the example under "Pin Definitions" as in our test project. These are for S2 pin 6 and for S3 pin 7. OE is pin 3.

Note: This is the library that requires (as mentioned above) the sensor output at the input of the Arduino Pins D5. This is set in the library "FreqCount.h". More information can be found on the website of Paul Stoffregen. There is also a list that pins need to be used for the respective Arduino boards.

The baud rate for the serial monitor we change either in the source code, or in the serial monitor. You can decide that for themselves because both are. It is important only that both has the same value. After these changes, we invite the program to the Arduino and lead it out.

You will notice that the pins S0 and S1 are not specified. These are used (as described above) for the frequency scaling, which does not have to be set in this program. Without watching the library's source code, I assume that the setting was programmed there.

When the program starts and the serial monitor has been opened, an indication that black should be scanned. We do and confirm with Enter. Then the whole thing again with white. Then you can then scan the desired colors. I test that with red, blue and green and get the following values:

My red reference card has the color shares 127, 16, 18 (R, G, B). Blue has 19, 51, 99 (R, G, B) and green has 53, 78, 39 (R, G, B). In this case, the 8-bit color values, i. Each color channel can take the values ​​0 to 255. The larger the value, the higher the color content. Therefore, the rotary part is highest in the recorded red color. This is the difference to our first test with this sensor. The values ​​have already been converted here. We lack a weighting for our talking color detector.

We open the sample project "colormatch_tcs230" from the same library. Here we also change the pins numbers for S2, S3 and OE (6, 7 and 3). In addition, we adapt the baud rate for the serial monitor and load the program on the Arduino. In the screen output we are asked to choose between Learn or Match Mode. In Learn Mode, we take reference values ​​again. We need them to put them in the file Colormatch.h enter. With a look at this file (you can reach in the rider under the menu in the Arduino IDE), we see an array for different colors. There, the values ​​from the Learn mode are entered later.

We go through the process of the Learn Modes, in which we enter a large "L" in entering the serial monitor. Now we have to record black and white again. These are the maximum reference values. White ideally has the values ​​255, 255, 255 (RGB) and black has 0, 0, 0 (RGB). Since we do not always achieve these ideal values, we need the calibration.

In the next step, we can record our references for the colors in the Farbarray. We can also enter your own names for the colors. If we do not write names in the input, the texts are taken from the template. After we have scanned all the colors, the following information appears in the output:

We copy the text from "// Calibration Data" and add it to the file Colormatch.h One by replacing the existing text there.


Note: In the Serial Monitor, highlight the text and press Ctrl + C on the keyboard. Right mouse button and copying does not work here.

We now recharge the program on the Arduino. Our reference values ​​are stored. We now select the match mode with "M". If we scan one of the previously stored reference colors, we will be issued again. This time a weighting takes place. Even if the values ​​are not exactly the same, it still remains the same color:

35, 14, 8 (RGB) and 27, 9, 5 (RGB) is recognized by me as brown.

With the result we can already be satisfied because we need exactly that for our talking color detector. But that would mean that we record the reference colors each time and then re-program the Arduino. We keep that in mind and now want to test the second library we have installed.

We open the Sample Project "TCS3200_Calibration" from the library "TCS3200". The PIN D5 does not necessarily have to be used here for the output. Here we could change the pen sequence again so that it is chronological. However, I let them put them so if I want to compare something again. Then I do not need to change to use the other library again. So we change the pin numbers in this line:

TCS3200 TCS (4, 8, 6, 7, 5); // (S0, S1, S2, S3, Output PIN)

The OE pin is not needed here. But since we have put it, we also initialize him to make sure he is set with low level. In addition, we will adjust the baud rate for the serial monitor again:

void set up() {
Serial.Begin (115200);
PinMode (3, Output);
DigitalWrite (3, low);

If you now want to load the program on the Arduino, you will receive an error message. At least in the event that the following line is included in your source code in the upper part:

String Distinctcolors [NUM_OF_COLORS] = {"White", "Black", "red", "Yellow", "Green", "orange", "Blue"};

That can not work. On the Github page The library find the same example, but the line looks like this:

int DISTINCTCOLORS [NUM_OF_COLORS] = {0, 1, 2, 3, 4, 5, 6};

The library expects the function ClosestColor () An int array and no string array. Why the example in library administration is different, I can not say. Maybe there is no mistake. After correction, the program can be compiled and uploaded. I still keep the old line and change the name of the array:

String COLORNAMES [NUM_OF_COLORS] = {"White", "Black", "red", "Yellow", "Green", "orange", "Blue"};

At this time, I already suspected that the names of the colors, instead of numbers should be issued. We can then implement that later.

If we run the program, we see the cyclic output of the color values.

In the source code we will find the following line in the upper area:

int DISTINCTRGB [NUM_OF_COLORS] [3] = {{250, 250, 250}, {0, 0, 0}, {142, 34, 41}, {166, 125, 71}, {35, 55, 38}, {150, 50, 43}, {22, 25, 45}};

These are the reference values ​​for the colors. Now keep all the reference cards before the sensor and take over the color values ​​from the serial monitor in the array. The order I take over from the line of the color. So white, black, red, yellow, green, orange and blue. Then download the program on the Arduino and scan one of the colors. You should see the appropriate number for you.

But since we want to see texts instead of numbers, we change in the Loop ()Function the output. The function ClosestColor () returns an int value. This is still spent there. We can use it as an index for the array with our color names. So we simply change the line:

Serial.PrintLN (TCS.ClosestColor (DistinctrGB, DistinctColors, Num_OF_Colors));



Prerequisite is that you have kept the line with the names as I have renamed the array in COLORNAMES [].

If we charge the program on the Arduino and scan one of the reference colors, we will see the associated names. Again, a weighting takes place, i. The values ​​may vary and the colors are still recognized. To add more colors, we need the constant Numofcolors change and carry more fields in the arrays distinctrg, distinctcolors and COLORNAMES a. I will continue in the third part.

Complete source code: 2.1TCS3200calibration_changed.ino

With this library will be the example TCS3200_Example Included. However, only measured color values ​​are output there. There, the reference values ​​from the calibration can not be entered. In addition, the weighting and output of the recorded color is missing. Therefore, I do not go on the example at this point.


In the next blog post we will integrate the color sensor into our program. We have two ways to scan colors and to spend the name of the recorded color with weighting. Our device should output the color as a language. We will look for a way to simplify calibration and bypass the step of loading the program twice on the Arduino. That means, we have to switch between Learn Mode and Match Mode in live operation and save the data directly on the Arduino. In addition, I would like to add more languages ​​that we can also switch in live operation. Since we also want to use the device mobile, I will prepare it for battery operation.

Until then,

Andreas Wolter

For AZ-Delivery Blog

For arduinoProjects for beginnersSensors

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN