Ir ao conteúdo
  • Cadastre-se

Relógio em C usando microcontrolador PIC16F628A


Posts recomendados

Galera, estou fazendo um relógio em C usando o microcontrolador pic 16f628a, junto com mplab xc8. Nao estou conseguindo fazer o ajuste das horas, ele não incrementa e de acordo com meu pensamento, estaria certo (eis o problema, não enxergar o erro) e gostaria da ajuda de vocês. Caso puderem ajudar, segue o código:

 

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <pic16f628.h>
 
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
 
#define _XTAL_FREQ 4000000
 
//Configuração para catodo comum
unsigned char const digito[] = { 0b1111110,//0       
                                  0b0110000,//1
                                  0b1101101,//2
                                  0b1111001,//3
                                  0b0110011,//4
                                  0b1011011,//5
                                  0b1011111,//6
                                  0b1110000,//7
                                  0b1111111,//8
                                  0b1111011,//9    
};
 
int unidade=0;
int dezena=0;
int centena=0;
int milhar=0;
int seleciona_display=0;
int estouro = 0;
int segundo = 0;
int minuto = 0;
int hora = 0;
int led_seg = 0;
int entrada = 0;
 
 
/*Base de calculo para contagem de 1 seg pelo TMR0:
 * Ciclo basico do processador  (t) = 1/(frequencia do XTAL /4)
 * Tempo de estouro sem prescaler (T) = (t) * 256 
 * Tempo de estouro com prescaler (TP) = (t) * 256 * (n) ;;;;onde n = valor do preescaler
 * T(requerido em segundos) = T(estouro com prescaler) * N(totalizador a ser utilizado na variavel C do contador).  
 * n=T/t
 */
 
//neste caso a interrupcao e efetuada pelo estouro do TIMER0, e esta função é acessada acada estouro
void interrupt INT (void)
{
    estouro++;                        //incrementa variavel est a cada estouro do timer
    switch(seleciona_display)           //multiplex dos displays
    {
        //display 1: Display das unidades
        case 0:
            PORTB = digito[unidade];
            PORTAbits.RA0 = 1;
            PORTAbits.RA1 = 0;
            PORTAbits.RA2 = 0;
            PORTAbits.RA3 = 0;            
            seleciona_display = 1;
            break;
        //display 2: Display das dezenas    
        case 1:
            PORTB = digito[dezena];
            PORTAbits.RA0 = 0;
            PORTAbits.RA1 = 1;
            PORTAbits.RA2 = 0;
            PORTAbits.RA3 = 0; 
            seleciona_display = 2;
            break;
        //display 3: Display das centenas 
        case 2:
            PORTB = digito[centena];
            PORTAbits.RA0 = 0;
            PORTAbits.RA1 = 0;
            PORTAbits.RA2 = 1;
            PORTAbits.RA3 = 0; 
            seleciona_display = 3;
            break;
        //display 4: Display das milhares    
        case 3:
            PORTB = digito[milhar];
            PORTAbits.RA0 = 0;
            PORTAbits.RA1 = 0;
            PORTAbits.RA2 = 0;
            PORTAbits.RA3 = 1; 
            seleciona_display = 0;
            break;  
    }
    INTCONbits.TMR0IF = 0;            //limpa flag de estouro do TMR0
    INTCONbits.TMR0IE = 1;            //habilita interrupção por estouro
}
 
void converte_valor (void)
{
    unidade = segundo %10;          //minuto
    dezena = segundo /10;           //minuto
    centena = minuto %10;           //hora
    milhar = minuto /10;            //hora
}
 
void main(void) {
        
    TRISA = 0b01110000;             //porta como saída
    TRISB = 0b00000000;             //portab como saída
    PORTA = 0b00000000;
    #define led_seg RB7
      
    //Configuração para contagem do tempo
    INTCONbits.GIE = 1;               //Habilita interrupção
    INTCONbits.TMR0IE = 1;            //Habilita interrupção TMR0
    INTCONbits.TMR0IF = 0;            //Overflow ainda não ocorreu
    OPTION_REGbits.T0CS = 0;          //Cyclo de clock interno
    OPTION_REGbits.PSA = 0;           //Preescaler desligado
    OPTION_REGbits.PS = 0b111;        //Tempo preescaler 1:256
    PCONbits.OSCF = 1;                //INTOSC Oscillator Frequency bit
    
    while(1)
    { 
        if(PORTAbits.RA4 == 1)
        {
            INTCONbits.TMR0IE = 0;
            //Todos os displays acesos
            PORTAbits.RA0 = 1;
            PORTAbits.RA1 = 1;
            PORTAbits.RA2 = 1;
            PORTAbits.RA3 = 1;
            if(PORTAbits.RA6 == 1)      //incrementa minuto
            {
                minuto = minuto + 1;
                converte_valor();
            }    
        }else{ 
            INTCONbits.TMR0IE = 1;
        if (estouro == 15)              //contador do estouro. a cada 15 estouros temos 1 segundo
        {
            led_seg = ~led_seg;         //inverte estado do led
            segundo++;                  //incrementa segundos
            estouro = 0;                //zera valor do estouro
            converte_valor();
            if(segundo == 60)       
            {
                minuto++;               //incrementa minuto
                segundo = 0;            //zera segundo
                converte_valor();
                if (minuto == 60)
                {
                    hora++;             //incrementa horas
                    minuto = 0;         //zera minuto
                    converte_valor();
                    if(hora == 23)
                    {
                        hora = 0;       //zera hora
                    }                    
                }
            }
        }
        }      
      }
    return;
}
 

Link para o comentário
Compartilhar em outros sites

Edit1: Para ativar a interrupção do TMR0 o bit PEIE (Peripheral Interrupt Enable bit) também deve ser setado, ou não?

Edit2: Não, não precisa =)

 




if(PORTAbits.RA4 == 1) {
   INTCONbits.TMR0IE = 0;
   PORTAbits.RA0 = 1;
   PORTAbits.RA1 = 1;
   PORTAbits.RA2 = 1;
   PORTAbits.RA3 = 1;
   if(PORTAbits.RA6 == 1)           //incrementa minuto
   {  
      minuto = minuto + 1;
      converte_valor();
   } 
}
 
   else {
   INTCONbits.TMR0IE = 1;
   
      if (estouro == 15) {          //contador do estouro. a cada 15 estouros temos 1 segundo
         led_seg = ~led_seg;        //inverte estado do led
         segundo++;                 //incrementa segundos
         estouro = 0;               //zera valor do estouro
         converte_valor();
         
            if(segundo == 60) {
               minuto++;            //incrementa minuto
               segundo = 0;         //zera segundo
               converte_valor();
               
               if (minuto == 60) {
                  hora++;           //incrementa horas
                  minuto = 0;       //zera minuto
                  converte_valor();
                  
                  if(hora == 24) {
                     hora = 0;      //zera hora
                  }                    
               }
            }
      }
   }    



 

Se o pino RA4 e o RA6 estiverem em nível alto o PIC incrementa a variável minuto porém o incremento não é mostrado no display pois a interrupção está desativada e é lá que a atualização do display é feita;

 



if(PORTAbits.RA4 == 1) {
   INTCONbits.TMR0IE = 0;


 

o else também não é executado então o PIC incrementa a variável minuto fazendo com que ela passe de 60. Considerando que há botão conectado ao pino RA6, ao apertá-lo a variável minuto incrementará muitas vezes...

 

os displays estão sendo multiplexados no tempo (eu acho xD) então não é possível você ligar todos eles no mesmo instante.



//Todos os displays acesos
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 1;
PORTAbits.RA2 = 1;
PORTAbits.RA3 = 1;


 

display7seg_anim.gif

 

Se você estiver usando o Proteus carregue o pic com o arquivo .cof e em vez de apertar play aperte pause e faça o passo a passo do código... Assim fica mais fácil encontrar erros.

Link para o comentário
Compartilhar em outros sites

 
 
os displays estão sendo multiplexados no tempo (eu acho xD) então não é possível você ligar todos eles no mesmo instante.

 

Isso era só uma ideia maluca que tive, esqueci de apagar.

 

Pretendo usar o botão na porta RA4 como se fosse um modo de "habilitar" a edição das horas, por tanto fiz o seguinte:

 

if(PORTAbits.RA4)
        { 
            habilita_edicao = 1;                                          //habilita modo de edição
                if(habilita_edicao && PORTAbits.RA6)         //se ambas condicoes forem verdadeiras
                    minuto = minuto + 1;                    
                    if(minuto == 60) minuto = 0;                     //se minuto = 60, zera minuto
                    converte_valor(); 
                    if(estouro == 30) habilita_edicao = 0;       //tempo de X segundos para fazer edição,
                                                                                     //apos isso edição é desabilitada (X*15)
        }
 
 
Se você estiver usando o Proteus carregue o pic com o arquivo .cof e em vez de apertar play aperte pause e faça o passo a passo do código... Assim fica mais fácil encontrar erros.

 

Aonde fica esse arquivo? Pois fiz uma busca na pasta e não encontrei.

Link para o comentário
Compartilhar em outros sites

Na aba projects (dentro do MPLAB) clique com o direito na pasta do projeto / Selecione Properties / Selecione o XC8 global options / em Output file format escolha COFF. O cof será salvo na pasta diretório do projeto > dist > default > production

 
No proteus quando você carregar o PIC com o .cof clique em pause e a janela do código aparecerá (talvez em branco) então você clica na setinha "step in" / "step over" o código aparecerá daí é só ir fazendo os testes =D...
 
Se você clicar duas vezes em uma linha de código qualquer uma bolinha vermelha aparecerá (breakpoint) daí dando o play ou clicando no símbolo com o homenzinho correndo a simulação pausará quando o PIC for executar aquela linha (dá para economizar um tempinho). 
 
Meu MPLAB XC8 demora 15 segundos para compilar um código (bem pequeno) para o 18F4550 =(
Link para o comentário
Compartilhar em outros sites

 

Se o pino RA4 e o RA6 estiverem em nível alto o PIC incrementa a variável minuto porém o incremento não é mostrado no display pois a interrupção está desativada e é lá que a atualização do display é feita;
 
o else também não é executado então o PIC incrementa a variável minuto fazendo com que ela passe de 60. Considerando que há botão conectado ao pino RA6, ao apertá-lo a variável minuto incrementará muitas vezes...
 

 

Realmente, através desse método facilita bastante. Pode até demorar um pouco para rodar o programa, porém ajuda a encontrar erros. E realmente com havia dito, o contador minuto incrementa infinitas vezes.

Mais tarde irei pensar em algum jeito que incremente 1 a cada apertar do botão e não infinitas vezes que nem está acontecendo agora.

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
if(hora == 23)                    {                        hora = 0;       //zera hora                    }

esquisito. Vai zerar às 23:00

Que tal

if (segundo>59)...

if (minuto>59)...

if (hora>23)...

 

esquisito II. digitei um hyper mega texto com mais pitacos e não apareceu. + tarde temto de novo


esquisito - III . meu corretor ortográfico não está funcionando. Preguiça de corrigir os erros de digitação

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...