Como visto na parte 1, optei pelo microcontrolador MSP430G2231. O desenvolvimento foi feito com o IAR Kickstart. Para gravar o software na Flash do MSP430 usei a Launchpad.
O programa principal consiste em parar o watchdog (que é ativado automaticamente após um reset), programar as entradas e saídas digitais (pinos não usados são programados como saída para reduzir o consumo), ativar o clock auxiliar (ACLK) de 32KHz dividido por 8 (o que inclui selecionar os capacitores apropriados), programar o Timer A (mais sobre isto adiante) e colocar o microcontrolador no modo LPM3
#define POT BIT0
#define LED BIT2
#define DISPARO BIT3
#define NAO_USADO (BIT4 | BIT5 | BIT6 | BIT7)
#define POT_ADC INCH_1;
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
// inicia led
P1DIR = LED | POT | DISPARO | NAO_USADO;
P1OUT = 0;
// Ativa o clock de 32KHz
BCSCTL1 |= DIVA_3; // ACLK /8
BCSCTL3 |= XCAP_3; // 12.5pF
// init timer A
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 512;
TACTL = TASSEL_1 + MC_1; // ACLK upmode
_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt
}Para economizar energia, o microcontrolador ficará a maior parte do tempo "dormindo" no modo LPM3, apenas o clock auxiliar e o timer estarão ativos. É isto que faz a instrução _BIS_SR(LPM3_bits + GIE) no final do programa principal. Ao ocorrer uma interrupção o processador entrará no modo ativo, com todos os clocks ativos. Ao final da interrupção, salvo procedimentos especiais, o microcontrolador restaurará o modo anterior (LPM3).O timer A tem por entrada um clock de 32768/8 Hz. Programado para o upmode com uma contagem máxima de 512, ele gera uma interrupção a cada 1/8 de segundo. A rotina de interrupção é uma máquina de estados:
#define T_LED 2 // tempo de LED aceso em 1/8 seg
#define T_PAUSA 8 // tempo entre apagar o LED e disparar a foto em 1/8 seg
#define T_DISPARO 2 // tempo que mantem ativo o disparo em 1/8 seg
static volatile unsigned int pot;
// Timer A interrupt service routine
// Ocorre a cada 32768/8/512 = 1/8 segundo
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer( void )
{
static byte estado = 0;
static unsigned int cnt = 1;
static unsigned int tempo = 10;
static unsigned int pot_ant = 0;
if (estado == 0)
{
if (--cnt == 0)
{
// Inicio de um novo ciclo
// solta o disparo
P1OUT &= ~DISPARO;
// ler o potenciômetro
P1OUT |= POT; // alimenta o potenciômetro
ADC10CTL0 &= ~ENC;
ADC10CTL0 = ADC10SHT_3 + ADC10ON + ADC10IE;
ADC10CTL1 = ADC10SSEL_3 + POT_ADC;
ADC10CTL0 |= ENC + ADC10SC;
estado = 1;
}
}
else if (estado == 1)
{
// Leu o potenciômetro, determina o novo tempo
int dif = (pot > pot_ant) ? (pot - pot_ant) : (pot_ant - pot);
if (dif > 16)
{
// mudou significativamente a posição
unsigned int aux = pot >> 4;
if (aux < 10)
tempo = 10 + 2*aux; // 10 a 28seg, passo = 2 seg
else if (aux < 20)
tempo = 30 + 10*(aux-10); // 30 a 120 seg, passo = 10 seg
else if (aux < 35)
tempo = 150 + 30*(aux-20); // 150 a 570 seg, passo = 30 seg
else if (aux < 55)
tempo = 600 + 60*(aux-35); // 10 a 29 min, passo = 1 min
else
tempo = 1800 + 10*(aux-55); // 30 a 75 min, passo = 5 min
pot_ant = pot;
}
cnt = tempo << 3; // converte p/ oitavos de segundo
cnt -= T_LED + T_PAUSA + T_DISPARO;
estado = 2;
}
else if (estado == 2)
{
// Aguardando tempo para acender o LED
if (--cnt == 0)
{
// acende o led
P1OUT |= LED;
cnt = T_LED;
estado = 3;
}
}
else if (estado == 3)
{
// Aguardando tempo para apagar o LED
if (--cnt == 0)
{
// apaga o LED
P1OUT &= ~LED;
cnt = T_PAUSA;
estado = 4;
}
}
else if (estado == 4)
{
// Aguardando tempo para disparar foto
if (--cnt == 0)
{
// dispara a foto
P1OUT |= DISPARO;
cnt = T_DISPARO;
estado = 0;
}
}
}A operação é dividida em cinco estados:- 0: aguardando o inicio de um novo ciclo
- 1: aguardando a leitura da posição do potenciômetro
- 2: aguardando para acender o LED
- 3: aguardando para apagar o LED
- 4: aguardando para disparar a foto
Após alguns testes, decidi que o LED ficaria aceso por 2/8 de segundo, o disparo seria comandado 1 segundo após apagar o LED e que o sinal de disparo ficaria ativo por 2/8 de segundo. Este último parâmetro é importante, já que o acoplador ótico é quem mais consome energia. O valor adotado pressupõe que não será usado o foco automático.
O aguardo da leitura do potenciômetro é feito com o microcontrolador dormindo. A interrupção do ADC (conversor analógico digital) salva o valor lido e retira a alimentação do potenciômetro.
// Interrupção de fim da conversão
#pragma vector=ADC10_VECTOR
__interrupt void Adc_isr( void )
{
pot = ADC10MEM;
P1OUT &= ~POT;
}A interpretação da leitura do potenciômetro toma alguns cuidados. O ADC é programado para usar o seu clock interno e trabalhar com a escala de 0 a Vcc. O valor lido é entre 0 a 1023 (10 bits), o código ignora pequenas variações na leitura. O valor lido é dividido por 16, ficando entre 0 e 63. Organizei os tempos em faixas contínuas mas com inclinação crescente, para permitir escolher facilmente tempos entre 10 segundos e 75 minutos:- 10 a 28 segundos, passo de 2 segundos
- 30 a 120 segundos, passo de 10 segundos
- 150 a 570 segundos, passo de 30 segundos
- 10 a 29 minutos, passo de 1 minuto
- 30 a 75 minutos, passo de 5 minutos
Nenhum comentário:
Postar um comentário