terça-feira, julho 31, 2012

Convertendo o Display JY-MCU3208 em um Timer / Cronômetro

Vamos dar um uso prático para o display JY-MCU3208, transformando-o em um timer e cronômetro. A inspiração é um programa de PC que eu fiz algum tempo atrás.


Operação

O tempo no display esta no formato MM:SS (minutos : segundos). A operação é bastante simples e utiliza os três botões do display:
  • O primeiro botão é usado para parar e inciar a contagem. Se o valor no display for zero, será ativada a função de cronômetro, com o valor sendo incrementado a cada segundo (ao atingir 99:59 voltará a zero e continuará contando). Se o valor for diferente de zero ele será decrementado a cada segundo, parando quando atingir zero (modo timer).
  • O segundo botão incrementa os segundos, quando o timer estiver parado. A contagem vai de 0 a 59.
  • O terceiro botão incrementaros minutos, quando o timer estiver parado. A contragem vai de 0 a 99.
A lógica utilizada trata os botões quando eles são soltos.

Código

O código aproveita o gerador de caracteres e a rotina de escrita anteriores, acrescentando o caracter "dois pontos":
  1. // Matriz de Caracteres 5x7  
  2. // Contem os dígitos de 0 a 9 e dois pontos  
  3. uint8_t digitos [11][7] PROGMEM =  
  4. {  
  5.     { 0x0E, 0x11, 0x15, 0x15, 0x15, 0x11, 0x0E },  
  6.     { 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x1F },  
  7.     { 0x0E, 0x11, 0x02, 0x04, 0x08, 0x10, 0x1F },  
  8.     { 0x0E, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0E },  
  9.     { 0x11, 0x11, 0x11, 0x1F, 0x01, 0x01, 0x01 },  
  10.     { 0x1F, 0x10, 0x10, 0x1E, 0x01, 0x11, 0x0E },  
  11.     { 0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E },  
  12.     { 0x1F, 0x11, 0x01, 0x02, 0x04, 0x04, 0x04 },  
  13.     { 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E },  
  14.     { 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C },  
  15.     { 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00 }  
  16. };  
  17.   
  18. // Mostra o digito d a partir da posição x  
  19. static void display (uint8_t x, uint8_t d)  
  20. {  
  21.     uint8_t i, y, mask, gc;  
  22.       
  23.     for (y = 0; y < 7; y++)  
  24.     {  
  25.         gc = pgm_read_byte(&(digitos[d][y]));  
  26.         mask = 0x10;  
  27.         for (i = 0; i < 5; i++)  
  28.         {  
  29.             ht1632c_setLED (x+i, y, gc & mask);  
  30.             mask = mask >> 1;  
  31.         }  
  32.     }  
  33. }  
Um vetor guarda o valor atual do display e uma variável o modo atual de operação.
  1. // Variaveis  
  2. static volatile uint8_t tempo[5];  
  3. static volatile enum { PARADO, SUBINDO, DESCENDO } modo;  
O programa principal inicia as variáveis e o hardware.
  1. // Programa principal  
  2. int main(void)  
  3. {  
  4.     uint8_t i;  
  5.       
  6.     // Zera o relogio  
  7.     tempo[0] = 0;  
  8.     tempo[1] = 0;  
  9.     tempo[2] = 10;  
  10.     tempo[3] = 0;  
  11.     tempo[4] = 0;  
  12.     modo = PARADO;  
  13.     for (i = 0; i < 5; i++)  
  14.         display (6*i, tempo[i]);  
  15.   
  16.     // Liga pullup das teclas  
  17.     TEC_DDR &= ~(TEC_KEY1|TEC_KEY2|TEC_KEY3);  
  18.     TEC_PORT |= TEC_KEY1|TEC_KEY2|TEC_KEY3;  
  19.       
  20.     ht1632c_init();             // inicia o controlador do display  
  21.     ht1632c_send_screen ();     // limpa o display  
  22.     tempo_init();               // inicia a contagem de tempo  
  23.   
  24.     // Loop perpétuo - somente tratando a interrupção de timer  
  25.     for (;;)  
  26.     {  
  27.     }  
  28. }  
  29.   
  30. // Inicia a contagem de tempo  
  31. static void tempo_init (void)  
  32. {  
  33.   ASSR |= (1<<AS2);     // timer2 async from external quartz  
  34.   TCCR2 = 0b00000010;   // normal,off,/8; 32768Hz/256/8 = 16 Hz  
  35.   TIMSK |= (1<<TOIE2);  // enable timer2 overflow int  
  36.   sei();                // enable interrupts  
  37. }  
