Ambient light color sensing
Original Assignment
The goal of this project is to build a sensor that can detect the color of light produced by an LCD projector (such as the one in the lab). The sensor will consist of three tightly bundled phototransistors (e.g., the OP506B from digikey), each with its own color filter (see, for example, this description of color filters). Three analog inputs will read the sensed values and the program will print the RGB (or similar) values to an LCD screen (see, e.g., C_Example:_Serial_LCD or C_Example:_Parallel_Interfacing_with_LCDs). The demonstration will show these values changing as you move from one part of the projected image (a simple test pattern consisting of single-color blocks) to another.
Overview
A phototransistor will alter its emitter current according to the amount of light shone upon its base input. Thus, the current will be at its maximum when the transistor receives the most light, and at a minimum when it receives no light. To translate this current into a voltage measurable by the PIC, the voltage can be probed across a resistor placed in series at the collector or emitter of the phototransistor. This means that maximum voltage (at maximum light exposure) should be approximately equal to the input voltage at the collector, minus the voltage drop across the transistor, and the minimum voltage should be approximately zero.
To split the source light into separate colors, color filters must be used to block out other wavelengths of light. A red color filter will allow red light to pass through (650 nm), a cyan filter will allow cyan light to pass through, and a green filter will allow green light to pass through (510 nm). Note that filters may also allow light out of the visible spectrum (for example, Infrared radiation), so be sure to consult the spectral property of the individual filter you intend to use. The spectrum of the green filter can be seen on the right. (Click here for filter spec sheet).
These three filters will split light into Red-Green-Blue (RGB) components, a common quantification of the visible spectrum in PCs. Note that phototransistors may be sensitive to differing wavelengths of light, usually visible light or IR phototransistors- make sure you choose the correct one for your purposes.
Once you have three different phototransistor voltages that are dependent on 3 RGB values, each one can be connected to the PIC via an analog input. While the voltage read may be between 0 and 5, it can be adjusted linearly to a scale from 0 to 255, the range for an RGB value. Each transistor will have a value from 0 to 255, which can then be reconstructed back into a single color on the computer, or can be printed out to an LCD screen.
The LCD screen is a two-line parallel port screen, model MCC162A4-5. The information for displaying content on the lcd screen can be found here: C_Example:_Parallel_Interfacing_with_LCDs.
Phototransistors can be purchased through digikey. Color filters may be ordered here.
Circuit
R = 100 kOhm. Rp has a max value of 10 kOhms.
Note that if the positions of the phototransistors are swapped with that of the resistors, the input signs will be reversed.
Code
#include <18f4520.h> #DEVICE ADC=8; #fuses HS,NOLVP,NOWDT,NOPROTECT #use delay(clock=20000000) #include "flex_lcd.c" //#use rs232(baud=19200, xmit=PIN_A0, rcv=PIN_A1) // you can use any pins for software uart... #use rs232(baud=19200, UART1) // hardware uart much better; uses RC6/TX and RC7/RX // characters tranmitted faster than the pic eats them will cause UART to hang. int8 R; int8 G; int8 B; int8 redchan; int8 bluechan; int8 greenchan; void main(){ setup_adc_ports(AN0_TO_AN3); // Enable analog inputs; choices run from just AN0, up to AN0_TO_AN11 setup_adc(ADC_CLOCK_INTERNAL); // the range selected has to start with AN0 lcd_init(); // Always call this first. lcd_putc("\f(R,G,B)\n"); while (TRUE) { set_adc_channel(1); // there's only one ADC so select which input to connect to it; here pin AN0 delay_us(10); // wait 10uS for ADC to settle to a newly selected input redchan = read_adc(); // now you can read ADC as frequently as you like set_adc_channel(2); // there's only one ADC so select which input to connect to it; here pin AN0 delay_us(10); // wait 10uS for ADC to settle to a newly selected input greenchan = read_adc(); // now you can read ADC as frequently as you like set_adc_channel(3); // there's only one ADC so select which input to connect to it; here pin AN0 delay_us(10); // wait 10uS for ADC to settle to a newly selected input bluechan = read_adc(); // now you can read ADC as frequently as you like R = 255 - redchan ; G = 255 - greenchan; B = 255 - bluechan; printf(lcd_putc,"(%u, %u, %u) \n", R,G,B); delay_ms(500); } }