Páginas

quarta-feira, 4 de julho de 2012

Como utilizar o timer ( microcontroladores PIC )


A grande jogada dos timer's, em um microcontrolador, é que você não precisa manter o processador travado em delay aguardando o momento de realizar uma função. Em alguns casos, sem o uso de timer's, seria quase que impossível de realizar determinadas tarefas em conjunto (controle de servo motores por exemplo).
A ineficiência do delay, em alguns casos, pode ser comparada a uma pessoa que tem compromissos durante o dia só que, ao invés de olhar no relógio ou usar um despertador, a pessoa fica parada só contando os segundos até chegar o momento dela realizar determinada tarefa (almoçar, trabalhar, etc.) desperdiçando tempo que poderia ser gasto com outras tarefas.

Os timer's são registradores que servem como contadores em que, a cada pulso de clock, ele realiza um incremento nesse registrador (timer = timer + 1 ou timer++). Após o timer incrementar até o seu valor limite (que depende da quantidade de bits do timer que você esta utilizando) ocorre o que chamamos de "estouro de contagem", este então é zerado e é acionada a interrupção.
Especificamente:



TIMER0
O timer0 é um timer de 8 bits, logo, ele pode armazenar até o numero 256.
O timer0 vai começar a incrementar a partir do zero (ou valor que você programar) e quando ele estiver com o valor 256 e passar para 257 (valor que não cabe em 8 bits) ocorre um "estouro" de contagem. Após isso, o flag de interrupção do timer0 é setado e o timer é zerado, começando assim um novo ciclo de contagem.

TIMER 1
O timer1 é um timer de 16 bits, logo, ele pode armazenar até o numero 65.536.
O timer1 vai começar a incrementar a partir do zero (ou valor que você programar) e quando ele estiver com o valor 65.536 e passar para 65.537 (valor que não cabe em 16 bits) ocorre um "estouro" de contagem. Após isso, o flag de interrupção do timer1 é setado e o timer é zerado, começando assim um novo ciclo de contagem.



A entrada de clock utilizada para incremento do timer pode ser configurada da seguinte forma.
Interno:
O clock do oscilador ( cristal ) utilizado no microcontrolador é dividido automaticamente por 4, ou seja, se o oscilador utilizado pelo seu microcontrolador for de 4 MHz o clock utilizado para a contagem do timer será de 1MHz ( 4.000.000 / 4 = 1.000.000).
Externo:
O clock é gerado a cada mudança de estado do sinal externo(proveniente dos pinos para essa finalidade). O incremento pode ser configurado para a borda de subida ou borda de descida.

Em seguida, esse clock passa por um prescaler programável antes de chegar aos timer.
O prescaler funciona como um divisor de frequência de 8 bits em que o valor que você carregar nele, que deve ser multiplos de 2, funcionará como o fator de divisão, ou seja, você pode dividir o sinal de entrada no prescaler em até 256 vezes.
Exemplo:

Sinal de entrada ou Oscilador utilizado = 8.000.000 (8 MHz)
Clock que chega ao prescaler = 4.000.000 (4MHz)              // valor do cristal dividido por 4
Valor programado no prescaler = 128                                   // valor que foi escolhido
Frequência que sai do prescaler = 31.250 ( 31,250 KHz)     // ou um pulso a cada 32 microsegundos


E finalmente, o sinal que sai do prescaler, chega ao seu registrador contador que, no caso, é o próprio timer.
O timer sera incrementado conforme a frequência do clock que chega até ele e, quando ocorre o estouro, ele será zerado e gerará uma interrupção.
Exemplo:

Oscilador utilizado = 4.000.000 ( 4MHz)
Clock que chega ao prescaler = 1.000.000 (1MHz)          // valor do cristal dividido por 4
Valor programado no prescaler = 64                                // valor que foi escolhido
Frequência que sai do prescaler = 15.625 (15,625KHz)  // ou um incremento a cada 64 microsegundos
Tamanho do timer = 256 ( 8bits )                                     // valor máximo que o contador suporta
Valor carregado no timer = 0                                           // valor que foi escolhido
Tempo das interrupções = 16,384 milisegundos (16,384 ms) // a cada 16,384 ms ocorre uma interrupção


O valor que esta presente no registrador pode ser alterado por você durante a execução do programa. Por exemplo, se o timer suporta até o numero 256 e você escrever um valor aleatório (porém menor que 256) nesse registrado, o contador passará a incrementar a partir do valor que você carregou nele. Assim você adiantará a interrupção, tornando-a mais rápida.

Se você precisa de um tempo maior para realizar determinada tarefa(1 segundo por exemplo), o método é criar um sistema via software que imite um relógio. Por exemplo: a cada interrupção faça o incremento de uma variável x, se x for igual a y faça determinada tarefa.

Agorá que você entendeu ( pelo menos espero que sim ^^" ) o que é e como funciona o timer, vamos aos códigos .

O exemplo abaixo utiliza um pic 16f628a e faz um led ligado ao pino a0 piscar a 1Hz utilizando o timer0 :

__________________________________________
#include <16f628a.h>                                // Microcontrolador utilizado
#use delay(clock = 4000000)                      // Cristal de 4MHz utilizado
#fuses intrc_io, nowdt, nomclr, put,nolvp      // Fusiveis

#int_timer0                             // é para cá que o seu programa será desviado quando ocorrer a interrupção
void trata_timer0 ()                 // método para tratamento da interrupção
{
  int1 teste;                                // variável de 1 bit com nome led
  int x;                                     // variável de 8 bits com nome de x
  set_timer0(131+get_timer0()); //escreve o numero 131 + o que se passou no timer0
  x++;                                    // incrementa x
  if (x == 62)                         // se x for igual a 62 , ou seja, se já tiverem passado 500ms
  {
   x = 0;                                // x será igual a zero
   teste = !teste;                         // inverte o estado de teste (se for 1 será igual a 0 e vice versa)
   output_bit (pin_a0, teste);    //coloca o valor de teste no pino a0
 }
}

void main ()
{
 setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_64 );  // timer0 com clock interno e dividido por 64
 set_timer0(131);                                         // carrega o valor 131 no registrador do timer
 enable_interrupts (global | int_timer0);         // habilita interrupções e libera o timer0
 while (true);                                                // loop infinito aguardando a interrupção para trata-la
}
__________________________________________

Timer0 :
#int_timer0
setup_timer_0 ( RTCC_"INTERNAL ou EXTERNAL" | RTCC_DIV_ xx ) ;
enable_interrupts ( global | int_timer0) ;
set_timer0 ( "valor") ;
get_timer0 ( ) ;

Timer1:
#int_timer1
setup_timer_1 ( T1_"INTERNAL ou EXTERNAL" | T1_DIV_BY_xx ) ;
enable_interrupts ( global | int_timer1 ) ;
set_timer1 ("valor") ;
get_timer1 ( );



Vale ressaltar que os timers também têm outras funções alem de servirem como temporizadores, mas isso veremos em um outro post.

Qualquer duvida é só postar nos comentários ;D .

2 comentários: