quarta-feira, dezembro 31, 2008

Controlando um LED com um MSP430 - Parte II

Nesta parte vamos ver o software do nosso projeto.

Como ambiente de desenvolvimento vou usar o IAR Embedded Workbench Kickstart, que é fornecido junto com o programador EZ430-F2013 e pode também ser baixado gratuitamente do site da Texas. Esta versão grátis é limitada para gerar programas de até 4KBytes; como o modelo que estamos usando possui somente 2K de Flash, é mais que suficiente.

Existem, é claro, várias maneiras de estruturar o nossa programa. Optei por programar o timer para gerar interrupções a cada 50 milisegundos e colocar toda a lógica dentro do tratamento desta interrupção. Desta forma, na maior parte do tempo o processador estará parado em modo de economia de energia.

Para controlar o botão usei uma variável de tipo byte, onde 1 bit indica o estado do botão na leitura anterior e outro o estado após o debounce. Este segundo bit só é alterado após duas leituras consecutivas iguais.

Uma segunda variável do tipo byte armazena o estado do LED: apagado, aceso continuamente ou piscando. A cada pressionamento do botão o estado muda ciclicamente.

Sem mais delongas, eis o código em C:
#include 

typedef unsigned char byte;

// Bits correspondentes aos pinos de E/S
#define BOTAO 0x01
#define LED 0x40

// Valor para contar 50ms c/ clock de 12KHz
#define TEMPO_50MS 600 // 50ms * 12KHz

// Controle do LED
static enum { APAGADO, ACESO, PISCANDO } ModoLed;

// Controles do estado do botão
#define BOTAO_ANTERIOR 0x01 // este bit indica o estado anterior
#define BOTAO_APERTADO 0x02 // este bit tem o valor c/ "debounce"
static byte ModoBotao;

void main (void)
{
// Desliga Watchdog
WDTCTL = WDTPW + WDTSSEL + WDTHOLD;

// Altera a configuração de clock para ativar o VLOCLK
BCSCTL3 |= LFXT1S1;

// Programa entradas e saídas
P1SEL = 0; // Todos os pinos como I/O
P1DIR = 0xFF & ~BOTAO; // Somente o botão é entrada
P1REN = BOTAO; // Usar resistor no botão
P1OUT = BOTAO; // Resistor é pullup

P2SEL = 0; // Todos os pinos como I/O
P2DIR = 0xFF; // Todos os pinos como saída
P2OUT = 0; // Todos as saídas em zero

// Inicia os nossos controles
ModoBotao = 0;
ModoLed = APAGADO;

// Alimentação já deve estar estável, vamos ligar o DCO
BCSCTL1 = CALBC1_12MHZ;
DCOCTL = CALDCO_12MHZ;

// Programar a interrupção de tempo real p/ cada 50ms
TACCR0 = TEMPO_50MS;
TACTL = TASSEL_1 + MC_1 + TAIE; // ACLK, up mode, interrupt

// O nosso programa principal vai ficar dormindo,
// todo o tratamento será feito na interrupção
_BIS_SR(LPM3_bits + GIE); // Dorme tratando interrupção

// Nuca vai chegar aqui
while (1)
;
}

// Tratamento da interrupção do Timer A
#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A_TO(void)
{
switch (TAIV)
{
case 10: // overflow

// Trata o LED
if (ModoLed == PISCANDO)
P2OUT ^= LED;

// Trata o botão
if ((P1IN & BOTAO) == 0)
{
// Botao está apertado
if (ModoBotao & BOTAO_ANTERIOR)
{
if ((ModoBotao & BOTAO_APERTADO) == 0)
{
// Acabamos de detectar o aperto
ModoBotao |= BOTAO_APERTADO;
switch (ModoLed)
{
case APAGADO:
ModoLed = ACESO;
P2OUT |= LED;
break;
case ACESO:
ModoLed = PISCANDO;
break;
case PISCANDO:
ModoLed = APAGADO;
P2OUT &= ~LED;
break;
}
}
}
else
{
// Vamos aguardar a confirmação
ModoBotao |= BOTAO_ANTERIOR;
}
}
else
{
if (ModoBotao & BOTAO_ANTERIOR)
ModoBotao &= ~BOTAO_ANTERIOR; // aguarda confirmar
else
ModoBotao &= ~BOTAO_APERTADO; // confirmado
}
break;

case 2: // CCR1, não utilizado
break;
}
}

Alguns comentários sobre o código:
  • O include msp430.h define as constantes relativas ao microcontrolador. O modelo específico de microcontrolador é definido nas opções do projeto.
  • O MSP430 inicia a execução com o watchdog ativo, portanto é necessário desativá-lo ou desarmá-lo periodicamente.
  • Para o timer estou utilizando o VCLOCK, que é um clock interno lento (12KHz) e de baixo consumo. É somente este clock que vai estar ativo enquanto o processador aguarda uma interrupção. O VCLOCK não é muito preciso; para ter um clock preciso de baixo consumo é necessário colocar um cristal externo de 32KHz.
  • Quando o processador está rodando é usado o DCO, que é um clock interno rápido (12MHz). Como parte do processo de fabricação são gravados na Flash parâmetros de calibração do DCO, desta forma esta clock é razoavelmente preciso.
  • O MSP430 possui uma grande versatilidade nos pinos de entrada e saída digital. A recomendação da Texas é que os pinos não usados sejam programados como saída.
  • O timer no MSP420F2011 é também muito flexível o que, neste caso, pode deixar a programação um pouco complicada. No caso é usado o up mode, no qual o timer conta de 0 até o valor em TACCR0. Ao atingir esta valor, o contador volta a zero e uma interrupção é gerada.
  • A função _BIS_SR permite ligar bits do registrador de status. No caso são ligados os bits que colocam o processador para dormir com economia de energia (Low Power Mode 3) e o bit que permite interrupções. O resultado é que o processador fica parado na instrução seguinte, tratando interrupções. Quando uma interrupção ocorre, o registrador de status é salvo na pilha e o processador entra no modo normal de execução (LPM0). Ao final da interrupção o registrador de status é restaurado da pilha. Para o processamento continuar no programa principal uma interrupção precisaria alterar o registrador de status na pilha antes de retornar, o que não é feito neste programa.
  • A pragma_vetor define que a rotina seguinte é uma rotina de tratamento de interrupção. O compilador cuida de colocar o endereço da rotina no vetor de interrupções e de colocar os preâmbulos e postâmbulos adequados no código.
  • A interrupção do timer pode ser gerada por vários motivos, o registrador TAIV informa qual o motivo. No caso só estamos interessados na interrupção gerada quando o contador dá a volta.
Na próxima parte vamos ver este mesmo código em Assembly; na quarta e última parte veremos como montar o circuito, compilar o código e gravá-lo no microcontrolador.

2 comentários:

Henrique disse...

Daniel , quando eu utilizo o cristal de 32k que vem com a placa do launchpad , o sistema fica muito sensível , não posso conectá-lo a protoboard nem mesmo tocar na malha do gnd ou acionar algo com as portas que não seja os leds do launchpad que o microcontrolador trava a execução , como se o cristal parasse de ressoar ... Você já passou por isso ?

Daniel Quadros disse...

Henrique, não usei ainda o cristal de 32K na launchpad. Normalmente é recomendado aterrar a carcaça do cristal.