Automatic Power Factor Correction
Automatic Power Factor Correction
Automatic Power Factor Correction
TCS3200 chip is designed to detect the colour of light incident on it. It has an array of
photodiode (a matrix of 8x8, so a total 64 sensors). These photodiodes are covered with three
type of filters. Sixteen sensor have RED filter over them thus can measure only the component of
red in the incident light. Like wise other sixteen have GREEN filter and sixteen have BLUE
filter. As you should know that any visible colour can be broken into three primary colours. So
these three type of filtered sensors helps measure the weightage of each of primary colours in
incident light. The rest 16 sensors have clear filter.
TCS3200 converts the intensity of incident radiation into frequency. The output waveform is a
50% duty cycle square wave. You can use the timer of a MCU to measure period of pulse and
thus get the frequency.
The output of TCS3200 is available in single line. So you would ask how we get the intensity of
RED,GREEN, BLUE and CLEAR channels? Well it has two inputs S2 and S3 that is used to
select the sensor whose output need to be made available on the out line.
S2 S3
RED L L
GREEN H H
BLUE L H
CLEAR H L
So we select a channel either RED, GREEN, BLUE or CLEAR and then do the measurement of
the output pulse width to get that channel's intensity. In our library we have made these four
functions to do this task.
void TCSSelectRed()
{
TCSS2Low();
TCSS3Low();
}
void TCSSelectGreen()
{
TCSS2High();
TCSS3High();
}
void TCSSelectBlue()
{
TCSS2Low();
TCSS3High();
}
void TCSSelectClear()
{
TCSS2High();
TCSS3Low();
}
The functions TCSS2High(), TCSS2Low() etc are low level functions that controls the i/o lines
connected to S2 and S3 lines.
TCS3200 Module
Since TCS3200 chip is a small SMD chip and is tough to prototype designs using the surface
mount chip. Thus we have made a small module that has the TCS3200 chip, four white LEDs,
LED control circuit and few other basic components on a PCB. The module has the connection
all the line on 0.1inch male header. This makes it easy to connect with microcontroller boards.
The white LEDs throws light on the object that is placed in front of the sensor. For best
performance the object should be placed 1inch away from the LEDs such that the beam from all
four LEDs converge at a single point (and do not make four distinct light spots on the object).
One i/o pin of MCU can be used to switch on and off the LED.
In our library we have made two functions to control the TCS3200 module's LEDs.
TCSLEDOn()
TCSLEDOff()
Fig. TCS3200 Module.
Fig. TCS3200 Module.
For measuring the output frequency of the TCS3200 we have used TIMER1 of AVR. Which is
16 bit timer. We have clocked the TIMER1 using same frequency as the CPU that is 16MHz
without any division.
The function which is used to measure the frequency of TCS3200 is named TCSMeasure() The
implementation of this function is given below.
uint32_t TCSMeasure()
{
//If the function is entered when the level on OUT line was low
//Then wait for it to become high.
if(!(TCS_OUT_PORT & (1<<TCS_OUT_POS)))
{
while(!(TCS_OUT_PORT & (1<<TCS_OUT_POS))); //Wait for rising edge
}
TCNT1=0x0000;//Reset Counter
//Stop Timer
TCCR1B=0x00;
return ((float)8000000UL/TCNT1);
Code Walkthrough
We measure the time between the falling the edge and next rising edge. So we must take care
when the function is called and the level on the OUT line is already LOW (that means already
some time has passed from the last falling edge, so we wait for the line to become high). As soon
as a falling edge is detected we start RESET the TIMER1 counter (TCNT1 to 0). Then we start
the timer by writing to the control register TCCR1B. Then we wait for a rising edge. And as soon
as we get a rising edge we stop the timer and do a small calculation to calculate the frequency.
Finally this frequency is returned.
A demo program which shows the use of TCS3200 function is provided below. This demo
program runs on xBoard v2.0 it shows program output on a 16x2 LCD module. The program
waits for an object to be placed in front of the sensor module. And when an object is placed it
measures the colour of object and shows the relative weightage of RED,GREEN and BLUE
components. The buzzer beeps and the LED glows whenever an object comes in front of the
sensor.
/****************************************************************************
*
Colour Sensor TCS3200 Demo Program
HARDWARE
--------
MCU = ATmega32 Running at 16MHz Crystal (LFUSE=0xFF HFUSE=0xC9)
LCD | ATmega32
RS -> PD3
R/W -> PD6
E -> PB4
DB0 ->
DB1 ->
DB2 ->
DB3 ->
DB4 -> PB0
DB5 -> PB1
DB6 -> PB2
DB7 -> PB3
TCS3200 Module
**************
ATmega32
S2 -> PA0
S3 -> PA1
OUT ->PA2
LED ->PA3
NOTICE
--------
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A
WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY
PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.
WRITTEN BY:
AVINASH GUPTA
[email protected] (Yes ! It's correct !)
*****************************************************************************
**/
#include <avr/io.h>
#include <util/delay.h>
#include "lib/lcd/lcd.h"
#include "lib/colour_sensor/tcs3200.h"
uint32_t MeasureR();
uint32_t MeasureG();
uint32_t MeasureB();
uint32_t MeasureC();
int main(void)
{
//Initialize the LCD Library
LCDInit(LS_NONE);
//Clear LCD
LCDClear();
while(1)
{
LCDWriteStringXY(0,0," Waiting. ");
TCSLEDOn();
uint32_t v1=MeasureC();
_delay_ms(100);
TCSLEDOff();
uint32_t v2=MeasureC();
uint32_t d=v1-v2;
if(d>8000)
{
//Object came in range
LCDClear();
PORTD|=(1<<PD7); //Buzzer On
_delay_ms(250);
//Show
uint32_t r,g,b;
TCSLEDOn();
r=MeasureR();
g=MeasureG();
b=MeasureB();
TCSLEDOff();
uint32_t smallest;
if(r<b)
{
if(r<g)
smallest=r;
else
smallest=g;
}
else
{
if(b<g)
smallest=b;
else
smallest=g;
}
uint32_t _r,_g,_b;
smallest=smallest/10;
_r=r/smallest;
_g=g/smallest;
_b=b/smallest;
LCDWriteIntXY(0,1,_r,4);
LCDWriteIntXY(5,1,_g,4);
LCDWriteIntXY(10,1,_b,4);
//End Show
_delay_ms(2000);
}
LCDWriteStringXY(0,1,"%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0");
LCDWriteStringXY(x,1,"%1");
LCDGotoXY(16,1);//Hide cursor.
x+=vx;
if(x==15 || x==0)
vx=vx*-1;
_delay_ms(50);
uint32_t MeasureR()
{
TCSSelectRed();
uint32_t r;
_delay_ms(10);
r=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
return r/3.3;
uint32_t MeasureG()
{
TCSSelectGreen();
uint32_t r;
_delay_ms(10);
r=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
return r/3;
uint32_t MeasureB()
{
TCSSelectBlue();
uint32_t r;
_delay_ms(10);
r=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
return r/4.2;
uint32_t MeasureC()
{
TCSSelectClear();
uint32_t r;
_delay_ms(10);
r=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
_delay_ms(10);
r+=TCSMeasure();
return r/3;
}
TCS3200 Library
tcs3200.c
tcs3200.h
They must be copier to current project folder and added to Atmel Studio Project.
TCS3200 Demo Schematic
Related Articles
This demo makes use of our LCD Library please see the following tutorial for more information
on LCD Modules and the library functions.
We have used microcontroller's timer to measure the period of the waveform comming from
TCS3200. You can consult following tutorial for basic information and usage of timers.
You can purchase the module online from our online store. We ship all over India. Payment
can be made online by using debit card or netbanking account. You will receive the product
within 3-5 working days delivered right to your doorsteps!
Troubleshooting
NO Display on LCD
o Make sure AVR Studio Project is set up for clock frequency of 16MHz (16000000Hz)
o Adjust the Contrast Adj Pot.
o Press reset few times.
o Power On/Off few times.
o Connect the LCD only as shown on schematic above.
Compiler Errors
1. Many people these days has jumped to embedded programming without a solid
concept of computer science and programming. They don't know the basics of compiler
and lack experience. To learn basic of compilers and their working PC/MAC/Linux( I
mean a desktop or laptop) are great platform. But embedded system is not good for
learning about compilers and programming basics. It is for those who already have
these skills and just want to apply it.
2. Make sure all files belonging to the LCD Library are "added" to the "Project".
3. avr-gcc is installed. (The Windows Binary Distribution is called WinAVR)
4. The AVR Studio project Type is AVR GCC.
5. Basics of Installing and using AVR Studio with avr-gcc is described in this tutorial
General Tips for newbie
o Use ready made development boards and programmers.
o Try to follow the AVR Tutorial Series from the very beginning. (Remember the list spans
four pages, page 1 is most recent addition thus most advance)
Downloads
Here is the image and the block diagram of the TCS230 color sensor,
The first block that comes into picture is the Photodiode array. The photodiode array consists
of three sets of diodes each for sensing Red, Green and Blue color respectively. So, when
you are measuring the intensity of Red light you need to enable only the Red photodiode
array and disable the other two photo diode arrays.
The output enable pin is generic output enable pin which turns the square wave output
ON/OFF.
Detecting the color: The TCS230 color sensor is having only one output pin on which a 50%
duty cycle square wave is output continuously.
First we need to make the OE pin low to enable the sensor output, and then make the S0 = 1,
S1 = 0 to select a 20% scaled squarewave output.
When we are measuring the color of any object in front of the sensor, we need to perform the
measurement in three steps,
1. Measure the Red color: To enable only the Red photo diode array by making S2=0,
S3=0. Wait for sometime and measure the time period of the square wave on the
output pin by enabling only Red photodiode array.
2. Measure the Blue color: To enable only the Blue photo diode array by making S2=0,
S3=1. Wait for sometime and measure the time period of the square wave on the
output pin by enabling only Blue photodiode array.
3. Measure the Green color: To enable only the Green photo diode array by making
S2=1, S3=1. Wait for sometime and measure the time period of the square wave on
the output pin by enabling only Green photodiode array.
After you get the values of the Red, Green and Blue components, you can get the name of the
color from any RGB color table. You can also measure the light intensity on the sensor by
disabling color filters. To measure the light iintensity disbale the color filters by making
S2=1, S3=0. Wait for sometime and measure the time period of the square wave on the
output pin.
Here i have configured the PIC's timer module in capture mode where i measure the square
waves time period. The color sensors output is connected to the timers capture input pin. To
measure RED color, i enable only the Red color receptors and measure the count in the timer
registers after a delay which gives me the pulse width.
Here is the piece of code i wrote for PIC16F877A microcontroller. If you want i can share
the libraries code.
Download the code for TCS230 color sensor with PIC16F877A microcontroller
?
1 <p></p>
2 <pre>#include "LCD.h"
3 #include "UART.h"
#include "I2C.h"
4 #include "Timer.h"
5 unsigned short Data[20];
6 unsigned short Red,Green,Blue,Brightness;
7 unsigned short Count = 0;
unsigned char over = 0;
8
9 unsigned char Colour;
10 unsigned char Level, PrevLevel;
11
12 void InitInterrupts(void)
13 {
14 //TRISB0 = 1;
//INTEDG = 0;
15 //INTE = 1;
16 PEIE = 1;
17 //ADIE = 1;
18 CCP1IE = 1;
GIE = 1;
19 }
20
21 unsigned short i;
22
23 unsigned char Temp;
24
25
26
27 void SendPacket(void)
28 {
//GIE = 0;
29 Print("$");
30 if(10000/Brightness < 200)
31 {
32 if(Red < Blue && Red < Green)
33 {
Print("Red");
34 }
35 else if(Green < Red && Green < Blue)
36 {
37 Print("Green");
}
38 else if(Blue < Red && Blue < Green)
39 {
40 Print("Blue");
41 }
42 }
else
43 {
44 Print("Too Bright");
45 }
46 PrintNumber3(10000/Red);
Print(",");
47 PrintNumber3(10000/Green);
48 Print(",");
49 PrintNumber3(10000/Blue);
Print(",");
50 PrintNumber3(10000/Brightness);
51
52 Print("\r\n");
53 if(over==1)
54 Print("Overflow\r\n");
//Delay(120000);
55 //GIE = 1;
56 //Delay(120000);
57 }
58
59 // rgbb 443 573 427 189
60 void main()
{
61
62 TRISB4 = 0;
63
64 // colour s2 s3
65 TRISDbits.TRISD1 = 0;
66 TRISDbits.TRISD0 = 0;
67 // led
TRISCbits.TRISC3 = 0;
68 // out
69 TRISCbits.TRISC2 = 1;
70
71 // s0 s1 = frequency
72 TRISDbits.TRISD2 = 0;
73 TRISDbits.TRISD3 = 0;
74
//leds
75 RC3 = 1;
76
77 InitUART();
78
79 i = 0;
80
81 InitInterrupts();
82 InitTimer1();
StartTimer1();
83
84 RD2 = 1;
85 RD3 = 0;
86
87 Colour =1;
88 while(1)
89 {
switch(Colour)
90 {
91 case 0:
92 RD1 = 0;//RED
93 RD0 = 0;
Delay(5000);
94 Red = Count;
95 Colour++;
break;
96 case 1:
97 RD1 = 0;//Blue
98 RD0 = 1;
99 Delay(5000);
Blue = Count;
100 Colour++;
101 break;
102 case 2:
103 RD1 = 1;//No color
104 RD0 = 0;
Delay(5000);
105 Brightness = Count;
106 Colour++;
107 break;
108 case 3:
RD1 = 1;//Green
109 RD0 = 1;
110 Delay(50000);
111 Green = Count;
112 Colour = 0;
113 break;
}
114 GIE = 0;
115 SendPacket();
116 GIE = 1;
117
118
119
120
121 }
122
123}
124unsigned long Sum;
125static void interrupt isroutine(void)
126{
127
128 if(INTF == 1)
129 {
130
131 }
if(CCP1IF == 1)
132 {
133 Count = CCPR1;
134 TMR1H = 0x00;
135 TMR1L = 0x00;
136
137 CCP1IF = 0;
138
}
139
140 if(TMR1IF == 1)
141 {
TMR1H = 0x00;
142 TMR1L = 0x00;
143 TMR1IF = 0;
144 over = 1;
145 }
146
147
148
149}
</pre><p></p>
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
The output of the color sensor is connected to INT0 of 8051 microcontroller. The
microcontroller uses the timer module to measure the time period of the square wave pulses.
The objective of the code is to detect the color as RED,BLUE,GREEN and move a stepper
motor to a particular position.
Here is a piece of code i wrote for interfacing TCS230 color sensor with 89s52/8051
microcontroller.
<p></p>
<pre>#include <reg52.h>
#include"SCI.h"
#include"LCD.h"
#include "Controller.h"
#define STEPS 30
#define NO_COLOUR 0
#define RED 1
#define GREEN 2
#define BLUE 3
}; */
{
//NO_COLOUR, RED, GREEN, BLUE
0,-STEPS,0,STEPS,// NO_COLOUR
0,0,STEPS,STEPS*2,// RED
0,-STEPS,0,STEPS,// GREEN
0,-STEPS*2,-STEPS,0// BLUE
};
while(Steps>0)
//while(1);
Delay(500);
Delay(500);
Delay(500);
Delay(500);
Steps--;
while(Steps>0)
//while(1);
Delay(500);
Delay(500);
Delay(500);
Delay(500);
Steps--;
int Steps;
Steps = BiforcatorPosition[Prev][Curr];
//DisplayString(LINE1,"prev=",Prev,DATA_WRITE);
//DisplayString(LINE4,"curr=",Curr,DATA_WRITE);
//PrintNumber3(Curr);
if(Steps < 0)
RotateAntiClockWise(Steps*-1);
//DisplayString(LINE3,"stps=",Steps,DATA_WRITE);
else
//DisplayString(LINE3,"stps=",Steps,DATA_WRITE);
RotateClockWise(Steps);
while(Count > 0)
Count--;
};
void UpdateDisplay(void)
//InitLCD();
DisplayString(LINE2,"50 KG = ",RedBags,DATA_WRITE);
DisplayString(LINE3,"100 KG = ",GreenBags,DATA_WRITE);
DisplayString(LINE4,"250 KG = ",BlueBags,DATA_WRITE);
void SendPacket(void)
//GIE = 0;
Print("$");
if
(
Print("Red");
if(PrevColour != RED)
RedBags++;
//DisplayString(LINE2,"Red",DUMMY_DATA,MESSAGE_WRITE);
MoveMotor(Prev,RED);
PrevColour = RED;
Prev = RED;
//DisplayString(LINE2,"Red",DUMMY_DATA,MESSAGE_WRITE);
Print("Green");
if(PrevColour != GREEN)
GreenBags++;
//DisplayString(LINE2,"Green",DUMMY_DATA,MESSAGE_WRITE);
MoveMotor(Prev,GREEN);
PrevColour = GREEN;
Prev = GREEN;
//DisplayString(LINE2,"Green",DUMMY_DATA,MESSAGE_WRITE);
Print("Blue");
if(PrevColour != BLUE)
BlueBags++;
//DisplayString(LINE2,"Blue",DUMMY_DATA,MESSAGE_WRITE);
MoveMotor(Prev,BLUE);
PrevColour = BLUE;
Prev = BLUE;
//DisplayString(LINE2,"Blue",DUMMY_DATA,MESSAGE_WRITE);
else
Print("Too Bright");
if(PrevColour != NO_COLOUR)
PrevColour = NO_COLOUR;
}
//DisplayString(LINE2,"Too Bright",DUMMY_DATA,MESSAGE_WRITE);
PrintNumber3(10000/Red);
Print(",");
PrintNumber3(10000/Green);
Print(",");
PrintNumber3(10000/Blue);
Print(",");
PrintNumber3(10000/Brightness);
Print("\r\n");
UpdateDisplay();
//Delay(120000);
//GIE = 1;
//Delay(120000);
void ReadColour(void)
Colour = 0;
while(1)
switch(Colour)
case 0:
PORT20 = 0; //Red
PORT21 = 0;
Pulses = 0;
EA = 0;
Red = GapDuration;
EA = 1;
Colour++;
break;
case 1:
PORT20 = 0;
PORT21 = 1;
Pulses = 0;
EA = 0;
Blue = GapDuration;
EA = 1;
Colour++;
break;
case 2:
PORT21 = 0;
Pulses = 0;
EA = 0;
Brightness = GapDuration;
EA = 1;
Colour++;
break;
case 3:
PORT20 = 1;//Green
PORT21 = 1;
Pulses = 0;
EA = 0;
Green = GapDuration;
EA = 1;
EA = 0;
SendPacket();
EA = 1;
Colour = 0;
return;
break;
TR0 = 0;
TH0 = 0x00;
TL0 = 0x00;
TR0 = 1;
Pulses++;
//Print("Duration = ");
//PrintNumber(GapDuration);
//Print("\n\r ");
unsigned short i;
EA=0;
DC_MOTOR = 0;
SERV_MOTOR1 = 1;
SERV_MOTOR2 = 0;
Delay(11000);
//Delay(42000);
SERV_MOTOR1 = 0;
SERV_MOTOR2 = 0;
Delay(40000);
SERV_MOTOR1 = 0;
SERV_MOTOR2 = 1;
Delay(11000);
//Delay(42000);
SERV_MOTOR1 = 0 ;
SERV_MOTOR2 = 0;
//ex1_isr_counter++;
Delay(10000);
DC_MOTOR = 1;
EA=1;
TH0 = 0x00;
TL0 = 0x00;
Print("Overflow");
TF0 = 0;
void InitSystemRegisters(void)
TMOD = 0x29;
ET0 = 1;
IT0 = 1;
EX0 = 1;
EX1 = 1;
TR0 = 1;
SCON = 0x50;
//
//
//
//
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
//ES = 1;
//EA = 1;
EA = 1;
DC_MOTOR = 1;
</pre><p></p>