Fork me on GitHub

Microcontrolandos

O Blog está passando por uma fase de mudanças. Todos os posts estão sendo atualizados, códigos, links e imagens estão sendo arrumados. Conteúdos novos ainda estão por vir.

Utilizando o TIMER0 do PIC

Share:

Utilizando o TIMER0 do PIC

O TIMER0 normalmente é utilizado em projetos para fazer a base de tempo, ou seja, o relógio do projeto, como contar tempo para repetir ou considerar um evento.

O TIMER0 utiliza normalmente três registros especiais (SFR), dependendo do PIC a ser utilizado. Mostrarei como utilizar o TIMER0 do PIC16F877A.








PIC16F877A

O temporizador/Contador TIMER0 possui as seguintes características:

• temporizador/contador de 8 bits;
• leitura e gravação;
• software prescaler de 8 bits programável;
• Relógio interno ou externo selecionavel;
• Interrupção no estouro de FFh para 00h;
• Borda de seleção para relógio externo;

Registros associados ao TIMER0:




MODO CONTADOR:

O TIMER0 funciona como contador, quando você usa como oscilador os pulsos externos aplicado no pino RA4/T0CKIN.

Você deve configurar o seguinte registro:





T0CS - Define a fonte de clock do TIMER0:

1 - Externa (PINO RA4/T0CKIN) - Modo contador;
0 - Interna (Cristal de quartzo) - Modo temporizador;


T0SE - Seleção da borda de transição do pino RA4/T0CKIN

1 - transição nivel alto-baixo (transição negativa);
0 - transição nivel baixo-alto (transição positiva);


PSA - Habilitação do prescaler (no modo CONTADOR é comum desabilitar);


1 - Desabilitado;
0 - Habilitado;



PS2, PS1, PS0 - Seleção do prescaler( somente no modo temporizador);


   bits / TMR0 rate
000 1:2
001 1:4
010 1:8
011 1:16
100 1:32
101 1:64
110 1:128
111 1:256



Exemplo:

void main()
{
TRISB=0;
OPTION_REG=0b10111000; //modo contador
TMR0=0;                   //Inicializa o registro TMR0 com o valor 0.
while(1)
{
  if(INTCON.TMR0IF)
  {
     INTCON.TMR0IF=0;    //limpa a flag
     TMR0 = 0; 
     portb=~portb; //quando acontecer o overflow(a cada 256 pulsos) interver as saidas
  }
delay_ms(10);
}
}




O registro TMR0 é o registro que armazena o estado inicial da contagem. Possui 8 bits, por  isso conta de 0 a 255. Quando acontece o overflow ele retorna a contagem inicial 0. O bit do overflow é o INTCON.TMR0IF e deve ser limpo por software.

MODO TEMPORIZADOR:

O temporizador do TIMER0 funciona quando você usa o oscilador interno do PIC ou o cristal de quartzo externo.

Você deve configurar os seguintes bits do registro OPTION_REG:


T0CS - Define a fonte de clock do TIMER0:
1 - Externa (PINO RA4/T0CKIN) - Modo contador;
0 - Interna (Cristal de quartzo) - Modo temporizador;

PSA - Habilitação do prescaler (no modo CONTADOR é comum desabilitar);

1 - Desabilitado;
0 - Habilitado;



PS2, PS1, PS0 - Seleção do prescaler;


bits / TMR0 rate
000 1:2
001 1:4
010 1:8
011 1:16
100 1:32
101 1:64
110 1:128
111 1:256


Você deve estar perguntando: O que é prescaler?
Prescaler é o divisor de frequência do clock do TIMER0. É usado no modo temporizador para poder obter tempos maiores.





A fórmula do tempo para o overflow é a seguinte:

t = ciclo de máquina * prescaler * contagem ( 256 - TMR0 );

ciclo de máquina = 4 / Fosc;


Fosc é a freqência do clock do cristal oscilador.

EXEMPLO:
O clock de um PIC é de 4MHz, utlizado o prescaler de 1:256 e contagem de 0 a 256, qual será o tempo?

ciclo de máquina = 4/4 = 1us.

t = 1 * 256 * 256;
t = 65536us ou 65,536ms

para ter tempos ainda maiores, como alguns segundos,um dos meios de se conseguir é utilizando a interrupção.
Veja um exemplo: utilizando clock 4Mhz e prescaler de 1:4.

unsigned contagem;

void interrupt()
{ 
contagem++;       //para cada interrpção do TMR0 incrementa a variável contagem
TMR0 = 0; 
INTCON.TMR0IF = 0;  //limpa o overflow.
}

void main()
{
INTCON.GIE = 1; //habilita interrupção global;
INTCON.PEIE = 1; //habilita interrupção dos perifericos;
INTCON.TMR0IE = 1; //habilita interrupção do TMR0;
TMR0 = 0; // TIMER0 inicia com o valor 0;
OPTION_REG = 0b10000001; // Modo Temporizador, prescaler 1:4;
//tempo =1us * 4 * 256 = 1ms
...
while (1)
{
   if(contagem == 1000)    //quando o contagem = 1000, tempo = 1000 * 1ms = 1s;
   {
     portb.RB0 = ~portb.RB0;  //inverte o estado do pino rb0
     contagem = 0; //reseta a variavel contagem 
   }                     
}
}


