O
TCS3200D é um sensor estático de cor. Ele possui 16 foto transistores com
filtro Vermelho (R), 16 com filtro Verde (G), 16 com filtro para azul(B)
e 16 sem filtro (branco). Os filtros impedem a passagem das demais cores
permitido que o fototraisistor seja excitado apenas pela luz quista. Através de
dois pinos é possível selecionar qual grupo de fototransistor estará
ativo e consequentemente qual luz será captada pelo sensor. A saída do sinal no
sensor em uma onda quadra com frequência proporciona a intensidade da
cor medida R, G, B, W.
O sensor
Como mencionado na
introdução o sensor é basicamente constituído por quatro grupos de
fototrasistores três desses grupos com filtros.
Os
fototransistores são simplificadamente, transistores cujas bases são
expostas. A incidência de luz sobre a base faz com que o transistor conduza. A variação
dessa luz provoca variação proporcional na corrente que circula no
fototransistor até o limite de saturação. Colocando um filtro que só deixe
passar luz vermelha, por exemplo, apenas a luz vermelha fara conduzir o
fototransistor. Então a corrente que circula no fototransistor será função da
luz vermelha sobre ele.
É isso
que ocorre no sensor, Um grupo de sensores não tem filtro algum o que o torna sensível
a toda luz que incida sobre ele e cada um dos três outros grupos de sensores é
dotado de filtro para uma determinada cor de luz vermelho, verde e azul.
Através
dos pinos S2 e S3 é possível selecionar qual grupo de fototransistores estará
ativo e consequentemente qual luz o sensor estará medindo e mostrando em sua
saída. A tabela ao lado mostra as combinações destes pinos e o respectivos
sensores selecionados.
Outra possibilidade de configuração do sensor
é escalonar a frequência de saída escolhendo através dos pinos S0 e S1. A
tabela ao lado mostra as combinações destes pinos e as respectivas escalas.
Recebendo os dados do sensor
A saída
do sensor e uma onda com frequência diretamente proporcional a intensidade da
cor medida naquele instante. Queremos obter a frequência em ciclos por segundo.
Como se trada de uma onda quadrada com "duty cicle" de 50% (metade do
ciclo em nível alto e metade em nível baixo). Então o programa deve contar
todos os ciclos que ocorrem em um segundo. Ou estimar contando por 1/2 segundo
e multiplicando por 2.
Uma forma
de contar os ciclos para determinar a frequência é usando uma interrupção
externa e um timmer o timer é setado para um segundo, por exemplo, e durante
esse tempo uma variável é incrementada toda vez que a saída do sensor ligada ao
pino de interrupção correspondente sai do nível baixo para o alto.
Para
receber os dados do sensor deve-se selecionar
o filtro através de S1, S2, S3 e S4 conforme a tabela abaixo e receber
e decodificar a informação sobre a cor selecionada através do pino OUT.
O programa para o arduino mostrado abaixo foi
adaptado do programa encontrado neste site. usa a solução timme e interrupção externa.
O programa para processing foi escrito suando como base o exemplo que acompanha
a IDE do arduino "Arduino call response". Na primeira leitura o
programa ajusta o balanço de branco, por isso é importante expor o sensor a
referência de branco ao iniciar o arduino. No vídeo eu coloco uma folha em
branco sobre o sensor ao iniciar o arduino para ter esta referência.
Código para o Arduino:
// este codigo e uma adaptação do coodigo encontrado em:
//http://www.elecfreaks.com/1666.html
//é necessario a biblioteca Timer1 que pode ser baixada aqui:
//http://www.arduino.cc/playground/Code/Timer1
// baixe renomei-a para TimerOne e adcione-a na pasta libriries da ide do arduino
#include <TimerOne.h>
#define OUT 2
#define S2 5
#define S3 6
#define S0 3
#define S1 4
volatile int g_count =0;
int g_flag = 0;
int g_array[3] = {0};
float g_SF[3] = {0};
void setup()
{
// Init TSC230 and setting Frequency.
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(OUT, INPUT);
digitalWrite(S0, LOW); // OUTPUT FREQUENCY SCALING 2%
digitalWrite(S1, HIGH);
Serial.begin(115200);
Timer1.initialize(); // defaulte is 1s
Timer1.attachInterrupt(TSC_Callback);
attachInterrupt(0, TSC_Count, RISING);
delay(4000);
g_SF[0] = 255.0/ g_array[0]; //R Scale factor
g_SF[1] = 255.0/ g_array[1] ; //G Scale factor
g_SF[2] = 255.0/ g_array[2] ; //B Scale factor
estabeleceContato(); // aguarda contato com o processing
}
void loop()
{
g_flag = 0;
for(int i=0; i<3; i++)
{
int val = int(g_array[i] * g_SF[i]);
val = constrain(val, 0, 255);
Serial.write(val);
}
delay(4000);
}
// seta o filtro
void TSC_FilterColor(int Level01, int Level02)
{
if(Level01 != 0)
Level01 = HIGH;
if(Level02 != 0)
Level02 = HIGH;
digitalWrite(S2, Level01);
digitalWrite(S3, Level02);
}
// incrementa g_cont cada vex que a sáida do sensor
// vai do nivel baixo ao alto
void TSC_Count()// finção chamada pela interrupção
{
g_count ++ ; // incrementa g_cont
}
void TSC_Callback()
{
switch(g_flag)
{
case 0:
TSC_WB(LOW, LOW); //Red
break;
case 1:
g_array[0] = g_count;
TSC_WB(HIGH, HIGH); //Green
break;
case 2:
g_array[1] = g_count;
TSC_WB(LOW, HIGH); //Blue
break;
case 3:
g_array[2] = g_count;
TSC_WB(HIGH, LOW); //Clear(no filter)
break;
default:
g_count = 0;
break;
}
}
void TSC_WB(int Level0, int Level1) //balanceamento de branco
{
g_count = 0;
g_flag ++;
TSC_FilterColor(Level0, Level1);
Timer1.setPeriod(1000000); // define periodo de 1 segundo
}
void estabeleceContato() {
while (Serial.available() <= 0) {
Serial.write('A'); // envia A ate estabelecer contato
delay(300);
}
}
Código para o Processing:
// Adaptado do exemplo SerialCallResponse que acompanha a IDE do Arduino
import processing.serial.*;
int comando =0;
int y_01 = 55;
Serial myPort; // porta serial
int[] serialInArray = new int[3]; // vetor para armazenar o valores recebidos
int serialCount = 0; // usado para contar o numero de bytes recebidos
int[] buffer = new int[3];
boolean firstContact = false; // Whether we've heard from the microcontroller
void setup() {
// imprime a lista de portas seriais
println(Serial.list());
String portName = Serial.list()[0];
// substituir COM9 pela porta onde esta o Arduino
myPort = new Serial(this, "COM9", 115200);
size(800, 600); //janela, largura, altura
smooth();
}
void draw() {
background(buffer[0],buffer[1],buffer[2]);
}
void serialEvent(Serial myPort) {
// le os bytes da porta serial
int inByte = myPort.read();
// se receber o primeiro byte e for 'A'
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // Limpa o buffer da porta serial
firstContact = true; // o primeiro contato ja ocorreu
myPort.write('A'); // envia "A" para que o arduino
// reconheça o primeiro contato
}
}
else {
// se não for o primeiro byte adiciona-o ao vetor:
serialInArray[serialCount] = inByte;
serialCount++;
// quando receber os 12 bytes armazena-os em buffer[i]
if (serialCount > 2) {
for(int i =0; i<3; i++)
{
buffer[i] = serialInArray[i];
}
// envia comandos caso existam
myPort.write(comando);
// Reset serialCount:
serialCount = 0;
}
}
}