segunda-feira, 2 de fevereiro de 2015

Relógio Digital com PIC16F628 em Linguagem C

Que tal montar seu próprio Relógio Digital?


Este artigo mostra o projeto de um Relógio Digital simples com 4 displays do tipo 7 Segmentos para fins didáticos.
 
 Figura 1 - Display 7 segmentos do Relógio Digital

Para a montagem são utilizados poucos componentes:
- 1 microcontrolador PIC16F628;
- 4 displays 7 segmentos;
- 2 botões para ajuste de hora e minuto;
- 8 resistores de 330 ohms para os segmentos do display;
- 2 resistores de 10 kohms para pullup dos botões;
- 4 resistores de 1 kohms para acionamento dos transistores.

O diagrama de interligação é mostrado na Figura 2.


Figura 2 - Diagrama do Circuito

A montagem pode ser feita em Matriz de Contatos. Veja a Figura 3.


Figura 3 - Circuito montado em Matriz de Contatos

O Vídeo a seguir mostra a Simulação do circuito no Proteus.


Video Relógio Digital rodando no Proteus



O programa do PIC

O programa do Relógio Digital foi escrito em Linguagem C no MPLAB IDE e compilado com o CCS. No Anexo 1 você encontra o código fonte.


A interrupção do Timer0 é utilizada como base de tempo para o relógio (clock).


Todo programa escrito em C inicia-se com a função main ( ).

Após a inicialização algumas variáveis são carregadas com seus valores iniciais. 


A função config_microcontrolador( ) se encarrega de configurar os pinos do microcontrolador como entrada (valor 1) ou saída (valor 0) através dos registros TRISA e TRISB. Os comparadores analógicos internos são desabilitados, pois não são utilizados.

Em setup_timer_0 ( ) é configurado o temporizador timer0 para utilizar a fonte de pulsos internos com presscaler em 1:8 (divisão de pulsos). Esta configuração proporciona um tempo de 2048 us para cada interrupção.

No final das configurações são habilitadas as interrupções do Timer0 e global.

O programa passa então para um loop infinito, em while(true), lendo o status dos botões 1 e 2 para ajuste do minuto e da hora do relógio respectivamente.


A rotina de interrupção do Timer0 é chamada a cada 2048 us.


A cada interrupção é alternado o display que fica aceso, seguindo um processo de multiplexação. Pela cintilação do olho humano enxergamos os 4 displays acesos, mas na verdade apenas um se mantém ligado, e são alternados a cada 2048 us!


A cada interrupção a variável timer é incrementada. 


A cada 29297 interrupções é completado 1 minuto:


29297 x 2048 us = 60000,256 ms ~ 1 minuto


É incrementada a variável do minuto e se necessário a variável de hora.


O horário do relógio é atualizado.


A cada 500 ms o "ponto" do relógio é invertido de status, para "piscar" a cada segundo.


Os "2 pontos" do relógio são formados invertendo-se a montagem do terceiro display de 7 segmentos em 180°.


Você agora pode implementar o código e criar um horário de alarme para adicionar a função de despertador para o seu Relógio Digital!



Obs: 

Este é um circuito didático para ensinar o princípio de funcionamento de um relógio digital. Para menor erro na temporização utilizar cristal externo (XT) de 4 MHz ao invés do oscilador interno (RC).

Note que o minuto não é exato, mas sim de  60000,256 ms, o que acumula um erro de 0,000000042667 %.

Isso quer dizer que o relógio irá adiantar pouco mais de 2 minutos por ano!

(60 minutos x 24 horas x 365 dias = 525600 minutos/ano * 0,256 ms = 134,5536 s)

Para precisão no relógio deve-se utilzar um Relógio de Tempo Real (Real Time Clock - RTC), como por exemplo o DS1302  com cristal de 32,768 kHz ou um PIC com o módulo RTC interno.


Exemplos de circuitos com RTCC:
https://www.youtube.com/watch?v=zR0KW0H_dD4
https://www.youtube.com/watch?v=k_SVMvWyYak


O circuito também não pode ser desligado da alimentação, senão perde a hora, pois não tem bateria de backup.


Anexo 1 - O código fonte do Relógio Digital em Linguagem C

// ***********************************************************
//                          Relogio Digital
// ***********************************************************
// Arquivo:   Relogio.c
// Microcontrolador: PIC16F628    
// Compilador: CCS C Compiler com MPLAB IDE 
// Rev 1.0 03/04/2014
// Rev 1.1 05/04/2014 - alterado pic p 628, adicionado ponto
// Desenvolvido por M.R.G.
// ***********************************************************

/*     Relogio Digital com display 7 segmentos
    com 2 teclas para ajuste de hora e minuto
    utiliza interrupcao do Timer 0 para o clock

*/

// **************** M.R.G. **************************************
// **** Desenvolvido no Brasil *** Made in Brazil ***************
// ********* Build The World ************************************

