Obs.: Reparar que refiz a fixação dos botões. Outra alteração foi o reposicionamento do buzzer para o lado de fora, para ficar mais audível.
A operação é bastante simples. Inicialmente, com o relógio parado, os LEDs na extremidade pulsam bem devagar. Através do botão da esquerda se seleciona o tempo dentre as opções programadas no firmware. O botão da direita inicia a contagem decrescente, com os LEDs nas extremidades pulsando mais rápido. O botão da direita pode ser usado para parar momentaneamente a contagem (apertando de novo retoma) e o botão da esquerda interrompe (voltando à situação inicial). Se a contagem chegar a zero, a "bomba" "explode": o buzzer é acionado e os LEDs azuis no interior piscam rapidamente. Neste ponto é preciso apertar o botão esquerdo para voltar ao estado inicial.
O programa principal do software está organizado como uma máquina de estados. Os estados possíveis são RESET, INICIAL, CONTANDO, PAUSA e EXPLOSAO. A mudança entre os estados (exceto de RESET para INICIAL) é controlada pelos botões (quando a tecla é solta) e o evento da contagem chegar a zero. A atualização do display e o acionamento do buzzer na explosão também são feitos pelo programa principal:
// Programa Principal
int main (void)
{
enum { RESET, INICIAL, CONTANDO, PAUSA, EXPLOSAO } estado;
uint8_t iVal = 0;
// Inicia o hardware
iniciaHw();
// Inicia o software
estado = RESET;
// Permite interrupções
sei ();
// Eterno equanto dure
for (;;)
{
// Maquina de Estados
switch (estado)
{
case RESET:
contador = valCont[iVal];
mostraContador ();
apagaLedMeio ();
acendeLedPonta (100, 200);
estado = INICIAL;
break;
case INICIAL:
if (botaoEsq)
{
while (botaoEsq)
;
click();
if (++iVal == N_VALORES)
iVal = 0;
contador = valCont[iVal];
mostraContador ();
}
if (botaoDir)
{
while (botaoDir)
;
click();
acendeLedPonta (20, 20);
ligaContador (valCont[iVal]);
estado = CONTANDO;
}
break;
case CONTANDO:
if (contAtl)
{
mostraContador();
contAtl = FALSE;
}
if (contZero)
{
mostraContador();
acendeLedMeio (20, 20);
PORTA |= BUZZER;
estado = EXPLOSAO;
break;
}
if (botaoEsq)
{
while (botaoEsq)
;
click();
pausaContador();
estado = RESET;
}
if (botaoDir)
{
while (botaoDir)
;
click();
pausaContador();
apagaLedPonta();
estado = PAUSA;
}
break;
case PAUSA:
if (botaoEsq)
{
while (botaoEsq)
;
click();
estado = RESET;
}
if (botaoDir)
{
while (botaoDir)
;
click();
acendeLedPonta (20, 20);
contOn = TRUE;
estado = CONTANDO;
}
break;
case EXPLOSAO:
if (botaoEsq)
{
while (botaoEsq)
;
click();
PORTA &= ~BUZZER;
estado = RESET;
}
break;
}
}
}
A rotina de interrupção do timer é usada para:- Verificar o estado das teclas e efetuar o "debounce"
- Controlar a piscada dos LEDs
- Decrementar o contador
- Desligar o buzzer no click das teclas.
// Tratamento da interrupção do timer 0
// ocorre a cada 10ms
ISR (TIM0_COMPA_vect)
{
static uint8_t debDir = 0, debEsq = 0;
static uint8_t contSeg = 100;
// Atualiza estado das teclas
if ((PINB & TEC1) == 0)
{
if (botaoDir)
{
debDir = 0;
}
else
{
if (++debDir == DEBOUNCE)
{
botaoDir = TRUE;
debDir = 0;
}
}
}
else
{
if (botaoDir)
{
if (++debDir == DEBOUNCE)
{
botaoDir = FALSE;
debDir = 0;
}
}
else
{
debDir = 0;
}
}
if ((PINB & TEC2) == 0)
{
if (botaoEsq)
{
debEsq = 0;
}
else
{
if (++debEsq == DEBOUNCE)
{
botaoEsq = TRUE;
debEsq = 0;
}
}
}
else
{
if (botaoEsq != 0)
{
if (++debEsq == DEBOUNCE)
{
botaoEsq = 0;
debEsq = 0;
}
}
else
{
debEsq = 0;
}
}
// Trata o contador
if (contOn && (--contSeg == 0))
{
contSeg = 100;
if (contador != 0)
{
contAtl = TRUE;
if (--contador == 0)
contZero = TRUE;
}
}
// Trata os LEDs
if (cntLedPonta != 0)
{
if (--cntLedPonta == 0)
{
if ((PORTA & LED1) != 0)
{
PORTA &= ~(LED1 | LED2);
cntLedPonta = tmpOffPonta;
}
else
{
PORTA |= (LED1 | LED2);
cntLedPonta = tmpOnPonta;
}
}
}
if (cntLedMeio != 0)
{
if (--cntLedMeio == 0)
{
if ((PORTA & LED3) != 0)
{
PORTA &= ~(LED3 | LED4);
cntLedMeio = tmpOffMeio;
}
else
{
PORTA |= (LED3 | LED4);
cntLedMeio = tmpOnMeio;
}
}
}
// Click das teclas
if (cntClick != 0)
{
if (--cntClick == 0)
{
PORTA &= ~BUZZER;
}
}
}
O resto do código (inclusive as rotinas de manipulação do display) podem ser vistas baixando Timer.zip dos arquivos do blog.
O curioso com relação ao software foi que nos primeiros testes nada funcionada direito, o microcontrolador estava muito doido! Depois de muitos testes, descobri que o problema era que quando eu linkava os objetos não estava informando o modelo do microcontrolador. Corrigido isto, funcionou praticamente tudo.
Nenhum comentário:
Postar um comentário