Para que serve e como utilizar o TIMER0 – PIC16F874A

ScreenShot

Chip utilizado: PIC16F874A 

Linguagem: Mikroc

Circuito: Ligação básica da PIC com um XTAL de 20 Megahertz, configuração para interfacear com um LCD de 16 posições, o mais comum do mercado, e uma saida configurada para acender um Led. 

Se você ainda não tem experiencia com circuitos básicos envolvendo PICs, tais como, acendimento de Leds, LCDs, Displays de 7 Segmentos, entrada analógica, interfaces I2C, então, este post não é para você, sugiro não gastar muito tempo nele, no máximo efetuar um CTRL D em seu browser, e voltar aqui quando tiver feito as coisas acima.

Objetivos: Explicar para que serve ecomo funciona a fução TIMER (TIMER0, 1,2) do PIC (neste caso tomando como exemplo o PIC16F874A), e como efetuar uma configuração básica utilizando esta função.

Problema como a função Delay:  Para contar o tempo em um circuito com PICs, poderiamos inicialmente pensar em utilizar funções em MikroC do tipo Delay(), porém ela tem um problema, pois ao utiliza-la, o processador interrompe qualquer outra atividade, e só retoma a próxima linha do programa após o final da execução desta função. Este problema não ocorre se utilizarmos as funções de TIMER da PIC, sendo que neste caso, é possivel efetuar a contagem sem interromper o programa principal.

Como contar o Tempo:  O TIMER0 é um contador de 8 bits (conta de 1 a 256), incrementando 1 a cada ciclo de máquina, mais abaixo veremos os cálculos para mensuração do tempo, por enquanto, basta entender que a cada ciclo interno do processador, o TIMER0 incrementa 1, e chegando a um valor de 256, o timer retorna para zero, gerando o que chamamos de “estouro”.

Ao gerar este “estouro”, o TIMER0 pode ser confurado para executar a função padrão de interrupção da PIC, também chamada de interrupção TMR0, fazendo o programa executar as intruções em C colocadas nesta função. (O exemplo mostrará bem como funciona). De novo, ele faz essa contagem sem parar o programa principal da PIC.

Outras Opções do TIMER: O TIMER pode ser configurado para fazer a contagem NÃO pelo ciclo de processador interno, mas por uma fonte externa de clock (bit de subida e descida), a ser ligado em um pino especifico da PIC. O programa exemplo mostra a configuração deste bit no registro do TIMER0 para definir a fonte de contagem, neste caso interna. Esta maneira de funcionamento pode ser utilizada em um contador de peças por exemplo, ou qualquer outro circuito que gere um clock digital externo.

O que difere o TIMER0 dos demais Timers (TIMER1, 2) são detalhes complementares, tais como, forma de contagem, numero de bits, geração de interupções, tipo de incrementação. Sendo que o TIMER0 seria o mais simples para aprendizado.  Por exemplo o TIMER1 em geral possui 2 bits de contagem, elevando o nivel de precisão da mesma, Enquanto o Timer0 vai até 256 (2 elevado a 8), o Timer1 conta ate 2 elevado a 16.

Prescaler: A função de prescaler pode ser ligada, desligada, e configurada para o TIMER0, sendo que ela nada mais é que um divisor, que dividirá um ciclo do processador por um valor fixo, que pode ser 1,2,4,8,16,32,64,128 ou 512).  Sendo assim, por exemplo, se o Prescaler for configurado para 4, ao invés do TIMER0 incrementar 1 a cada ciclo de máquina, ele irá incrementar 1 a cada 4 ciclos de máquina. Tão simples quanto isso. Com isso podemos aumentar o tempo de estouro, aumentar a contagem é bastante util devido ao baixo valor de tempo que um ciclo de processador tem. (mais abaixo exemplos do calculo).

Outros métodos de aumentar o tempo de contagem: É comum para aumentar o tempo de contagem, adicionar uma variável numerica no programa em C, sendo que a cada estouro do TIMER0, e consequente execução da função de interrupcao(), a variavel pode ser incrementada. Sendo que no programa principal pode-se tratar esse valor da variável, de novo o exemplo mostrará. Outro método seria alimentar a variavel com um valor fixo pré calculado, fazendo-a contra 1 segundo, 1 milisegundo, etc.

Lógica de Cálculo para estimativa de tempo de contagem para este exemplo: 

Ciclo basico do processador  (t) = 1/(frequencia do XTAL /4) = 1 / (20.000.000/4) = 0,0000002 ou 0,2 µ s.
Obs: O ciclo interno  do processador corresponde ao valor da frequencia do XTAL dividido por 4.

Tempo de estouro sem prescaler (T) = (t) * 256 = 51,2 µ s.

Tempo de estouro com prescaler de 4 (por exemplo)
 (T4) = (t) * 256 * 4 = 204,8 µ s.
O prescaler multiplica o ciclo interno por um valor fixo, aumentando o tempo de contagem para cada ciclo.

Exemplo de calculo utilizando uma variável unsigned cnt, dentro do programa C, aonde se quer contar 1 segundo:

T(requerido em segundos) = T(estouro com prescaler) * N(totalizador a ser utilizado na variavel C do contador).

1 s = 51,2 µ s * N   –> N = 1 / 51,2 µ s  –>  19531 (quando o contador ultrapasar esse valor, conta-se 1 segundo)

