O princípio básico deste software foi fazer algo simples e aproveitar ideias que já usei antes.
Do ponto de vista global o timer possui um estado (andando ou parado) e um valor a apresentar no display. Para facilitar, vamos manter também um flag para indicar que a contagem chegou a zero (alarme). O valor será armazenado em quatro bytes (um por dígito, com valor de 0 a 9).
// Estado do timer static bool bParado = true; static bool bAlarme = false; static char valor[4];O coração de tudo é uma temporização para contagem de tempo e atualização do display. A precisão do cristal do Arduino é mais que suficiente para esta aplicação. Para ficar mais simples, vamos usar uma interrupção de timer a cada 5 milisegundos. A biblioteca Timer1 é perfeita para isto. Além de apresentar o valor atual no display, a rotina de interrupção irá decrementar o valor, piscar os pontos e pulsar o buzzer. Começando pelos pontos, vamos piscá-los a cada 50 interrupções quando o timer estiver andando e mantê-los acesos quando o timer estiver parado:
static uint8_t cntPonto = 50; static uint8_t mskPonto = 0; if (bParado) { mskPonto = 0x80; } else if (--cntPonto == 0) { cntPonto = 50; mskPonto ^= 0x80; }Quando o contador chega a zero (alarme), o buzzer é pulsado junto com os pontoes:
if (bAlarme) { // Pulsar o buzzer junto com o ponto digitalWrite (pinBuzzer, (mskPonto == 0) ? LOW : HIGH); }Se o timer está andando e não atingiu zero, a contagem deve ser decrementada a cada 200 interrupções. O código abaixo faz na raça o tratamento dos quatro dígitos e a detecção de zero.
static uint8_t cntSeg = 200; // Trata contagem do tempo if (--cntSeg == 0) { cntSeg = 200; if (valor[3] > 0) { valor[3]--; } else { valor[3] = 9; if (valor[2] > 0) { valor[2]--; } else { valor[2] = 5; if (valor[1] > 0) { valor[1]--; } else { valor[1] = 9; valor[0]--; } } } bAlarme = (valor[0] | valor[1] | valor[2] | valor[3]) == 0;Completando a rotina de interrupção, temos a apresentação do valor. A cada interrupção um dígito é apresentado. Uma tabela é usada para determinar quais segmentos devem ser ativados para cada número.
// Desenho dos digitos static const uint8_t digito[10] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; static uint8_t iDig = 0; // Mostra o valor atual digitalWrite (pinDigito[iDig], LOW); iDig = (iDig+1) & 3; uint8_t segtos = digito[valor[iDig]] | mskPonto; for (uint8_t iSegto = 0; iSegto < 8; iSegto++) { digitalWrite (pinSegto[iSegto], (segtos & 1) ? LOW : HIGH); segtos = segtos >> 1; } digitalWrite (pinDigito[iDig], HIGH);O programa principal se resume a tratar os botões (que vou chamar de A e B). Com o timer parado, o botão A seleciona a contagem inicial e o botão B inicia (ou retoma) a contagem. Com o timer andando, o botão A interrompe o alarme (se a contagem chegou a zero) e o botão B para a contagem (se ainda não chegou a zero).
// Opções de contagem static char opcoes[][4] = { { 0, 0, 3, 0 }, { 0, 0, 4, 5 }, { 0, 1, 0, 0 }, { 0, 2, 0, 0 }, { 0, 5, 0, 0 }, { 1, 0, 0, 0 }, { 1, 5, 0, 0 }, { 3, 0, 0, 0 } }; #define N_OPC (sizeof(opcoes)/sizeof(opcoes[0])) static uint8_t iOpc = 0; void loop() { if (bParado) { if (digitalRead (pinBotaoA) == 0) { // Passar para o próximo valor iOpc++; if (iOpc == N_OPC) { iOpc = 0; } valor[0] = opcoes[iOpc][0]; valor[1] = opcoes[iOpc][1]; valor[2] = opcoes[iOpc][2]; valor[3] = opcoes[iOpc][3]; // Espera soltar while (digitalRead (pinBotaoA) == 0) { } delay (200); // debounce } if (digitalRead (pinBotaoB) == 0) { // Espera soltar while (digitalRead (pinBotaoA) == 0) { } delay (200); // debounce // Inicar contagem bParado = false; } } else { if (bAlarme) { if (digitalRead (pinBotaoA) == 0) { // Desligar o alarme bAlarme = false; bParado = true; digitalWrite (pinBuzzer, LOW); // Voltar ao valor inicial valor[0] = opcoes[iOpc][0]; valor[1] = opcoes[iOpc][1]; valor[2] = opcoes[iOpc][2]; valor[3] = opcoes[iOpc][3]; // Espera soltar while (digitalRead (pinBotaoA) == 0) { } delay (200); // debounce } } else { if (digitalRead (pinBotaoB) == 0) { // Parar contagem bParado = true; // Espera soltar while (digitalRead (pinBotaoA) == 0) { } delay (200); // debounce } } } }O programa completo está nos arquivos do blog (veja no alto à direita), no arquivo TimerBSides.zip.
Nenhum comentário:
Postar um comentário