// Pinos utilizados do microcontrolador:
// RA0 - display unidade
// RA1 - display dezena
// RA2 - display centena
// RA3 - display milhar
// RA4 - saida coletor aberto - botao1
// RA5 - MCLR - entrada digital - botao2
//
// RB0 - segmento ponto
// RB1 - segmento a
// RB2 - segmento b
// RB3 - segmento c
// RB4 - segmento d
// RB5 - segmento e
// RB6 - segmento f 
// RB7 - segmento g



// ******** Inclui ficheiros *********************************

#include <16F628.H> // Define processador

// ******** Configuracao do microcontrolador ******************
#use delay(clock=4000000,RESTART_WDT)

// ******* confifura fuses ***********************************
#fuses INTRC_IO,PUT,WDT,BROWNOUT,NOMCLR,NOLVP,NOCPD
//XT         oscilador externo com cristal
//INTRC_IO    Clock interno, RA6 e RA7 como I/O
//PUT              Ativa tempo de inicialização
//WDT        Ativa Watch Dog Timer
//NOWDT       desativa Wotch Dog Timer
//NOPROTECT       nao protege memoria de programa
//NOBROWNOUT    Não usa brownout reset
//NOMCLR    Pino Master Clear usado como I/O
//NOLVP        Não usa baixa voltagem para programação,
// pino B3 usado como I/O
//NOCPD           Não protege EEPROM




//********** Declara constantes **************************************

#byte porta = 5 // endereco do port a
#byte portb = 6 // endereco do port b


#bit botao1  = porta.4 //botao de incremento de minuto
#bit botao2  = porta.5 //botao de incremento de hora
#bit ponto   = portb.0 //ponto do display

//********** Declara variáveis globais ******************************

unsigned int digito, unidade, dezena, centena, milhar;
unsigned long int tempo;


// **************** Declara protótipos ******************************

void le_botao1 (void);
void le_botao2 (void);



// *************** Rotina de interrupçcao do Timer0 ***************
#int_timer0
void timer0interrupt()                 // 2048 us por interrupcao

{
unsigned int portAPino, portBValor, portBPino;


    digito++;
    
    if (digito == 5)
        digito = 1;




    
// identifica o digito (display) que deve ser aceso

   switch (digito){                //verifica qual digito a acender

     case 1:{                 //codigo para acender o display 1
       portAPino = 0b00000001;
       portBValor = unidade;
         break;}

      case 2:{                 //codigo para acender o display 2
       portAPino = 0b00000010;
       portBValor = dezena;
         break;}

      case 3:{                 //codigo para acender o display 3
       portAPino = 0b00000100;
       portBValor = centena;
         break;}

      case 4:{                 //codigo para acender o display 4
       portAPino = 0b00001000;
       portBValor = milhar;
         break;}

      default:{

         break;}
      }



// carrega valor do numero a acender no diaplay

   switch (portBValor){        //verifica qual valor do numero
      case 0:{                 //codigo para acender o digito 0
        portBPino = 0b01111110;
         break;}

     case 1:{                 //codigo para acender o digito 1
       portBPino = 0b00001100;
         break;}

      case 2:{                 //codigo para acender o digito 2
       portBPino = 0b10110110;
         break;}

      case 3:{                 //codigo para acender o digito 3
       portBPino = 0b10011110;
         break;}

      case 4:{                 //codigo para acender o digito 4
       portBPino = 0b11001100;
         break;}

      case 5: {                //codigo para acender o digito 5
       portBPino = 0b11011010;
         break;}

      case 6: {                //codigo para acender o digito 6
       portBPino = 0b11111010;
         break;}

     case 7: {                //codigo para acender o digito 7
       portBPino = 0b00001110;
         break;}

      case 8: {                //codigo para acender o digito 8
       portBPino = 0b11111110;
         break;}

      case 9: {                //codigo para acender o digito 9
       portBPino = 0b11011110;
         break;}

      default:{

         break;}
      }

    porta = 0;                //apaga todos os digitos
    portB = portBPino;            //acende segmentos
                        //carrega valor do numero no digito 

// pisca os 2 pontos do relogio
        if( (bit_test(tempo,8)) && (bit_test(tempo,7)) && ( (digito == 2)||(digito == 3)) )
            ponto = 1;
        else
            ponto = 0;


    porta = portAPino;             //acende o digito com multiplexacao


// ***** ajusta a hora e minuto  *****

    tempo++;

    if (tempo >= 29297)       //29297 * 2048 us = 60000,256 us = 1 minuto
    {                        //488 = 1 segundo
        unidade++;
        tempo = 0;
    }


// verifica incremento de minuto e hora
    if (unidade >= 10)
    {
        dezena++;
        unidade = 0;
    }

    if (dezena >= 6)
    {
        centena++;
        dezena = 0;
    }

    if ((centena == 4) && (milhar == 2))
    {
        milhar = 0;
        centena = 0;
    }
    if (centena >= 10)
    {
        milhar++;
        centena = 0;    
    }

//    fim da interrupcao

    clear_interrupt(int_rtcc); // clears the timer0 interrupt flag
}



