Citando o livro de Fábio Perreira (Microcontroldores PIC - Programação em C, pag 258) + informações da Net + as formulas cedidas por Away
UTILIZANDO OS TIMERS INTERNOS
Uma técnica muito interessante para implementar bases de tempo precisas com com
o timer interno dos PICs é a chamada acúmulo de erros.
Essa técnica consiste em implementar um contador de software que decrementado a
cada ciclo de interrupções, e uma vez que o seu valor atinja um determinado limite,
se subtrai-se a frequência de entrada, mantendo-se o resto no reistrador.
Vejamos um exemplo prático:
suponhamos que seja necessário implementar uma base de tempo de 1 segundo utilizando
o timer 0 (zero) num PIC com clock do cristal = 4Mhz.
O primeiro passo é selecionar o maior fator de divisão do prescaler que resulte
em uma frequência interira. No nosso caso, o maior fator de divisão é 64, resultando
em uma frequência de 15625 Hz (na saída).
Fosc é um sinal gerado internamnte no PIC pelo circuito de clock e é igual a
frequência de clock dividida por quatro (exemplo 4Mhz/4 = fosc 1.000.000).
Ou seja, o valor do Fosc / prescale ( 1000000 / 64 = 15625 )

O fator de divisão é diferente para cada timer, veja tabela:

(Alguem pode me dizer se o Timer2 e 3 são 16Bits????)
Este valor (15625) será carregado em uma variável de contagem e a cada ciclo de
interrupção, subtrai-se 256 dessa variável. O valor 256 é utilizado pois consiste
no fator de divisão natural do Timer0, que nos PICs da série 16 é sempre de 8 bits.
ou seja 8bits (11111111) = 256
Se o valor dela for igual ou menor que zero, soma-se 15625 à variável, executan-se
os comandos relativos ao evento de passagem de 1 segundo e o processo reinicia.
Observe que o resto presente na variável de contagem (erro residual da divisão) é
acumulado durante a contagem, reduzindo o erro total a praticamente zero.
O incoveniente dessa técnica é que o intervalo de tempo entre cada evento (no caso
de 1 segundo) não é constante, o que en alguns casos pode ser inaceitavel.
vejamos um exemplo para piscar um led conectado ao pino RC2 a uma frequência de 1Hz.
FORMULA
Dados necessários:
Cristal = 4000000 (4Mhz)
Prescale = 64
Frequência procurada (em segundos) = 1seg / 1Hz = 1
Fórmula geral:
TCY * PS * V = tempo em segundos
//---------------------------
Fórmula TCY:
TCY = 1seg / Fosc
1 / (4000000 / 4)
1 / 1000000
TCY = 0,000001
//---------------------------
PS = Prescale selecionado para o timer, nesse caso 64
PS = 64
//----------------------------
Fórmula V:
V = Valor
V = Frequencia procurada em segundos / ( TCY * Prescale selecionado para o timer, nesse caso 64 )
V = (1seg / 1Hz) / (0,000001 * 64)
V = 1 / (0,000001 * 64)
V = 1 / (0,000064)
V = 15625
//-----------------------------
TCY * PS * V = tempo em segundos
0,000001 * 64 * 15625 = 1seg
Frequência = 1 / tempo em segundos
Frequência = 1 / 1
Frequência = 1Hz
Agora, vamos fazer o calculo para achar o valor que vamos colocar no set_timer, esse é o valor que realmente
interessa para agente.
Valor set_timer = Valor máximo do timer selecionado - V
Valor set_timer = 256 - 15625
Valor set_timer = -15369
*Obs.: Se o valor der negativo como nesse exemplo, teremos que usar IF para poder chegar
na frequência que queremos.
1° - Vamos achar o valor para colocar no IF
Valor do IF = Raiz quadrada de Valor
Valor do IF = Raiz quadrada de 15625 (o simbolo não quis aparecer)
Valor do IF = 125
*Obs.: Não sei como vocês fazem, mas eu vou no Excel e digito em uma célula =SQRT(15625) e ele mostra o valor da raiz quadrada
2° - Agora, o valor do set_timer
Valor set_timer = Valor máximo do timer selecionado - raiz quadrada de V
Valor set_timer = 256 - 125
Valor set_timer = 131
USANDO NA PRATICA
- Código: Selecionar todos
#include <16f628a.h>
#use delay(clock=4000000)
#fuses HS,NOWDT,PUT,NOLVP
#int_timer0
void trata_t0 ()
{
static boolean led;
static int conta; set_timer0(131+get_timer0()); // reinicia o timer 0 em 131 mais a contagem que já passou
conta++;
if (conta == 125) // se já ocorreram 125 interrupções
{
conta=0;
led = !led; // inverte o led
output_bit (pin_b0,led);
}
}
main()
{
// configura o timer 0 para clock interno e prescaler dividindo por 64
setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_64 );
set_timer0(131); // inicia o timer 0 em 131
// habilita interrupções
enable_interrupts (global | int_timer0);
while (true); // espera interrupção (loop infinit)
}
TESTE NO PROTEUS

Configuração do Clock