A ação toda está na rotina de interrupção do timer.
  1. // Interrupção do Timer2  
  2. ISR(TIMER2_OVF_vect)   
  3. {  
  4.     static uint8_t cnt_seg = 16;  
  5.     static uint8_t teclas = TEC_KEY1|TEC_KEY2|TEC_KEY3;  
  6.     uint8_t mudou = FALSE;  
  7.     uint8_t i;  
  8.   
  9.     if (--cnt_seg == 0)  
  10.     {  
  11.         cnt_seg = 16;  
  12.           
  13.         // Atualiza a contagem  
  14.         if (modo == SUBINDO)  
  15.         {  
  16.             mudou = TRUE;  
  17.             if (++tempo[4] == 10)  
  18.             {  
  19.                 tempo[4] = 0;  
  20.                 if (++tempo[3] == 6)  
  21.                 {  
  22.                     tempo[3] = 0;  
  23.                     if (++tempo[1] == 10)  
  24.                     {  
  25.                         tempo[1] = 0;  
  26.                         if (++tempo[0] == 10)  
  27.                             tempo[0] = 0;  
  28.                     }  
  29.                 }  
  30.             }  
  31.         }  
  32.         else if (modo == DESCENDO)  
  33.         {  
  34.             mudou = TRUE;  
  35.             if (tempo[4] == 0)  
  36.             {  
  37.                 tempo[4] = 9;  
  38.                 if (tempo[3] == 0)  
  39.                 {  
  40.                     tempo[3] = 5;  
  41.                     if (tempo[1] == 0)  
  42.                     {  
  43.                         tempo[1] = 9;  
  44.                         tempo[0]--;  
  45.                     }  
  46.                     else  
  47.                         tempo[1]--;  
  48.                 }  
  49.                 else  
  50.                     tempo[3]--;  
  51.             }  
  52.             else  
  53.                 tempo[4]--;  
  54.             if ((tempo[0] + tempo[1] + tempo[3] + tempo[4]) == 0)  
  55.                 modo = PARADO;  
  56.         }  
  57.     }  
  58.       
  59.     // Trata as teclas  
  60.     if (((teclas & TEC_KEY1) == 0) && ((TEC_PIN & TEC_KEY1) != 0))  
  61.     {  
  62.         // soltou tecla de modo  
  63.         if (modo == PARADO)  
  64.         {  
  65.             if ((tempo[0] + tempo[1] + tempo[3] + tempo[4]) == 0)  
  66.                 modo = SUBINDO;  
  67.             else  
  68.                 modo = DESCENDO;  
  69.         }  
  70.         else  
  71.             modo = PARADO;  
  72.     }  
  73.     if (modo == PARADO)  
  74.     {  
  75.         if (((teclas & TEC_KEY2) == 0) && ((TEC_PIN & TEC_KEY2) != 0))  
  76.         {  
  77.             mudou = TRUE;  
  78.             if (++tempo[4] == 10)  
  79.             {  
  80.                 tempo[4] = 0;  
  81.                 if (++tempo[3] == 6)  
  82.                     tempo[3] = 0;  
  83.             }  
  84.         }  
  85.         if (((teclas & TEC_KEY3) == 0) && ((TEC_PIN & TEC_KEY3) != 0))  
  86.         {  
  87.             mudou = TRUE;  
  88.             if (++tempo[1] == 10)  
  89.             {  
  90.                 tempo[1] = 0;  
  91.                 if (++tempo[0] == 10)  
  92.                     tempo[0] = 0;  
  93.             }  
  94.         }  
  95.     }  
  96.     teclas = TEC_PIN;  
  97.       
  98.     if (mudou)  
  99.     {  
  100.         // Atualiza o display  
  101.         for (i = 0; i < 5; i++)  
  102.             display (6*i, tempo[i]);  
  103.     }  
  104.      
  105. }  
Uma sugestão de aperfeiçoamento é  detectar o acionamento de dois botões e zerar o display nesta condição.

Outra melhoria possível é fazer o display piscar quando estiver no modo timer e a contagem chegar a zero. Pode-se também conectar um alto-falante ou buzzer para gerar um alarme sonoro.

O Timer em Funcionamento

O vídeo abaixo mostra o resultado obtido.


Nenhum comentário: