Página 1 de 1

[Ajuda] Utilizar Timer PIC16F877A

MensagemEnviado: 29 Nov 2011 16:10
por marcosribeirobr
Olá galera não estou conseguir ajudar o timer do PIC16F877A, estou utilizando cristal de 4MHz e necessito que a cada 1 segundo seja incrementado a variável "segundo".

Segue o código até o momento, encontrei alguns exemplos de implementação do timer, mas acabou não dando certo.

Código: Selecionar todos

#define A_incre portd.f0
#define B_decre portd.f1
#define C_start portd.f2

char segundo, unidade_segundo, dezena_segundo, minuto;



//========================ATUALIZAÇÃO DISPLAY 7 SEGMENTOS=======================
void imprime_display (char posicao, char valor)
{
 portb=valor;
 if (posicao==1)        //UNIDADE SEGUNDO (CI4511 U3) PINO26
 {
  portc.f7=0;
  delay_ms(1);
  portc.f7=1;
 }
 else if (posicao==2)   //DEZENA SEGUNDO (CI4511 U2) PINO25
 {
  portc.f6=0;
  delay_ms(1);
  portc.f6=1;
 }
 else if (posicao==3)   //MINUTO (CI4511 U1) PINO24
 {
  portc.f5=0;
  delay_ms(1);
  portc.f5=1;
 }
}
//=======================FIM ATUALIZAÇÃO DISPLAY================================



//=========================ATUALIZAÇÃO DISPLAY TIMER============================
void imprime_timer (char posicao, char valor)
{
 portb=valor;
 if (posicao==1)        //UNIDADE SEGUNDO (CI4511 U3) PINO26
 {
  portc.f7=0;
  delay_ms(1);
  portc.f7=1;
 }
 else if (posicao==2)   //DEZENA SEGUNDO (CI4511 U2) PINO25
 {
  portc.f6=0;
  delay_ms(1);
  portc.f6=1;
 }
 else if (posicao==3)   //MINUTO (CI4511 U1) PINO24
 {
  portc.f5=0;
  delay_ms(1);
  portc.f5=1;
 }
}
//=======================FIM ATUALIZAÇÃO DISPLAY TIMER==========================



//================================TIMER 1=======================================
void interrupt()
{
 if (PIR1.TMR1IF)
 {
  segundo--;
  if (segundo==255)
  {
   minuto--;
   segundo=59;
  }
  dezena_segundo = segundo/10;
  unidade_segundo = segundo - segundo/10*10;
  imprime_timer (3,minuto);
  imprime_timer (2,dezena_segundo);
  imprime_timer (1,unidade_segundo);
  PIR1.TMR1IF = 0;              //reset timer1 flag
  TMR1L = 0xEC ;
  TMR1H = 0x78;
 }


}
//=============================FIM TIMER 1======================================



void main()
{
 trisa=0;
 trisb=0;
 trisc=0;
 trisd=0b11111111;
 porta=0;
 portb=0;
 portc=0;
 portd=0;
 
 minuto=0;
 segundo=0;

 
 while (1)
 {
 //============================BOTAO "A" INCREMENTO=============================
  while (A_incre==0)
  {
   if (minuto==9 && segundo==59)
   {
   }
   else
   {
    delay_ms (100);
    segundo++;
    if (segundo==60 && minuto<9)
    {
     minuto++;
     segundo=0;
     imprime_display (3,minuto);
    }
    dezena_segundo = segundo/10;
    unidade_segundo = segundo - segundo/10*10;
    imprime_display (3,minuto);
    imprime_display (2,dezena_segundo);
    imprime_display (1,unidade_segundo);
   }
  }
 //============================FIM INCREMENTO===================================
 
 //==========================BOTAO "B" DECREMENTO===============================
  while (B_decre==0)
  {
   if (minuto==0 && dezena_segundo==0 && unidade_segundo==0)
   {
    break;
   }
   else
   {
    delay_ms(100);
    segundo--;
    if (segundo==255 && minuto>0)
    {
     minuto--;
     segundo=59;
     imprime_display (3,minuto);
    }
    dezena_segundo = segundo/10;
    unidade_segundo = segundo - segundo/10*10;
    imprime_display (3,minuto);
    imprime_display (2,dezena_segundo);
    imprime_display (1,unidade_segundo);
   }
  }
 //============================FIM DECREMENTO===================================
 
 //========================BOTAO "START" CRONOMETRO=============================
  if (C_start==0)
  {
   T1CON.TMR1CS = 0;                    // Fosc / 4
   T1CON.T1CKPS1 = 1;                   // Setting prescale value to 1:8
   T1CON.T1CKPS0 = 1;                   //              "
   T1CON.TMR1ON = 1;                    //turn on timer1
   TMR1L = 0xEC ;
   TMR1H = 0x78;
   PIE1.TMR1IE = 1;
   PIR1.TMR1IF = 0;
   INTCON.PEIE = 1;
   INTCON.GIE = 1;           // Enable interrupt on overflow
  }
 
 
 //============================FIM CRONOMETRO===================================
 
 }//fim while (1)
}//fim void main

Re: [Ajuda] Utilizar Timer PIC16F877A

MensagemEnviado: 29 Nov 2011 19:48
por andre_luis
marcosribeirobr escreveu:...Segue o código até o momento...mas acabou não dando certo.


O que acontece exatamente ?
Oscila fora da frequencia, ou sequer oscila ?


+++

Re: [Ajuda] Utilizar Timer PIC16F877A

MensagemEnviado: 29 Nov 2011 20:27
por marcosribeirobr
andre_teprom escreveu:
marcosribeirobr escreveu:...Segue o código até o momento...mas acabou não dando certo.


O que acontece exatamente ?
Oscila fora da frequencia, ou sequer oscila ?


+++


Essa implementação do TIMER peguei em alguns exemplos na internet, mas nao deu certo pois está incrementando mais rápido que 1 segundo, tentei alterar os valores do TMR1L e TMR1H mas também não deu certo acabou piorando.

MensagemEnviado: 30 Nov 2011 08:59
por ze
o mais legal seria se voce entendesse como funciona o circuito do timer antes de confiar cegamente no que acha na net. Que frequencia isso dá? confere se é 3.6Hz. neste caso ele é meio feio
Código: Selecionar todos
T1CON.T1CKPS1 = 1;                   // Setting prescale value to 1:8
 T1CON.T1CKPS0 = 1;                   //              "
 T1CON.TMR1ON = 1;                    //turn on timer1
 TMR1L = 0xEC ;
 TMR1H = 0x78;

façamos mais bunitinho 400Hz
TMR1L = 0xC8;
TMR1H = 0xFE;
eu poderia até saber explicar como cheguei nestes valores mas a parte legal é voce descobrir. Com este dado em mãos fica fácil ajustar 1 seg na interrupt
algo como:
Código: Selecionar todos
unsigned char segundo,minuto;
unsigned int tmp,seg=600; //p.ex. 10 minutos
void interrupt()
{
 if (PIR1.TMR1IF)
 {
  if (tmp++>399) {seg--;tmp=0;}
  minuto=seg/60;
  segundo=seg%60;
  dezena_segundo = segundo/10;
  unidade_segundo = segundo%10;
  imprime_timer (3,minuto);
  imprime_timer (2,dezena_segundo);
  imprime_timer (1,unidade_segundo);
...

dica: cristal de 1MHz no clock voce deve conseguir menor freq na interrupt ou se voce colocar cristal 32768 externo no timer1
li rápido o dshit e pode haver alguma shit e claro desconsidere as palavras acima pois não deve confiar na net, lembra?

MensagemEnviado: 30 Nov 2011 15:48
por marcosribeirobr
lellis escreveu:o mais legal seria se voce entendesse como funciona o circuito do timer antes de confiar cegamente no que acha na net. Que frequencia isso dá? confere se é 3.6Hz. neste caso ele é meio feio
Código: Selecionar todos
T1CON.T1CKPS1 = 1;                   // Setting prescale value to 1:8
 T1CON.T1CKPS0 = 1;                   //              "
 T1CON.TMR1ON = 1;                    //turn on timer1
 TMR1L = 0xEC ;
 TMR1H = 0x78;

façamos mais bunitinho 400Hz
TMR1L = 0xC8;
TMR1H = 0xFE;
eu poderia até saber explicar como cheguei nestes valores mas a parte legal é voce descobrir. Com este dado em mãos fica fácil ajustar 1 seg na interrupt
algo como:
Código: Selecionar todos
unsigned char segundo,minuto;
unsigned int tmp,seg=600; //p.ex. 10 minutos
void interrupt()
{
 if (PIR1.TMR1IF)
 {
  if (tmp++>399) {seg--;tmp=0;}
  minuto=seg/60;
  segundo=seg%60;
  dezena_segundo = segundo/10;
  unidade_segundo = segundo%10;
  imprime_timer (3,minuto);
  imprime_timer (2,dezena_segundo);
  imprime_timer (1,unidade_segundo);
...

dica: cristal de 1MHz no clock voce deve conseguir menor freq na interrupt ou se voce colocar cristal 32768 externo no timer1
li rápido o dshit e pode haver alguma shit e claro desconsidere as palavras acima pois não deve confiar na net, lembra?


Primeiramente obrigado pela ajuda, esqueci de mencionar no inicio do post que sou leigo no assunto e peço desculpa pela minha ignorância em alguns comentários..rsrs pois tudo é novo ainda para mim ainda, quanto ao TIMER se puder explicar como chegou nos resultados obtidos ficarei grato pois também não consegui chegar no valor.

Desde já, agradeço.

MensagemEnviado: 30 Nov 2011 17:30
por MOR_AL
Olá!
Você está ciente de que o contador do TIMER é incrementado a cada pulso de clock, e portanto o tempo de contagem é "quanto falta" para a contagem "virar" de tudo um para tudo zero?
Tente ler o manual que lá tem toda a informação necessária para programá-lo.
Se o seu inglês não for suficiente, tem documentação em português na net.
Bons projetos.
MOR_AL

MensagemEnviado: 01 Dez 2011 07:27
por ze
pois não amigo. presuponho que já tenhas noção de hexadecimal <-> decimal, MegaHerts, MSB, LSB e afins. Caso não tenha não temas adimitir. Aprenda e releia depois.
faço minha as palavras do moris. vejamos se consigo exemplificar. veja o circuito do timer
Imagem
ao ligar TMR1CS=0 note que vai entrar 1MHz no prescaler que voce programou para dividir por 8
1Mhz=1000000Hz isto implica que 1000000/8=125000Hz. memorize
Só que eu quero 400Hz de interrupção. Lembra do 125000 laaaaá de trás? Portanto 125000/400=312,5 (numero quebrado não é bom. fda-se, por enquanto)
De acordo com a teoria 'do moris' (vulgo MOR_AL) a interrupção ocorre quando o contador - que é crescente - passa de 0xffff para 0x0000 ou seja no momento 65536 (ou é 65535...? nunca sei). Portanto para passar por isso a 400 ciclos por segundo (Hz) ele precisa de 312,5 contagens (num falei que não era um bom numero?). Devemos fazer 65536-312,5=65223,5. Esquecendo o 0,5 em hexa fica 0xfe7c que é o que deve ser carregado no timer1 TMR1H=0xfe TMR1L=0x7c (recarga)

(putz! agora o valor deu diferente. antigamente eu era confuso, hoje em dia não tenho mais certeza. veja a mecânica da coisa aí pelo menos. to com pregui de rever os calculos.)


Exercício:
mostre que voce entendeu e calcule os valores de recarga para prescaler = 4 sendo essa a primeira coisa a fazer na interrupção

abç