98 comentários:

  1. Boa tarde.
    No texto você coloca t=65,536ms e no código 4,096ms
    É uma divisão por 16 que eu não consegui entender.
    Outra coisa, preciso contar um segundo com um cristal de 20MHz, pode me ajudar na conta mais precisa /

    ResponderExcluir
    Respostas
    1. Muito obrigado pelo seu comentário! É o primeiro do blog!!!
      Você tem razão,acabei utilizando o prescaler de 1:256 sendo que na verdade é de 1:16, me desculpe pelo erro e já corrigi.

      No seu caso:
      ciclo de máquina = 4 / 20MHZ = 0,2 us.

      tempo = 0,2 * 4 * 125 = 100us.
      utilizando prescaler de 1:4 e TMR0=131(256 - 125) => irá contar de 131 a 256.

      Para cada interrupção gerada, você pode incrementar uma variável (x) e quando essa variável chegar no valor de 10000 executar alguma coisa.
      No final de tudo: 10000 * 100us = 1segundo.

      Espero que possa ter entendido! Muito obrigado pelo seu comentário!!

      Excluir
    2. Utilizando O Timer0 Do Pic - Microcontrolandos >>>>> Download Now

      >>>>> Download Full

      Utilizando O Timer0 Do Pic - Microcontrolandos >>>>> Download LINK

      >>>>> Download Now

      Utilizando O Timer0 Do Pic - Microcontrolandos >>>>> Download Full

      >>>>> Download LINK ij

      Excluir
  2. Boa tarde,

    Primeiramente gostaria de lhe dar os parabéns pela explicação, pesquisando, não encontrei nada nem mesmo similar. Muito bom!!!

    Infelizmente não estou entendendo muito bem a configuração do "optionreg" já li e reli o datasheet do pic16f877a mas ainda tenho duvidas sobre como delarar as variáveis do pre escale.

    Estou tentando fazer um led piscar com a funçar timer0, você poderia me auxiliar?

    ResponderExcluir
  3. Obrigado :)

    Cada bit do registro OPTION_REG tem uma função. os bits 2, 1 e 0 possui a função de configurar o prescaler. Então, caso OPTION_REG = 0B10000111, como os ultimos bits são 111, o prescaler será 1:256.

    para poder fazer um led piscar, você deve configurar TIMER0 no modo temporizador(bit 5). Atraves da formula dito acima, você calcula o tempo.

    Faz de conta que utilize um cristal de 4Mhz(ciclo maquina = 1us),precaler 1:128, e carregue o TMR0 como o valor 100; O perido será: 1 * 128 * (256 - 100) = 19968us = 20ms. O led piscara num intervalo de 20ms.

    O codigo ficaria assim:
    void main(){
    TMR0 = 100;
    OPTION_REG = 0B10000110;//como os ultimos bits sao 110, prescaler e 1:128.
    TRISB.F0 = 0;

    while(1){
    if(INTCON.TMR0IF==1){//flag de sinalizacao quando TMR0 e maior q 255
    PORTB.F0 = ~PORTB.F0;//pisca o led
    TMR0 = 100;//necessita carregar o TMR0, senao volta pra 0
    INTCON.TMR0IF=0;//limpa a flag
    }
    }
    }

    ResponderExcluir
    Respostas
    1. Nossa, que ágil a resposta hehehe...^^
      Com um exemplo tudo começa ficar mais claro, agora consegui associar a função de cada bit do "OPTION_REG". Li o Cap. 2 e 5 do datasheet mas faltava uma dica para unir a teoria com a pratica.
      A atividade que estou desenvolvendo pede que eu configure a fonte de clock com configuração do pre escaler 1:256 e que siga o seguinte algoritmo:

      configurar fonte de clock
      conf. pre escaler 1:256
      enquanto timer<15625 espere
      timer = 0
      acended lad
      enquando timer<15625, espere
      timer = 0
      apaga led

      O meu código encontra-se assim:

      void main() {

      TRISA=0b11111110; //Porta A têm o pino A0 configurado como "saída"
      OPTION_REG=0b10000111;

      for(;;)
      {
      while (TMR0<255) {
      TMR0=0;
      PORTA=0b00000000;} //Pino A0 libera "saída alta" (5V)
      while (TMR0<255) {
      TMR0=0;
      PORTA=0b00000001;} //Pino A0 libera "saída alta" (5V)
      }

      }

      Mas não funciona por nada hehehe.... alguma luz?

      Excluir
    2. Eu faria assim:
      void main() {
      TRISA = 0b11111110;
      OPTION_REG = 0b10000111;

      for(;;)
      {
      while (TMR0<255);
      TMR0 = 0;
      PORTA = 1;
      while (TMR0<255);
      TMR0 = 0;
      PORTA = 0;

      }
      }

      No seu codigo, dentro do while, vc carregou TMR0=0, como o TMR0=0 sera sempre menor q 255, nunca iria sair do loop.

      Excluir
    3. Entendi, eu havia criado uma função que nunca sairia do loop T_T... Farei apenas mais um questionamento, o que o algoritmo do problema que estou tentando resolver quer dizer com "... timer<15625...", pois, qualquer valor que entro, se maior do que 255, o programa não funciona como esperado.

      Excluir
    4. O módulo timer0 na verdade conta ate 255, pois possui um registro contador(TMR0) de 8 bits. Para o timer1, possui um registro de 16 bits(TMR1H/TMR1L) e pode contar até 65536.

      Excluir
    5. Muito obrigado pelas explicações, apesar de conceitos básicos, foram essenciais para clarear minha vida =)...

      Excluir
  4. Estou com uma duvida
    Estou tentando acender 4 leds um de cada vez com intervalo de 2segundos utilizando o pic 18f4520, porem ele só acende o primeiro?
    Oque estaria errado?


    void main() {
    int segundos = 0;
    trisb=0;
    portb=0;
    T0CON=0b10000110;

    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;

    while(1){

    if(segundos == 0 && INTCON.TMR0IF == 1){
    //porta = 0;
    portb.f0 = 1;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    segundos++;

    }else if(segundos == 1 && INTCON.TMR0IF == 1){
    portb.f0 = 0;
    portb.f1 = 1;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    segundos++;

    }else if(segundos == 2 && INTCON.TMR0IF == 1){
    portb = 0;
    portb.f2 = 1;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    segundos++;

    }else if(segundos == 3 && INTCON.TMR0IF == 1){
    portb = 0;
    portb.f3 = 1;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    segundos++;

    }else if(segundos == 4 && INTCON.TMR0IF == 1){
    segundos = 0;
    }else{
    portb = 0;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    segundos++;
    }
    }
    }

    ResponderExcluir
  5. Olá!
    Veja que no ultimo "else" voce incrementa a variavel segundos. como o intervalo do timer é de 2 segundos(eu acho) durante esse tempo, o pic ira executar esse "else" milhares de vezes, ou seja, a variavel incrementara milhares de vezes, e nunca sera 1,2,3 ou 4.

    simplifiquei seu codigo:

    void main() {
    int segundos = 0;
    trisb=0;
    portb=0;
    T0CON=0b10000110;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    while(1){
    if(INTCON.TMR0IF==1)
    {
    PORTB = (1 << segundos++);
    if(segundos==4) segundos=0;
    TMR0L=0XEE;
    TMR0H=0X85;
    INTCON.TMR0IF = 0;
    }
    }
    }

    ResponderExcluir
  6. Olá, minha dúvida a seguinte:

    Preciso de uma contagem de 0 a 20ms, ou seja, 0 a 20000us.

    Meu cristal é de 4MHz. Minha aplicação é com USB, então preciso de 48MHz. Consigo isso modificando o prescaler do clock. Mas esse prescaler é o mesmo do timer0?

    Outra coisa, o ciclo de máquina nesse caso seria:
    4/48=0.08333us

    O tempo de overflow é:

    T=ciclo de maq*prescaler*contagem

    20000=0.08333us*128*contagem

    Ta certo isso?

    ResponderExcluir
    Respostas
    1. Olá!
      O prescaler do PLL e do timer0 NAO é o mesmo.
      Vc teria q configurar o prescaler PLL para 1:1 e ativar o PLL.
      Depois vc configura o prescaler do timer0.

      A conta esta certinho!

      Excluir
    2. Olá Tiago, obrigado pela rápida resposta!

      Existe algum comando no MikroC (sou novato) para que eu possa pegar o valor atual de um timer? Quero dizer, eu quero fazer uma interrupção no timer e pegar o valor da contagem na hora dessa interrupção. No CCS existe o "get_timer0()", existe algo parecido no MikroC?

      Excluir
    3. Recomendo que você leia o datasheet do PIC q vc está utilizando.

      Na verdade não existe nenhum comando, você tem q pegar o valor de registro.
      Provavelmente, vc esta utilizando um timer de 16bits, entao voce tera q pegar o valor do registro TMR0H(8bits) e TMR0L(8bits);
      Exemplo:
      int valorDoTimer; //declara uma varivel do tipo int(16 bits)

      valorDoTimer = (TMR0H<<8) + TMR0L;//desloca 8 bits do TMR0H para esquerda e soma com TMR0L

      Excluir
  7. cara para fazer um programa que tenha um botão com duas funções por exemplo: se eu só o aperto ele faz alguma coisa tipo acende um led mas se eu o aperto e segura por meio segundo ele faz outra coisa. Como eu faço isso?? é com timer??

    ResponderExcluir
    Respostas
    1. Nesse caso, voce pode utilizar delay. Veja um exemplo:

      char funcao = 0;

      void main()
      {

      TRISB = 255;
      TRISC = 0;

      while(1)
      {
      funcao = 0;

      if(PORTB.F0==1)//botao pressionado
      {
      funcao = 1;
      delay_ms(500);

      while(PORTB.F0)// a cada 500ms, uma nova funcao ao botao
      {
      funcao++;
      delay_ms(500);
      }

      switch(funcao)//define uma acao para a funcao
      {
      case 1: PORTC = 1; break;
      case 2: PORTC = 2; break;
      case 3: PORTC = 4; break;
      default: PORTC = 0; break;
      }

      }
      }

      }

      Excluir
    2. vlw cara
      obrigado, me ajudou bastante, gosto muito do seu blog

      Excluir
  8. Olá Boa tarde!
    Encontrei este blog e achei-o muito bom, sendo em C e eu que estou a dar os passos em Mikrobasic.
    Estou a tentar fazer um contador de eventos para contar nº de voltas de uma base de uma paletelizadora e depois desenvolver todo o programa.
    parabéns.
    cump.
    Jorge

    ResponderExcluir
  9. Muito obrigado! Você me ajudou em um antigo problema!

    ResponderExcluir
  10. Primeiro queria dizer que essa página do seu blog é muito legal, li todos os posts e vc explica muito bem.
    Minha duvida com timer é a seguinte.
    Vejo que todo mundo faz um timer que faz alguma coisa alternada, ou seja, com uma base de tempo só. Ex: No seu programa a cada estouro do timer muda o estado de uma saida =~, ou seja, se o timer tiver estouro de 20ms, a cada 20ms a saida estará em nivel 1 e passados 20ms ela vai para nivel 0, assim se visualizarmos essa saida em um osciloscópio teremos um formato de onda quadrada e simétrica. Isso eu consegui, o meu problema é que eu quero uma interrupção assimetrica.

    Por exemplo, quero fazer um programa que fique 2ms em nivel 1 e 18ms em nivel 0, mas queria fazer isso através de uma variável e proporcional, quando um subir o outro desce, assim se o nivel alto se manter por 5ms o baixo se mantém por 15ms.

    Existe uma maneira de fazer isso?

    Outra coisa que percebi é que quando uso timer o delay_ms não funciona.

    ResponderExcluir
  11. Voce pode faz o seguinte:
    Define o estouro do timer para 1ms e...

    char i = 0, state = 0, var = 3;

    //1ms
    void interrupt()
    {
    if (TMR0IF_bit)
    {
    TMR0IF_bit = 0;
    TMR0L = 0x05;
    i++;
    if(i == (2 + var) && state == 0) //Depois de 2ms + var
    {
    PORTB.B0 = 0;
    i = 0;
    state = 1;
    }
    else if(i == (18 - var) && state == 1) //Depois de 18ms + var
    {
    PORTB.B0 = 1;
    i = 0;
    state = 0;
    }


    }
    }

    ResponderExcluir
  12. Obrigado por responder, testei esse código mas não funcionou.
    Você consegue fazer um timer que conte um estou a cada 2us com um oscilador de 8Mhz, no resto eu me viro, a minha maior dificuldade é o timer pois nunca trabalhei com timer antes.

    Obrigado.

    ResponderExcluir
    Respostas
    1. void Interrupt()
      {
      if (TMR0IF_bit)
      {
      TMR0IF_bit = 0;
      TMR0 = 251;
      //Seu código
      }

      void InitTimer0()
      {
      OPTION_REG = 0x88; //Prescaler 1:1
      TMR0 = 251;
      INTCON = 0xA0;
      }

      Excluir
  13. Obrigado mais uma vez por responder, mas está dando erro no TMR0 q eu depois declarei como variavel int, depois fica dando erro no InitTimer0.

    Este código devo colocar acima do void main() ?

    ResponderExcluir
  14. Respostas
    1. void Interrupt()
      {
      if (TMR0IF_bit)
      {
      TMR0IF_bit = 0;
      TMR0L = 0xFB;
      //Seu código
      }
      }

      void InitTimer0()
      {
      T0CON = 0xC8;
      TMR0L = 0xFB;
      GIE_bit = 1;
      TMR0IE_bit = 1;
      }

      void main()
      {
      InitTimer0();

      //Seu código
      }

      Excluir
  15. Opa Tiago, pode me dar uma força?

    Estou usando um Pic 12F675

    O programa que estou tentando criar funciona assim:

    Estou usando GP0 como entrada e GP2 como saida.

    Funciona assim:

    A saida GP2 fica em nivel 1.

    No momento que eu mudo o estado da entrada "GP0" atraves de um botão, depois de 5 minutos a saida vai a 0 e permanece assim por 5s e volta para "1".

    Até ai tudo bem, funciona, porém se eu antes dos 5 minutos deixar de pressionar o botão, não era mais pra acionar a saída, mas não é isso que acontece, mesmo assim a saída vai para "0".

    Pode me ajudar?

    ResponderExcluir
    Respostas
    1. vc tem o programa q vc esta fazendo.
      Eu nao entendi muito, se puder passar mais detalhes.

      Excluir
    2. Bom dia Tiago, obrigado pela atenção.

      Segue o programa.

      void main() {
      ansel = 0;
      cmcon = 7;
      trisio = 0x01;
      gpio = 0;

      while(1){
      if (GP0_bit == 0){
      GP2_bit = 0;
      }
      else{
      delay_ms (300000);
      GP2_bit = 1;
      delay_ms (5000);
      GP2_bit = 0;
      }
      }
      }

      Como sou novo no assunto, ainda não sei trabalhar com os timers e interrupções, meus programas são todos do nível acima, mas tô praticando, e te agradeço por perder tempo comigo. A lógica do programa tá invertida em relação ao que eu escrevi ontem, mas é só isso.

      Excluir
    3. Ah, esqueci,

      O problema que não consigo resolver é: se eu pressiono o botão(GP0_bit) e solto ele não deveria acionar a saída (GP2_bit), mas ele entra no looping de tempo, ai já era. Porque se eu solto o botão, antes dos 5 minutos, ele teria que interromper a contagem do tempo e zerar a contagem.

      Excluir
    4. void main()
      {
      unsigned i=0;
      ansel = 0;
      cmcon = 7;
      trisio = 0x01;
      gpio = 0;

      Label1:
      while(1)
      {
      if (GP0_bit == 0)
      {
      GP2_bit = 0;
      }
      else
      {
      while(GP0_bit && i < 30000)
      {
      delay_ms(10);
      i++;
      }
      if(!GP0_Bit)
      {
      i=0;
      GP2_Bit = 0;
      goto Label1;
      }
      GP2_bit = 1;
      delay_ms(5000);
      GP2_Bit = 0;
      i=0;
      }
      }
      }

      Excluir
    5. Thiago o que significa este Label 1 e o Goto Label?
      Muito obrigado.


































      Excluir
    6. A instruçao goto significa “ir para“. ela direciona o contador de programa do mcu para um endereço, no caso, para o label1, que é o inicio do “while“.

      Excluir
  16. Anderson, você quer que a saida permaneça em nivel 1 durante o tempo que o botão está pressionado ou vc dá um toque no botão e ele fica em nivel 1 por 5s e depois volta pra 0?
    Vi no seu programa que vc colocou um delay de 300.000ms, isso é igual a 300s. Assim qdo entrar no o programa vai manter o ultimo estado, que no caso é 0, por 300 segundos.
    Me diga o que extamente vc quer fazer que acredito que posso te ajudar.
    Se vc quiser mudar o status do que vc está fazendo, antes do tempo que vc está querendo programar, vc não deve usar delay, vc deve usar uma variável que vai contar um numero X e ela será o seu flag, assim vc pode interromper e alterar o status de alguma saída antes do tempo do delay.
    Acontece que o delay em alguns casos não é interessante pois ele trava o programa o resto do código até que o tempo daquela linha onde está o delay estoure.

    Ex.
    while(1){

    PORTB.RB1 = 1; //A saida RB1 irá pra nivel lógico 1
    delay_ms(1000); //RB1 permanecerá assim por 1s até que o microcontrolador leia a próxima linha
    PORTB.RB1 = 0; //Esta linha altera o estado para nivel 0
    delay_ms(20000); //A leitura do código ficará parada aqui até que os 20s desse delay estoure, só depois ele passará pra linha abaixo.
    PORTB.RB2 = 1;
    }

    ResponderExcluir
  17. Na verdade se a entrada for pra 1(botão pressionado), começa a contar 300s pra acionar a saida, porem se eu soltar o botão a saida deveria permanecer no mesmo estado.

    ResponderExcluir
  18. Olá! parabéns pelo tutorial. Só tenho uma dúvida. Se eu quiser usar um tempo de overflow de 1000us e um cristal de 4Mhz, qual o prescaler indicado? Pois estou tentando fazer aqui e sempre dá um tempo enorme de contagem.

    ResponderExcluir
    Respostas
    1. Olá! Obrigado!
      Você pode utilizar um prescaler 1:4 e TMR0 = 6;

      4 / 4MHz = 1us

      1us * 4 * (256 - 6) = 1000us

      Excluir
    2. Obrigado. O problema que estou tendo é que quando mudo o prescaler fica errado. Por exemplo, 4mhz, prescaler 1:8 e overflow de 1000us. 1us*8*(256 - 131) = 1000us com TMR0 = 131, mas quando coloco pra rodar o tempo não bate.

      Excluir
    3. Voce está fazendo assim? Lembre-se de recarregar o TMR0 sempre que houver um overflow. Se o TMR0 for recarregado com 0, não há necessidade de inseri-lo no código.

      void Interrupt()
      {
      //seu código
      TMR0 = 131;
      TMR0IF_Bit = 0;
      }

      void Main()
      {
      OPTION_REG = 0b10000010;
      TMR0 = 131;
      INTCON.GIE = 1;
      INTCON.PEIE = 1;
      INTCON.TMR0IE = 1;

      }

      Excluir
    4. valew Tiago!! Eu estava carregando o tmr0 fora da rotina de interrupção. Agora tá rodando redondo aqui.

      Excluir
  19. Olá Thiago, muito bacana sua explicação sobre o TMR0 mas li as respostas que você deu aos outros colegas e não encontrei uma solução para mim. Estou tentnado implementar um temporizador com o PIC16F628 de pelo menos duas horas, isso acionado por um LDR numa determinada porta. Pois bem, a questão do LDR até posso resolver depois mas já li muitos materiais sobre a manipulação do TMR0 do PIC mas todos acabam falando em acionamento por um segundo de um led, etc. Assim, gostaria de alguma ajuda com esse cálculo para um período maior, caso possa fazê-lo. Obs.: uso CCS e minha pequena base de programação é C ANSI. Grande abraço e tudo de bom. Sandro

    ResponderExcluir
    Respostas
    1. #include <16F628A.h>
      #device adc=8
      #FUSES NOWDT,XT
      #use delay(clock=4000000)

      int32 time=0;
      #int_RTCC
      void RTCC_isr(void) //1000us
      {
      time++;
      if(time == 7200000)
      {
      output_toggle(pin_b0);
      time = 0;
      }
      }

      void main()
      {
      setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);
      setup_timer_1(T1_DISABLED);
      setup_timer_2(T2_DISABLED,0,1);
      enable_interrupts(INT_RTCC);
      enable_interrupts(GLOBAL);
      set_timer0(6);
      set_tris_b(0x00);
      time =0;
      while (TRUE)
      {

      }
      }

      Excluir
    2. Calculo:
      1us * 4 * (256 - 6) = 1000us

      2horas = 120min = 7200 seg == 7200000ms

      Excluir
    3. Salve Tiago!! Estudo completo, hein? (pelo menos com o setor #### eu devia me virar sozinho (rss..).
      Valeu mesmo, seu algoritmo vou guardar prá sempre porque a explicação é perfeita e servirá de base para outros pequenos projetos de final de semana por aqui (ou de um ano inteiro, kkk). Grande abraço e tudo de bom. Sandro.

      Excluir
    4. pq foi usada uma variavel time do tipo inteira de 32 bits? Poderia ser do timpo inteira de 8 bits?

      Excluir
  20. Tiago, preciso de ajuda com o timer0, mas é para o pic12F675. Preciso fazer um temporizador que fique ligado por 168 horas seguidos, e após este tempo desligar. O programa é inicialmente simples, o problema está na precisão, pois como o tempo é longo, o acumulo de pequenos erros na temporização acaba atrapalhando o resultado final. Você pode me ajudar na questão de precisão desse temporizador ? Agradeço se me der uma ajuda.

    ResponderExcluir
    Respostas
    1. No seu caso poderia utilizar um cristal de 32768Hz.
      Irei fazer um post sobre este assunto!!
      Até mais!!

      Excluir
    2. Valeu Tiago. A resposta veio rápido vai me ajuda muito. Obrigado e parabéns pelo material disponível no blog.

      Excluir
  21. Tiago Você conhece mesmo o pic e o mickroc.
    você poderia me ajudar a sincronizar com a rede eletrica.
    assim um pino fica gerando onda quadrada a 60Hz atraves de um temporizador.
    uma chave fica aberta e conecta um pino contador um sinal externo que varia de 57Hz a 63Hz, quando isso acontece o pino que gera os 60Hz tem que ir de 60Hz suavemente para a frequencia que está entrando nesse pino contador, caso abra a chave o pino que gera o clock deve voltar suavemente para 60Hz, olha já quebrei a cabeça mas é complicado. eu programo com o CCS

    ResponderExcluir
  22. Por favor, preciso fazer um temporizador com o PIC 18F4520, porém não estou conseguindo. Preciso selecionar no display LCD, por meio de um botão, a função TEMPO, que faz a contagem, em segundos, para o acionamento de um motor. Quando a função TEMPO é selecionada será necessário informar o tempo que o motor irá ser acionado. Por exemplo: Preciso que o motor entre em funcionamento após 5 segundos, assim eu selecionaria a função TEMPO no display LCD e incrementaria por meio de um botão, até aparecer o número 5, dessa forma após 5 segundos o motor seria acionado.

    Muito obrigado

    Thiago

    ResponderExcluir
  23. Olá Thiago, gostei muito da sua explicação sobre o TMR0, uso o ccs e estou tentando fazer um temporizador com o PIC16F628a que fique um Led ligado por 6segundos e desligado por 2 horas por uma determinada porta, sempre assim com loop, mas não encontro nada sobre esse tipo de temporizador infinito por horas, apenas segundos preciso de ajuda com esse cálculo para um período maior, pode me ajudar? fico grato por sua ajuda e parabéns pelo blog.

    ResponderExcluir
  24. Olá Thiago,
    Cara, estou com um projeto que que seria mais ou menos assim:
    Tenho um dispositivo que faz um movimento e fica parado "x" segundos (regulado em um temporizador ). Após isso um segundo temporizador faz o mesmo durante "xx" segundos .
    Esses dois movimentos desse dispositivo, gerariam "X" + "XX" segundos , que automaticamente me dariam "Z" quantidades por hora.
    Ex: 1segundo + 2 segundos = 60 minutos / 3 segundos = "Z" quantidades por minuto * 60 minutos= 1200 por hora.
    Não estou conseguindo resolver isso.
    Se por possível me ajudar !!!

    Abraço !

    ResponderExcluir
  25. Olá Thiago,
    Cara, estou com um projeto com PIC 16f877a que seria mais ou menos assim:
    Tenho um dispositivo que faz um movimento e fica parado "x" segundos (regulado em um temporizador ). Após isso um segundo temporizador faz o mesmo durante "xx" segundos .
    Esses dois movimentos desse dispositivo, gerariam "X" + "XX" segundos , que automaticamente me dariam "Z" quantidades por hora.
    Ex: 1segundo + 2 segundos = 60 minutos / 3 segundos = "Z" quantidades por minuto * 60 minutos= 1200 por hora.
    Não estou conseguindo resolver isso.
    Se por possível me ajudar !!!

    Abraço !

    ResponderExcluir
  26. Ola, Thiago
    Estou com um projeto que vai ter varias rotinas no lcd, estou usando um pic 18F452, so que eu acho que ele nao vai suportar a memoria. o que vc me diz uso uma externa ou tem alguma rotina pra minizar a memoria.

    ResponderExcluir
  27. Olá,Thiago.
    Muito boa a sua explicação sobre os timers,mas preciso de sua ajuda.Preciso fazer um contador de pulsos que conte um determinado numero de pulsos que eu determinarei,por exemplo 10 pulso, sendo que isso só pode acontecer depois de acionado um botão,isto feito deverá acionar duas porta: uma com 200 ms e outra acionada direta.

    ResponderExcluir
  28. Como saber o prescaler e como configurar para estourar a cada 1ms

    ResponderExcluir
  29. Olá!
    Não poderia passar por aqui sem deixar o meu agradecimento e os parabéns pelos responsáveis por esse blog, que foi uma ajuda incrível para minhas dúvidas. Infelizmente materiais assim ainda são escassos na internet.
    Ótima Iniciativa, continuem!

    ResponderExcluir
  30. Olá Thiago blz, preciso de uma pequena ajuda com botões, 16 botões que tem a seguinte função:
    cada botão seleciona 1 de cada 3 caracteres do alfabeto e imprime em um lcd 16x2, porem se crio condições de tempo ou por clicks para cada função de um botão o ciclo do while() faz com o lcd fique imprimindo varios dos caracteres e preenchendo todo o lcd sem parar.

    exemplo:

    Se botão 1 pressionado durante 500ms e solto imprime caracter "A" se 1000ms e solto imprime caracter "B"
    isso por condição de tempo

    por clicks seria se botão 1, um click caracter "A" e se dois carater "B"

    Poderia me dizer se e possivel eu criar uma rotina em que se o botão pressionado durante um tempo,
    ex: 1000ms ele fica selecionando os três caracteres e assim quando aparecer o caracter que quero solto o botão e imprime no lcd.

    Estou usando o compilador mikroc e o pic16f877, segue 1 ex do código que estou usando para esta função.
    Ja tentei de varias outras formas mas o lcd imprime sem parar, o objetivo e criar uma interface para entrada de senhas em um circuito para armar um alarme ou desarmar, o codigo para o alarme ja tenho
    em mente mas a dificuldade e no menu, ums dos códigos que criei faz a função de selecionar por meio de condição de tempo um dos caracteres e imprimir no lcd mas não da para calcular o tempo certo que o botão deve ser pressionado imprimir o caractere escolhido, segue o código do mesmo no 2 ex.

    ResponderExcluir
  31. Ex 1:

    // LCD module connections
    sbit LCD_RS at RB4_bit;
    sbit LCD_EN at RB5_bit;
    sbit LCD_D4 at RB0_bit;
    sbit LCD_D5 at RB1_bit;
    sbit LCD_D6 at RB2_bit;
    sbit LCD_D7 at RB3_bit;

    sbit LCD_RS_Direction at TRISB4_bit;
    sbit LCD_EN_Direction at TRISB5_bit;
    sbit LCD_D4_Direction at TRISB0_bit;
    sbit LCD_D5_Direction at TRISB1_bit;
    sbit LCD_D6_Direction at TRISB2_bit;
    sbit LCD_D7_Direction at TRISB3_bit;
    // End LCD module connections

    bit oldstate; // Old state flag

    char txt1[] = "A";
    char txt2[] = "C";
    char txt3[] = "D";
    char txt4[] = "E";
    char txt5[] = "F";
    char txt6[] = "G";
    char txt7[] = "H";
    char txt8[] = "I";
    char txt9[] = "J";
    char txt10[] = "K";
    char txt11[] = "L";
    char txt12[] = "M";
    char txt13[] = "N";
    char txt14[] = "O";
    char txt15[] = "P";
    char txt16[] = "Q";
    char txt17[] = "R";
    char txt18[] = "S";
    char txt19[] = "T";
    char txt20[] = "U";
    char txt21[] = "V";
    char txt22[] = "W";
    char txt23[] = "X";
    char txt24[] = "Y";
    char txt25[] = "Z";
    char txt26[] = "0";
    char txt27[] = "1";
    char txt28[] = "2";
    char txt29[] = "3";
    char txt30[] = "4";
    char txt31[] = "5";
    char txt32[] = "7";
    char txt33[] = "8";
    char txt34[] = "9";

    char txt35[] = "entre com senha";
    char txt36[] = "senha correta";
    char read [] = "RISEHANDS";

    //------------------//

    void main(){

    ADCON1=0x0F; //Configura analógios
    ADCON1=0x0F;
    CMCON|=0x07; //Desliga comparadores

    trisa=0;
    trisb=0;
    trisc=1;
    trisd=1;
    trise=0;
    porta=0;
    portb=0;
    portc=0;
    portd=0;
    porte=0;

    oldstate = 0;


    Lcd_Init();
    Lcd_out(1,1,txt35);
    delay_ms(3000);
    Lcd_Cmd(_LCD_BLINK_CURSOR_ON);
    delay_ms(500);
    Lcd_Cmd(_LCD_CLEAR);
    Lcd_Cmd(_LCD_RETURN_HOME);

    oldstate = 0;


    while(1){

    if (portd.RD0 == 1, // Detect logical one
    delay_ms(500),
    oldstate == 0){
    Lcd_out_CP("A");
    }

    if (portd.RD0 == 1, // Detect logical one
    delay_ms(1000),
    oldstate == 0){
    Lcd_out_CP("B");
    }

    Delay_ms(10);

    }

    }

    ResponderExcluir
  32. Ex 2:

    while(1){

    if (portd.RD0 == (1, 0, 1)){
    delay_ms(500); // Detect logical one
    Lcd_out_CP("A");
    }

    if (portd.RD0 == (1, 0, 1)){
    delay_ms(1000); // Detect logical one
    Lcd_out_CP("B");
    }

    Delay_ms(10);

    }

    }

    O circuito a seguir:

    ResponderExcluir
  33. 1 * 128 * (256 - 100) = 19968us = 20ms. como que o 19968 é igual a 20ms

    ResponderExcluir
    Respostas
    1. Nao tem como obter um tempo exatamente igual a 20ms. Único jeito é aproximando...

      Excluir
  34. Boa noite, teria como me ajudar nessa questão ?

    Exemplo: Quero fazer um led piscar permanecendo aceso durante um segundo e apagado durante um segundo. No meu sistema embarcado tenho cristal que gera um clock de 1Mhz. Meu timer é de 16 bits. Escolha um valor de pescaler e ache até quanto o timer deve contar para que eu possa criar uma rotina que o led possa picar da maneira que eu desejo.

    ResponderExcluir
  35. Olá Thiago muito bom seu blog, é grande ajuda, parabéns pela iniciativa.
    Se puder me ajudar?
    Tenho um sensor de umidade (grove), e tenho que fazer uma programação em um PIC18F4520, que quando o solo estiver umido mande um sinal ao pic que o faça ligar uma bomba de água, quando o solo estiver em níveis normais fique parado e quando o solo estiver bem molhado desligue a bomba.
    Desde já agradeço, e novamente parabéns pelo blog.

    ResponderExcluir
  36. Boa tarde, será que me podiam ajudar nesta questão?

    Qual o valor com que se deve inicial o TIMER0 do pic18 para obter um overflow em 175ms. Suponha que utiliza um cristal de 20MHZ e um prescaler de 1/64.

    a) 54688
    b) 13672
    c) 51863
    d) Nenhuma das anteriores

    Sei que a resposta certa é a "c", mas gostava de perceber como chegar ao valor.

    Desde já, obrigado.

    ResponderExcluir
    Respostas
    1. Boa tarde.
      Como o TIMER0 do PIC18F é de 16 bits entao vai contar até 65535 e estourar no proximo tick. Utlizando a formula lá no post, T = ciclo * prescaler * ( 65536 - valor inicial ), vamos isolar a incognita 'valor inicial', entao vai ficar assim: valor inicial = 65536 - ( T / ( ciclo * prescaler ) ). Jogando os valores, valor inicial = 65536 - ( 175000us / 0.2us * 64 ) = 51864.

      Excluir
    2. Muito muito obrigado! Excelente blog, parabéns!

      Excluir
    3. Obrigado.
      Pra nao ficar preso as formulas, voce poderia pensar no seguinte: Dentro de um intervalo de tempo (T1), neste caso, 175ms, há varios subintervalos (T2), que é o tempo de cada tick, ou seja, ( ciclo * prescaler = 0.2 * 64 = 12,8us ), pra saber quantos T2 são necessarios, é so fazer T1 / T2 = 175000us / 12.8us = 13672 subitervalos. Agora e só subtrair 13762 de 65536, que vai dar 51864.

      Excluir
    4. Mais uma vez, muito obrigado! Sem querer "abusar" nem sobrecarregar, apenas se tiver tempo e disponibilidade. Será que me podia dar umas luzes neste problema?

      Imagine que ocupa o cargo de engenheiro de sistemas numa empresa que se
      dedica ao desenvolvimento de hardware. Um cliente pretende desenvolver um sistema
      para monitorização do nível de água existente num depósito, baseado num microcontrolador.
      O sensor utilizado apresenta como saída um sinal analógico com tensões
      que podem variar entre os 2 e 3V estando esta gama de tensões associada linearmente
      à capacidade do depósito (i.e. 0 a 100%). Desenhe um diagrama de blocos
      correspondente ao sistema que sugere implementar e descreva-o detalhadamente.
      Quais os módulos existentes num microcontrolador que sugere utilizar? Que técnicas
      de programação recomenda, e porquê? Justifique.

      Excluir
    5. E se eu configurasse o timer0 com 8 bits?? como ficaria?

      Excluir
  37. Olá Thiago, sera que vc pode ajudar em uma questão?
    Estou fazendo um TCC onde haverá um alarme por ldr no jardim pegando 4 pontos, e pontos de luz no jardim quando escurecer, isso usando o pic16F628, o alarme tem que tocar por 2min com intervalo de30 seg.

    ResponderExcluir
  38. Parabéns pelo excelente material e obrigado por compartilhar esse conhecimento!

    ResponderExcluir
  39. Olá,

    é possivel gerar uma interrupçao por timer, passando 1 hora?

    ResponderExcluir
  40. Olá Thiago, excelente consulta esse seu blog. Gostaria que por gentileza você me ajudasse com uma dica.

    Estou querendo calcular o fator de potência da rede. Para isso é necessário os sinais analógicos de tensão e corrente. Entretanto para que eu possa amostrar o sinal eu devo fazer meus cálculos de forma discreta para que eu possa pegar cada pedaço do sinal analógico. Pois bem, para que eu possa determinar o time de amostragem do meu sinal discretizado no pic, você pela sua experiência acha melhor eu utilizar o timer0 ou simplesmente aplicar o delay? a frequencia de rede é 60Hz e o meu sinal amostrado será de 960Hz, ou seja, ele irá me informar uma amostra do sinal a cada (1/960) = 1.04 ms.. como eu poderia aplicar o timer0 nesse caso?

    ResponderExcluir
  41. Não estou conseguindo fazer calculo de tempo:
    estou usando cristal 4Mhz, Pic 16f628A, precisava de um tempo de 5 segundos

    ResponderExcluir
  42. Bom dia, eu preciso controlar uma sinaleira simples com PIC PIC16F877A, utilizando o TIMER 0, fazendo o seguinte: sendo que o verde deverá permanecer aceso durante 3 segundos, o amarelo durante 1 segundo e o vermelho durante 3 segundos, lembrando que o processo se repetirá indefinidamente. Pode me ajudar?

    ResponderExcluir
  43. Um microcontrolador PIC está utilizando um clock externo de 4 MHz. O temporizador TIMER0 foi configurado para um prescaler de 256. Qual o intervalo de interrupção do TIMER0?


    0,256 milissegundos.


    65,536 milissegundos.


    16,384 milissegundos.


    Impossível calcular.


    1,024 milissegundos.

    ResponderExcluir
  44. Estou achando 16,67 segundos e não tem nenhuma alternativa com esse valor !
    Poderia me ajudar

    ResponderExcluir
  45. Olá, eu li o post inteiro porem n vi uma solucao de como criar uma base de tempo usando o timer0 do CCS para que gere um sinal de 50hz na saída. Obs: O pic usado é o 18f4550 topado, ou seja clock do cpu em 48MHz. Por favor me ajudem!!


    ResponderExcluir
  46. boa tarde , alguem pode me ajudar, tenho que montar um circuito com pic, com uma entrada de bot aonde acione os dois reles com tempo programavel por mim ,tipo um micro chave possa aumentar ou diminuir o tempo de atracado,sendo que o tempo de um rele fique o dobro do outro.EX: Isto é assim que presionar o botão BOT se colocar 10 minutos no tempo um rele ficara atracada por esse tempo e o outro automaticamente ficara atracado por 20 minutos ,ou tb que eu programe o tempo individual ( o mais facil)meu email marcosj_soares@hotmail.com, obrigado pela atenção marcos soares

    ResponderExcluir
  47. Ola! pessoal estou precisando de uma ajudinha ai com o tmr0 do pic16f877a
    estou montando um projecto e preciso que uma variavel guarda o tempo porque irei usar mais tarde este tempo para calcular a energia e preciso mostrar o tempo contando no LCD...

    ResponderExcluir
  48. Olá,

    Copiei o código e adaptei para testar no MPLAB com PIC16F628A e o LED apenas acende e não apaga, não estou conseguindo entender o porque, na contagem ele respeita o tempo para acender, mas uma vez ligado não desliga mais. Alguma ideia do que pode ser?

    ResponderExcluir
  49. Ola pessoal!! Preciso fazer um temporizador com timer0 que começe em 0hz e vá até 20000hz, como faço para controlar as interrupções para incrementar e decrementar essa frequência ? Qual o preescaler mais indicado para esse caso ?

    ResponderExcluir
  50. Sobre o temporizador de 0 a 20000 Hz que citei, quero acrescentar mais algumas informações para que alguém possa me ajudar, estou usando a linguagem ccs e o pic que estou utilizando é o 16f628A com um clock interno de 4MHZ para o timer0. Um dos problemas que estou tendo é que não consigo iniciar a frequência de 0HZ.

    ResponderExcluir
  51. Olá, parabéns pelo blog!
    Estou tendo um problema, estou usando o MPLAB linguagem C.
    Quando eu coloco OPTION_REG ele gera um erro na compilação, comecei a incrementar o timer0 e no início deu esse erro:

    *** Error 48 "codigo.c" Line 47(12,22): Expecting a (
    *** Error 43 "codigo.c" Line 47(14,25): Expecting a declaration
    *** Error 43 "codigo.c" Line 47(25,26): Expecting a declaration

    Se alguém ou o moderador poder me ajudar eu agradeço.
    Segue o código.

    #include <16F877a.h> //Define o modelo do microcontrolador

    // Fusíveis de configuração do microcontrolador


    #FUSES NOWDT //Sem Watch dog, evitando reset
    #FUSES BROWNOUT //Resetar quando detectar brownout (Quando a tensão cair abaixo do previsto no datasheet)
    //#FUSES HS //Crystal de oscilação > QUE 4mhz
    #FUSES XT //Crystal de oscilação de 4mhz
    #FUSES PUT //Tempo de início do PIC
    #FUSES NOPROTECT //Codigo sem proteção de leitura, software livre!
    #FUSES NODEBUG //Verifica se tem erros bo código (desabilitado)
    #FUSES NOLVP //No low voltage prgming (prog. baixa voltagem desabilitado), B3(PIC16) or B5(PIC18) used for I/O
    #FUSES NOCPD //No EE protection (Sem travar o chip)

    #use delay(clock=4000000) //Define o cristal utilizado


    //***************************************** LCD *****************************************
    //Definição de entradas e saídas
    //Cada bit representa um pino físico de I/O
    // 0 significa que o pino será uma saída
    // 1 significa que o pino será uma entrada
    #define trisa 0b11111111
    #define trisb 0b00000000


    // Estas são as definições dos pinos que o LCD utiliza.
    // Definem quais pinos do PIC controlarão os pinos do LCD

    #define lcd_enable pin_a1 // pino enable do LCD (E)
    #define lcd_rs pin_a0 // pino rs (register select)do LCD (RS)
    // (0) para comandos (1) para dados
    //O pino RW vai no negativo.
    #define lcd_db4 pin_b4 // pino de dados d4 do LCD
    #define lcd_db5 pin_b5 // pino de dados d5 do LCD
    #define lcd_db6 pin_b6 // pino de dados d6 do LCD
    #define lcd_db7 pin_b7 // pino de dados d7 do LCD

    #include //declaração da biblioteca do LCD
    //***************************************** LCD *****************************************




    //***************************************** TIMER0 *****************************************
    OPTION_REG = 0b100000001; //Pag. 23 - Explicação em 11:34 link: https://www.youtube.com/watch?v=K81eMwKZYYw&t=938s
    //Conversor: http://www.calculadoraonline.com.br/conversao-bases
    //Em binário: 0b10000001 = 0x81
    //Configura o prescale em 1:4


    //***************************************** TIMER0 *****************************************



    //Programa principal
    void main(){



    inicializa_lcd(); //Inicializa o LCD

    while(1){

    //delay_ms(10);
    limpa_lcd(); //Limpa o display do LCD
    output_high(pin_b3); //Liga o Led testando a saída do pino
    caracter_inicio(1,1); //Define o caracter de inicio da escrita
    printf(escreve_lcd,"TESTE LCD"); //Escreve no LCD
    caracter_inicio(2,1); //Define o caracter de inicio da escrita
    printf(escreve_lcd,"Linha 2"); //Escreve no LCD
    //output_low(pin_b3); //Desliga o Led
    //delay_ms(5000);

    }
    } //fecha void main

    ResponderExcluir
  52. Utilizando O Timer0 Do Pic - Microcontrolandos >>>>> Download Now

    >>>>> Download Full

    Utilizando O Timer0 Do Pic - Microcontrolandos >>>>> Download LINK

    >>>>> Download Now

    Utilizando O Timer0 Do Pic - Microcontrolandos >>>>> Download Full

    >>>>> Download LINK

    ResponderExcluir