Postagem em destaque

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte I

Este post é o primeiro de uma série de seis que escrevi tratando de controle de potência e PID (controle proporcional, integral e derivativo...

terça-feira, 7 de agosto de 2012

Arduino: Parla!

Tempos atrás, em abril especificamente, comprei uma placa de som chamada GinSing, da http://www.ginsingsound.com/. Quando eu já havia me esquecido da dita, eis que a Receita Federal me comunica que eu poderia retirá-la nos Correios, pagando para isso um imposto equivalente ao custo da plaquinha...

Fui lá na semana passada e retirei-a. No fim de semana comecei a utilizá-la. Ela é construída em torno de um CI chamado BabbleBot, que é um sintetizador de sons muito poderoso, com seis canais e uma gama de efeitos invejável.

Eu resolvi "investir" nessa plaquinha porque qdo eu era adolescente eu fiz algumas montagens de circuitos para efeitos especiais em som de danceterias, houve um tempo em que eu alugava os troços que eu montava e também um "jogo de luzes" para festas. Não que eu tenha a intenção de me tornar um DJ tardio, mas acho que a plaquinha será útil para games, robots e outras brincadeiras.

Resolvi começar a testá-la pelo que mais chama a atenção: a capacidade de síntese de voz. Criei então um modelo relógio digital para deficientes visuais, que poderiam, ao pressionar um botão, ouvir as horas faladas pelo relógio.

Pois taí o bicho funcionando:


A plaquinha funciona em quatro modos: efeitos sonoros, sintetizador de voz, modelagem de instrumentos e modulador sonoro.

No modo sintetizador de voz trabalha com Allophones, que são fonemas codificados, quer dizer, um tipo de alfabeto fonético. Com ele a gente consegue compor frases fonéticas. Os fonemas são mais ou menos específicos da linguagem, no caso, inglês,  mas dá para falar em português, ainda que com um sotaque americano. Fiz alguns testes. Como esse foi o primeiro uso, fiz em inglês. Mas já testei em português também, fica bem inteligível, em outros posts vou usar a nossa inculta e bela.

A plaquinha tem recursos de pausas, entonações, consegue até mesmo cantar. Mas essas features ficam para outros posts.

Abaixo, como é regra nesse blog, o código fonte comentado.

#include "LiquidCrystal.h"
// essa é a classe que interfaceia com a plaquinha
GinSing       GS;                                  

// abaixo os pinos de comunicação. Uma boa característica dessa placa é que
// tem jumpers para configurar os pinos, com duas alternativas para cada,
// o que adiciona muita flexibilidade na combinação com outros shields.

#define rcvPin  4                           
#define sndPin  3                           
#define ovfPin  2                                  


 // botão para acionar a voz
#define sayTimePin 10

// como não tenho um chip de timer, o relógio é iniciado com essa gambi abaixo
long __hour = 21;long __minutes = 12;
long initialSecs = __hour * 3600 + (__minutes * 60);
long _now;
long _hour;
long _minutes;
long _secs;

// esse ponteiro vai para a estrutura de voz, qdo a classe for criada
GinSingVoice * voice = 0x0;                         

// inicializa o display
LiquidCrystal lcd(12, 11, 9, 8, 7, 6); 

// define os sons dos números com os fonemas
GSAllophone one[] = {_W,_U,_NE,_ENDPHRASE};
GSAllophone two[] = {_T,_UE,_ENDPHRASE};
GSAllophone three[] = {_THH,_R,_EE,_ENDPHRASE};
GSAllophone four[] = {_F,_OR,_ENDPHRASE};
GSAllophone five[] = {_F,_IE,_V,_ENDPHRASE};
GSAllophone six[] = {_SE,_I,_KE,_SE,_ENDPHRASE};
GSAllophone seven[] = {_SE,_E,_V,_I,_NE,_ENDPHRASE};
GSAllophone eight[] = {_AE,_T,_ENDPHRASE};
GSAllophone nine[] = {_NE,_IE,_NE,_ENDPHRASE};
GSAllophone ten[] = {_T,_E,_NE,_ENDPHRASE};
GSAllophone eleven[] = {_I,_LE,_E,_V,_E,_NE,_ENDPHRASE};
GSAllophone twelve[] = {_T,_W,_E,_LE,_V,_ENDPHRASE};
GSAllophone thirteen[] = {_TH,_ER,_T,_EE,_NE,_ENDPHRASE};
GSAllophone fourteen[] = {_F,_OR,_T,_EE,_NE,_ENDPHRASE};
GSAllophone fifteen[] = {_F,_I,_F,_T,_EE,_NE,_ENDPHRASE};
GSAllophone sixteen[] = {_SE,_I,_KE,_SE,_T,_EE,_NE,_ENDPHRASE};
GSAllophone seventeen[] = {_SE,_E,_V,_I,_NE,_T,_EE,_NE,_ENDPHRASE};
GSAllophone eighteen[] = {_AE,_T,_EE,_NE,_ENDPHRASE};
GSAllophone nineteen[] = {_NE,_IE,_NE,_T,_EE,_NE,_ENDPHRASE};
GSAllophone twenty[] = {_T,_W,_E,_NE,_T,_EE,_ENDPHRASE};
GSAllophone thirty[] = {_TH,_ER,_T,_EE,_ENDPHRASE};
GSAllophone fourty[] = {_F,_OR,_T,_EE,_ENDPHRASE};
GSAllophone fifty[] = {_F,_I,_F,_T,_EE,_ENDPHRASE};
// palavras
GSAllophone hour[] = {_OU,_R,_ENDPHRASE};
GSAllophone minute[] = {_M,_I,_NE,_I,_T,_ENDPHRASE};
GSAllophone second[] = {_SE,_E,_PITCHDN,_KO,_PITCHDN,_U,_NE,_OD,_ENDPHRASE};
GSAllophone hours[] = {_OU,_R,_SE,_SE,_ENDPHRASE};
GSAllophone minutes[] = {_M,_I,_NE,_I,_T,_SE,_SE,_ENDPHRASE};
GSAllophone seconds[] = {_SE,_E,_PITCHDN,_KO,_PITCHDN,_U,_NE,_PITCHDN,_OD,_SE,_SE,_ENDPHRASE};


void setup (){
  Serial.begin
(9600);
  
Serial.println(initialSecs);

// "pega" a interface de voz
  
voice = GS.getVoice();                            

// inicializa o LCD
  
cd.begin(16, 2);
  
lcd.clear();
  
pinMode(sayTimePin,INPUT);
  
GS.begin ( rcvPin, sndPin, ovfPin );             


}

void loop (){
  
// escreve a hora
  
printTime();
  
delay(1000);
  
// se apertou-se o botão, diz a hora
  
if (digitalRead(sayTimePin) == HIGH)
  
{
    sayTime
();
  
}
}


// calcula a hora atual
void calcTime(){
  _now
= initialSecs + (millis()/1000);
  
_hour = _now / 3600;
  
_minutes = (_now / 60) - (_hour * 60);
  
_secs = _now % 3600 - (_minutes * 60);}


// escreve a hora no display
void printTime(){
  calcTime
();
  
lcd.clear();
  
lcd.print(_hour); lcd.print(":"); lcd.print(_minutes); lcd.print(":"); lcd.print(_secs);

}

// diz a hora, considerando inclusive o plural/singular das palavras
void sayTime(){
  voice
->setNote( C_2 );
  
sayTimeNumbers(_hour);
  
if (_hour > 1)
    
say(hours);
  
else
    
say(hour);
  
sayTimeNumbers(_minutes);  
  
if (_minutes > 1)
    
say(minutes);
  
else
    
say(minute);
  
sayTimeNumbers(_secs);  
  
if (_secs > 1)
      
say(seconds);
  
else
    
say(second);

}

void say(GSAllophone phrase[])
{
  
// diz o texto em phrase
  
voice->speak( phrase);
  
// espera o fim da fala
  
delay ( voice->getMillis( phrase ) );   

}

void sayANumber(byte num)
{
  
// diz um determinado número
  
Serial.println(num);
  
switch(num)
  
{
    
case  1say(one); break;
    
case  2: say(two); break;
    
case  3: say(three); break;
    
case  4: say(four); break;
    
case  5: say(five); break;
    
case  6: say(six); break;
    
case  7: say(seven); break;
    
case  8: say(eight); break;
    
case  9: say(nine); break;
    
case 10: say(ten); break;
    
case 11: say(eleven); break;
    
case 12: say(twelve); break;
    
case 13: say(thirteen); break;
    
case 14: say(fourteen); break;
    
case 15: say(fifteen); break;
    
case 16: say(sixteen); break;
    
case 17: say(seventeen); break;
    
case 18: say(eighteen); break;
    
case 19: say(nineteen); break;
    
case 20: say(twenty); break;
    
case 30: say(thirty); break;
    
case 40: say(fourty); break;
    
case 50: say(fifty); break;
  
}
}


// diz os números do tempo
void sayTimeNumbers(byte number){
  
int n=number / 10;
  
if (n > 1)
  
{
    sayANumber
(n * 10);
    
n=number % 10;
    
sayANumber(n);
  
}
  
else
    
sayANumber(number);