Sendo assim, toda vez que a variavel de contagem (cnt) do programa C, atingir o valor de 19531, então pode-se efetuar alguma ação, como piscar um led, ou alimentar uma segunda variável de segundos, pois corresponderá a 1 segundo.

Exemplo de Programa simples utilizando o TIMER0, piscar um Led a cada 1 segundo, observar cada comentário em cada linha do programa: 


<span style="line-height: 1.5em;">// LCD module connections</span>

sbit LCD_RS at RB4_bit; //pino 4 do lcd
 sbit LCD_EN at RB5_bit; //pino 6 do lcd
 sbit LCD_D4 at RB6_bit; //pino 11 do lcd
 sbit LCD_D5 at RC0_bit; //pino 12 do lcd
 sbit LCD_D6 at RC1_bit; //pino 13 do lcd
 sbit LCD_D7 at RC2_bit; //pino 14 do lcd
 sbit LCD_RS_Direction at TRISB4_bit;
 sbit LCD_EN_Direction at TRISB5_bit;
 sbit LCD_D4_Direction at TRISB6_bit;
 sbit LCD_D5_Direction at TRISC0_bit;
 sbit LCD_D6_Direction at TRISC1_bit;
 sbit LCD_D7_Direction at TRISC2_bit;
 // End LCD module connections

unsigned cnt; //contador de estouros do timer0, a cada estouro, o programa acessa a função de interrupção, e esta variavel é incrementada.

unsigned cnt_seg; //contador de segundos timer0 - quando a variavel cnt atingir o valor estimado no calculo anterior, esta variavel incrementa 1.

unsigned char txt[15]; // conversão para mostrar a variavel cnt_seg no LCD.

// funcao de interrupcao, funcao padrao da PIC, que e acionada sempre que uma interrupcao e efetuada,

// neste caso a interrupcao e efetuada pelo estouro do TIMER0, e esta função é acessada acada estouro
 void interrupt()
 {
 cnt++;  // incrementa a cada estouro do TIMER0
 INTCON = 0b00100000; //tmr0ie=1 enable interrup no overflow  - habilita a interrupcao no estouro do TIMER0, tmr0if = 0 bit de overflow tem que ser resetado por software.
 }

void main(){

// Configurações basicas da PIC, definem as portas para os perifericos - nao tem relação com o TIMER0

TRISA = 0b00000000; //output lcd
 TRISB = 0b00000000; // PORTB todas saidas
 TRISC = 0b00000000; //PORTC todas saidas

ADCON1 = 0b00000000;

ADCON0 = 0b00000000; // 0- left justif 1- opcao osc, , 00-void, 0000 portA toda analogica, vdd e vss como ref.
 ANSEL = 0b00000000; // define porta analogica ou digital neste caso digitais
 ANSELH = 0b00000000; // define porta analogica ou digital neste caso digitais

OSCCON = 0b01100000;
 //Configuracoes da PIC para o TIMER0 inicio
 OPTION_REG = 0b00001000; // t0cs = 0 para XTAL, psa =0 prescaler desligado,  ps2:ps0 - tempo prescaler, 1, 2,4,8 etc
 INTCON = 0b10100000; // GIE=1-interrup global, tmr0ie=1-enable interup no overflow
 cnt =0;
 cnt_seg = 0;
 PORTB.F1 =0;  // Led apagado
 //Configuracoes da PIC para o TIMER0 final

Lcd_Init(); // Initialize LCD

Lcd_Cmd(_LCD_CLEAR); // Clear LCD display
 Lcd_Cmd(_LCD_CURSOR_OFF); // Turn cursor off

<span style="line-height: 1.5em;">while(1)</span>

{

/*
 if (cnt >19531) //cnt chega a este valor apos diversos estouros do TIMER0, cada estouro chama a funcao  interrupt() que incrementa cnt em 1, esse valor corresponde a 1 segundo.
 {
 PORTB.F1 = ~PORTB.F1;  // Inverte o status do LED - se apagado acende, e vice-versa
 cnt_seg++; // conta 1 segundo
 inttostr(cnt_seg,txt); //converte em texto
 Lcd_Out(2,11,txt);  //mostra no LCD
 cnt =0; // reset na variavel cnt, para contar um novo segundo
 }
 */

}

}

Observações Finais: 

O valor calculado para cnt (19531) é uma estimativa, e deve ser ajustado com a utilização de um cronometro.

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, conforme comentado no programa dentro da funcao de interrupcao.

Bibliografia: 

http://denteazultecnologia.blogspot.com.br/2011/07/tutorial-temporizador-timer-0.html

http://microcontrolandos.blogspot.com.br/2012/11/utilizando-o-timer0-do-pic.html

Maneira de contar utilizando o tmr1 que por ser 16 bits pode contar 1 segundo diretamente, deve ser mais precisa que o exemplo deste post.

http://microcontrolandos.blogspot.com.br/2012/12/utilizando-timer1-pic.html

Outras interrupções da PIC, neste caso a PIC16F877A

http://microcontrolandos.blogspot.com.br/2012/12/utilizando-as-interrupcoes-do-pic.html

Excelente exemplo de um Timer PIC16F877A – com o 4515 que converte de binario para BCD(7segtos) – essa conversão pode ser feita por software conforme mostrei no meu relogio 7 segtos.

http://microcontrolandos.blogspot.com.br/2012/12/timer-decrescente-com-pic.html

Diferencas entre Binario e BCD caso queira utilizar um display de 7 segtos

http://www.dirsom.com.br/index_htm_files/Sistema%20Binario.pdf