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;
- }
- }
- }
- 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