Vamos dar uma olhada rápida no software que eu fiz para a palestra/oficina de montagem de timers.
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).
-
- static bool bParado = true;
- static bool bAlarme = false;
- static char valor[4];
// 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;
- }
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) {
-
- digitalWrite (pinBuzzer, (mskPonto == 0) ? LOW : HIGH);
- }
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;
-
-
- 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;
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.
-
- static const uint8_t digito[10] = {
- 0x3F, 0x06, 0x5B, 0x4F, 0x66,
- 0x6D, 0x7D, 0x07, 0x7F, 0x6F
- };
-
- static uint8_t iDig = 0;
-
-
- 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);
// 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).
-
- 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) {
-
- 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];
-
-
- while (digitalRead (pinBotaoA) == 0) {
- }
- delay (200);
- }
- if (digitalRead (pinBotaoB) == 0) {
-
- while (digitalRead (pinBotaoA) == 0) {
- }
- delay (200);
-
- bParado = false;
- }
- } else {
- if (bAlarme) {
- if (digitalRead (pinBotaoA) == 0) {
-
- bAlarme = false;
- bParado = true;
- digitalWrite (pinBuzzer, LOW);
-
-
- valor[0] = opcoes[iOpc][0];
- valor[1] = opcoes[iOpc][1];
- valor[2] = opcoes[iOpc][2];
- valor[3] = opcoes[iOpc][3];
-
-
- while (digitalRead (pinBotaoA) == 0) {
- }
- delay (200);
- }
- } else {
- if (digitalRead (pinBotaoB) == 0) {
-
- bParado = true;
-
- while (digitalRead (pinBotaoA) == 0) {
- }
- delay (200);
- }
- }
- }
- }
// 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