//***********************************************************************
// Configura o microcontrolador 
//***********************************************************************

void config_microcontrolador(void){

   set_tris_A(0b11110000);        //configura pinos de I/O 1 = entrada 0 = saida

   set_tris_B(0b00000000);        //configura pinos de I/O 1 = entrada 0 = saida
                              

   setup_comparator(nc_nc_nc_nc);      //desabilita comparadores internos
   setup_vref(FALSE);
    setup_wdt(WDT_2304MS);                    //habilita watch dog timer
    restart_WDT();                                //zera WDT


// OPTION_REG = B'00010010'    ; T0 interno, dividido por 8 (2 ms/interr)

      //timer 0 habilitado
    setup_timer_0 (RTCC_DIV_8|RTCC_INTERNAL);    //presscaler do Timer0 1:8
                                                //2048 us para interrupcao
    set_timer0(0);                                 //zera contador do Timer 0



    clear_interrupt(int_rtcc);         // clears the timer0 interrupt flag
    enable_interrupts(int_rtcc);     // enables the timer0 interrupt faz T0IE = 1
    enable_interrupts(global);

   return;
}



// ************************************************************************
// Função principal - inicio do programa
// *************************************************************************

void main() {

unsigned long int i;


// --- inicializa variáveis --------------------- 
    portb = 0; 
    digito = 0;
    tempo = 0;    
    unidade = 0;
    dezena = 0;
    centena = 0;
    milhar = 0;            

       config_microcontrolador();          //configura microcontrolador
       restart_WDT();





 while(TRUE)                        //loop infinito
   {
    
        if (!botao1)                   //botao 1 pressionado?
             le_botao1 ();

        if (!botao2)                   //botao 2 pressionado?
             le_botao2 ();

        restart_WDT();         //zera WDT    
               
    }
}



//******************************************************************************
// Le botao 1        - ajuste de minuto
//******************************************************************************

void le_botao1 ()
{                                  // Debouncing --> tempo para estabilizar
 int t;                             // a tecla e evitar repique
   for (t=0;t<50;t++)            // debouncing verifica se tecla pressionada durante tempo t
        {
         delay_ms(1);
         if (botao1) 
            {
              goto sair;   //tecla liberada antes do tempo
            }
          }

        delay_cycles( 2 ); //  NOP - nenhuma instrução
    
   while (!botao1)        //aguarda liberar a tecla
     {
        delay_cycles( 2 ); //  NOP - nenhuma instrução
        restart_WDT();                               //zera WDT
     }


    disable_interrupts (global); // desabilita interrupcao global GIE

    unidade++;            //incrementa minuto

    if (unidade >= 10)
    {
        dezena++;
        unidade = 0;
    }

    if (dezena >= 6)
    {
        dezena = 0;
    }    

  

sair:
    enable_interrupts(global);
    restart_WDT();         //zera WDT
     return;
}



//******************************************************************************
// Le botao 2        - ajuste de hora
//******************************************************************************

void le_botao2 ()
{                                  // Debouncing --> tempo para estabilizar
 int t;                                // a tecla e evitar repique
   for (t=0;t<50;t++)            // debouncing verifica se tecla pressionada durante tempo t
        {
         delay_ms(1);
         if (botao2) 
            {
              goto sair2;   //tecla liberada antes do tempo
            }
          }

        delay_cycles( 2 ); //  NOP - nenhuma instrução
    
   while (!botao2)        //aguarda liberar a tecla
     {
        delay_cycles( 2 ); //  NOP - nenhuma instrução
        restart_WDT();                               //zera WDT
     }


    disable_interrupts (global); // desabilita interrupcao global GIE

    centena++;            //incrementa hora

    if ((centena == 4) && (milhar == 2))
    {
        milhar = 0;
        centena = 0;
    }
    else if (centena == 10)
    {
        milhar ++;
        centena = 0;    
    }
  

sair2:
    enable_interrupts(global);
    restart_WDT();         //zera WDT
    return;
}


//******************************** M.R.G.***********************************



17 comentários:

  1. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
  2. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
  3. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
    Respostas
    1. Este comentário foi removido pelo autor.

      Excluir
    2. Este comentário foi removido por um administrador do blog.

      Excluir
  4. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
  5. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
  6. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
  7. Respostas
    1. eu copiei a programação ela esta dando erro...

      Excluir
    2. Olá Windison! Qual a mensagem de erro que aparece na compilação?
      Este programa foi escrito para compilar com o CCS C Compiler e o microcontrolador PIC16F628.

      Excluir
  8. Montei o circuito, mas deu erro no código.

    ResponderExcluir