quinta-feira, fevereiro 08, 2018

Franzininho: Caixa de Música

Inaugurando uma série de posts com pequenos projetos usando o Franzininho, vamos ver aqui como fazer uma caixa de música com ele.


O objetivo deste projeto é tocar uma música quando a caixa for aberta. A alimentação do circuito vai ser feita com um "power bank" (bateria com um circuito para gerar 5V, usada para carga de emergência em celulares). Três pilhas comuns (4.5V) também podem ser usadas.

Sensor da Abertura da Caixa

Uma série de maneiras podem ser usadas, entre as quais:
  • Sensores digitais:
    • Botão que deixa de ser pressionado quando a caixa abre
    • Um reed switch (chave acionada por um imã)
    • Um sensor efeito hall digital + um imã
  • Sensores analógicos
    • Um sensor efeito hall analógico + um imã
    • Um LDR (resistor variável com a luz)

Eu optei aqui por um LDR, ligado entre o pino A1 e o Vcc. Um resistor de 1K entre o pino A1 e terra completa o divisor. Quando o LDR estiver exposto à luz (caixa aberta) sua resistência diminui e o valor lido será alto. Ao fechar a caixa, a resistência do LDR aumenta, a tensão no pino diminui e o valor lido será baixo.

Para contornar pequenas variações, são somadas dez leituras e são usados dois valores diferentes para detectar abertura e fechamento (histerese). O LED do Franzininho é aceso quando a caixa está aberta.

O código fica assim:
// Pinos utilizados
const int pinLED = 1;
const int pinLDR = A1;
const int pinSOM = 0;

// Variaveis globais
int refLDR; // valor correspondente a caixa aberta

void setup() {

  // Iniciação do LED
  pinMode (pinLED, OUTPUT);
  digitalWrite (pinLED, HIGH);  // acende

  // Iniciação do SOM
  pinMode (pinSOM, OUTPUT);
  digitalWrite (pinSOM, LOW);

  // Iniciação do LDR
  // Assume que caixa está aberta
  analogReference (DEFAULT);
  refLDR = 0;
  for (int i = 0; i < 10; i++) {
    refLDR += analogRead(pinLDR);
    delay (50);
  }
}

void loop() {
  int leituraLDR;
  
  // Espera a caixa ser fechada
  do {
    leituraLDR = 0;
    for (int i = 0; i < 10; i++) {
      leituraLDR += analogRead(pinLDR);
      delay (50);
    }
  } while (leituraLDR/10 > refLDR/12);
  digitalWrite (pinLED, LOW);  // apaga

  // Espera a caixa ser fechada
  do {
    leituraLDR = 0;
    for (int i = 0; i < 10; i++) {
      leituraLDR += analogRead(pinLDR);
      delay (50);
    }
  } while (leituraLDR/10 < refLDR/11);
  digitalWrite (pinLED, HIGH);  // acende

  tocaMusica();
}
Geração da Música

Em um Arduino normal usaríamos a função tone para gerar as notas. Entretanto, a função tone da biblioteca padrão não suporta o Franzininho. A solução adotada foi gerar os tons manualmente, ligando e desligando uma saída digital. Utilizando o código de um exemplo da Adafruit:
// Musica a ser tocada
#define MI5   659
#define RE5s  622
#define DO5   523
#define SI4   494
#define LA4   440
#define SOL4s 415
#define MI4   330
#define DO4   262

#define PAUSA 20000
#define D(x) (10000+x)
#define TEMPO 250

int musica[] = {
  MI5, RE5s, MI5, RE5s, MI5, SI4, RE5s, DO5, D(LA4), PAUSA,
  DO4, MI4, LA4, D(SI4), PAUSA,
  MI4, SOL4s, SI4, DO5, PAUSA,
  MI4, MI5, RE5s, MI5, RE5s, MI5, SI4, RE5s, DO5, D(LA4), PAUSA,
  DO4, MI4, LA4, D(SI4), PAUSA,
  MI4, DO5, SI4, D(LA4),
  0
};

// Toca as notas da música
void tocaMusica() {
  int i = 0;
  int f, d;
  while (musica[i] != 0) {
    f = musica[i];
    d = TEMPO;
    if (f == PAUSA) {
      delay (TEMPO);
    } else {
      if (f > 10000) {
        f -= 10000;
        d = 2*TEMPO;
      }
      beep (pinSOM, f, d);
    }
    delay(10);
    i++;
  }
}

// Rotina para gerar tons "na raça"
// Fonte: https://learn.adafruit.com/trinket-gemma-mini-theramin-music-maker/arduino-code
//        http://web.media.mit.edu/~leah/LilyPad/07_sound_code.html
void beep (unsigned char speakerPin, int frequencyInHertz, long timeInMilliseconds)
{ 
  int  x;
  long delayAmount = (long)(1000000 / frequencyInHertz);
  long loopTime = (long)((timeInMilliseconds * 1000) / (delayAmount * 2));
  for (x = 0; x < loopTime; x++) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(delayAmount);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(delayAmount);
  }
}
Podemos também gerar os tons programando manualmente o hardware de PWM, porém temos aqui uma limitação do ATtiny. Ele possui somente dois timer de 8 bits. O timer 0 é usado pelo runtime do Arduino para contagem de tempo. Podemos usar o timer 1, porém os 8 bits não fornecem uma resolução muito boa para gerar as notas. O resultado é que esta solução irá desafinar um pouco. Do ponto de vista de circuito, a saída digital do Franzininho  é ligada a um transistor, para aumentar a corrente no alto falante. Um resistor de 150R em série com o alto falante evita que ele (e os nossos ouvidos) sofra muito. O transistor S8050 pode ser substituído por praticamente qualquer transistor NPN; O circuito completo fica:

O vídeo abaixo mostra o resultado.


Nenhum comentário: