Este projecto consiste num 'restauro' de um relógio de cuco adquirido na Alemanha, a parte electrónica avariou e deixou de funcionar. Desta forma houve a necessidade de o arranjar e foram utilizados meios diferentes daqueles que trazia inicialmente.
O controlador principal parece ter avariado, o motor e a parte electrónica de controle do pêndulo foram aproveitados.
Para o pêndulo:
A ideia foi assim controlar o sistema com um Attiny84 (o Attiny85 não tinha tantos pinos) e utilizar um módulo de audio MP3 WTV020-SD-16P com ficheiros de música num cartão miniSD.
A escolha do Attiny foi feita com base na seguinte tabela e respectivas necessidades para este projecto:
Na imagem seguinte podemos verificar os pinos do Attiny84:
Verificamos que:
PCINT = Pin Interrupt
Por exemplo o pino 11 é o Pino Digital 2 (PA2)
Para programar o Attiny foi usado um Arduino Uno, neste caso temos de colocar um condensador de 10uF entre o pino Aref e o Ground:
As ligações entre o Arduino e o Attiny são muito simples, verificado a imagem acima, dos pinos do Attiny, ligamos desta forma:
Temos disponíveis os seguintes comandos que podemos usar no Attiny:
pinMode()
digitalWrite()
digitalRead()
analogRead()
analogWrite()
shiftOut()
pulseIn()
millis()
micros()
delay()
delayMicroseconds()
Para conseguirmos programar o Attiny temos de colocar na pasta "Hardware" do IDE do Arduino a 'board' presente no ficheiro em anexo "attiny-master_outro" (...)\arduino-1.0.6\hardware\attiny).
Existe também anexo o ficheiro "attiny45_85" no caso de se utilizar o Attiny85.
Depois basta colocar o Arduino em modo ISP:
Escolher a board:
e fazer upload, como teste podemos usar o simples 'Blink' para acender e apagar um Led:
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
This example code is in the public domain.
*/
int led = 2; //Será no Pino PA2 (11)
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
O próximo passo é colocar o Attiny a dormir para pouparmos bateria e fazê-lo acordar apenas quando o ponteiro dos minutos do relógio passar pelas 12h. Teste usado para ativar o modo sleep no Attiny84:
#include <avr/sleep.h>
#include <avr/interrupt.h>
const int switchPin = 3; //PB3
const int statusLED = 2; //PB2
void setup() {
pinMode(switchPin, INPUT);
digitalWrite(switchPin, HIGH);
pinMode(statusLED, OUTPUT);
// Flash quick sequence so we know setup has started
for (int k = 0; k < 10; k = k + 1) {
if (k % 2 == 0) {
digitalWrite(statusLED, HIGH);
}
else {
digitalWrite(statusLED, LOW);
}
delay(250);
} // for
} // setup
void sleep() {
GIMSK |= _BV(PCIE0); // Enable Pin Change Interrupts
PCMSK0 |= _BV(PCINT3); // Use PA3 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
cli(); // Disable interrupts
PCMSK0 &= ~_BV(PCINT3); // Turn off PA3 as interrupt pin
sleep_disable(); // Clear SE bit
ADCSRA |= _BV(ADEN); // ADC on
sei(); // Enable interrupts
} // sleep
ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
}
void loop() {
sleep();
digitalWrite(statusLED, HIGH);
delay(1000);
digitalWrite(statusLED, LOW);
}
A partir de agora já temos o Attiny pronto a receber novo código usando sempre o modo sleep acima. Temos apenas de colocar o Pin Interrupt pretendido, por exemplo neste caso foi usado o PCMSK0, de acordo com a datasheet do Attiny84 temos:
PCMSK0 = PCINT(0), PCINT(1), PCINT(2), PCINT(3), PCINT(4), PCINT(5), PCINT(6), PCINT(7)
PCMSK1 = PCINT(8), PCINT(9), PCINT(10), PCINT(11)
Como pretendemos usar o pino PA3 como interrupt no nosso projecto, escolhemos assim PCMSK0 |= _BV(PCINT3);
A função GIMSK |= _BV(PCIE0); ativa a opção change interrupt. PCIE0 => Change Interrupt Enable.
("You enable the ISR in GIMSK (PCIE0 or PCIE1 depending on which bank you want), and then enable the individual pin in either PIMSK0 or PIMSK1. Only the pins you enable in the PIMSKx registers will trigger the interrupt.") Explicação abreviada:
There are two pcint interrupts:
PCMSK0 - for group of pins PCINT7 to PCINT0.
PCMSK1 - for group of pins PCINT11 to PCINT8.
These are enabled with bits GIMSK.PCIE0 and GIMSK.PCIE1.
For each interrupt individual pin(s) are enabled in mask-registers PCMSK0, PCMSK1.
If more than one pin is enabled in a group, it must be tested in ISR which one caused the interrupt.
If you need 2 interrupts, you can use pins from different groups.
For example PCINT0 (PA0) and PCINT10 (PB2).
Then you need not test for the interrupt source pin.
ISR(PCINT0_vect) // porta.0
{}
ISR(PCINT1_vect) // portb.2
{}
int main()
{
GIMSK = (1<<PCIE0)|(1<<PCIE1); // enable both interrupts
PCMSK0 = (1<<PCINT0); // enable PCINT0
PCMSK1 = (1<<PCINT10); // enable PCINT10
...
Agora vamos testar o módulo MP3 usando a biblioteca "Wtv020sd16p". As ligações para teste foram feitas ao Arduino da seguinte forma:
ver info.
Inicialmente foi usado um amplificador LM386 (ligado ao pino 2 do módulo MP3 e com um condensador 0.1uF (104)), mas para reduzir consumos foi retirado.
Pequeno teste que escolhe aleatoriamente 1 de 3 músicas presentes no cartão miniSD:
/*
Example: Control a WTV020-SD-16P module to play voices from an Arduino board.
Created by Diego J. Arevalo, August 6th, 2012.
Released into the public domain.
*/
#include <Wtv020sd16p.h>
int resetPin = 2; // The pin number of the reset pin.
int clockPin = 3; // The pin number of the clock pin.
int dataPin = 4; // The pin number of the data pin.
int busyPin = 5; // The pin number of the busy pin.
Wtv020sd16p wtv020sd16p(resetPin,clockPin,dataPin,busyPin);
unsigned long interval = 16000;
unsigned long currentMillis;
long previousMillis = 0;
int var=1;
long randNumber;
void setup() {
randomSeed(analogRead(0));
//Initializes the module.
wtv020sd16p.reset();
Serial.begin(9600);
delay(2000);
}
void loop() {
if (var==1) {
var=0;
randNumber = random(4);
Serial.println(randNumber);
wtv020sd16p.asyncPlayVoice(randNumber);
}
if (var==2) {
previousMillis = currentMillis;
interval=22000; //DURACAO DA MUSICA 5
var=10;
Serial.println("Teste MUSICA 5");
wtv020sd16p.asyncPlayVoice(5);
}
currentMillis = millis();
if (currentMillis - previousMillis > interval) { //14seg
if (var==0)var=2;
if (var==10){
var=3;
Serial.println("GO TO SLEEP");
}
}
}
As músicas têm de estar em formado "ad4" e numeradas no formato "0000". Para converter ficheiros .mp3 em .ad4 podemos usar o programa USBRecorder1.3
Para controlar o motor DC em ambos os sentidos, foi criada uma Ponte-H mediante o seguinte esquema:
Foram usados transístores para ligar\desligar o módulo MP3 (2N3904 Ic=200mA, inicialmente seria também para controlar board LM386) e a bobina que faz movimentar o cuco (BC548 Ic=100mA).
Consumos medidos:
Motor: ~50mA
Bobina: ~68mA @ 3.3v
Módulo MP3: ~30mA
Existem 2 jumpers que permitem, quando retirados, o upload de novo código sem ser necessário remover o Attiny (basta ligar Vcc, Gnd, Reset, MOSI, MISO, SCK):
Desligar ligação do pino de Reset do Attiny84 (pino 4) à resistência pull-up 10k (colocada para que o pino não fique a flutuar, quando está em funcionamento normal)
Desligar ligação do pino MOSI do Attiny84 (pino 7) ao transistor que liga\desliga módulo MP3
Notas:
Foi colocada uma resistência pull-up do pino interrupt de 560R (para combater interferências e garantir que apenas se ativa quando necessário = LOW)
Antes de colocar o Attiny em modo sleep temos de colocar os pinos como Inputs para não gerar consumos:
pinMode(resetPin, INPUT);
pinMode(clockPin, INPUT);
pinMode(dataPin, INPUT);
pinMode(Mp3Transistor, INPUT);
Foi adaptada a placa de botões, um botão do tipo Slide e outro tipo push. O objectivo é a configuração do sistema e ligar\desligar a música:
Nota: Foi usada uma resistência pull-down de 10M no botão Slide, quanto mais baixo o valor maior é o consumo.
LOW = MUSIC ON
HIGH= MUSIC OFF
Alguma informação sobre ligações na placa principal:
Consumos finais:
Botão Slide\Push:
OFF: 00.3uA
ON: 0.002uA
Pêndulo: 0.56mA
Attiny Sleep: 53uA
Total: ~0.65mA
Bateria: 3x1.2v Pilhas Ikea recarregáveis = ~3.85v
Resultado final: