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