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