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.***********************************
Este comentário foi removido por um administrador do blog.
ResponderExcluirEste comentário foi removido por um administrador do blog.
ResponderExcluirEste comentário foi removido por um administrador do blog.
ResponderExcluirEste comentário foi removido pelo autor.
ExcluirEste comentário foi removido por um administrador do blog.
ExcluirEste comentário foi removido por um administrador do blog.
ResponderExcluirEste comentário foi removido pelo autor.
ExcluirEste comentário foi removido por um administrador do blog.
ResponderExcluirEste comentário foi removido pelo autor.
ExcluirEste comentário foi removido por um administrador do blog.
ResponderExcluirEste comentário foi removido pelo autor.
Excluiresse codigo funciona ?
ResponderExcluirFunciona igual ao vídeo.
Excluireu copiei a programação ela esta dando erro...
ExcluirOlá Windison! Qual a mensagem de erro que aparece na compilação?
ExcluirEste programa foi escrito para compilar com o CCS C Compiler e o microcontrolador PIC16F628.
Montei o circuito, mas deu erro no código.
ResponderExcluirFalha na construção
ResponderExcluir