El PIC que estamos utilizando para el tutorial, posee tres módulos de timers, TIMER0, TIMER1 y TIMER2. En esta parte, utilizaremos el módulo TIMER0 para crear una función que genere un delay de un milisegundo.

El TIMER0 posee dos modos de funcionamiento, configurados por en el bit T0CS. Si T0CS es 1, entonces el timer funciona como contador de impulsos en el pin RA4/T0CKI. En dicha configuarción, es posible elegir si el incremento de TIMER0 ocurrirá en el pulso de bajada del reloj, o en el pulso de subida del reloj. El bit de configuración correspondiente es T0SE (TMR0 Source Edge Select Bit). Si dicho bit se encuentra en 1, el incremento ocurre en el pulso de bajada del reloj. Si el bit se encuentra en 0, el incremento ocurre en el pulso de subida del reloj.

Por otro lado, si T0CS es 0, entonces el timer se comporta como un temporizador, y su incremento ocurre en cada ciclo de instrucción (Fosc/4, dado que cada instrucción toma 4 ciclos del reloj para ejecutarse).

El registro asociado al módulo TIMER0 es TMR0. Este registro se puede leer y escribir. Se debe poner especial atención en que si el registro es escrito entonces el incremento se inhibe por los siguientes dos ciclos de instrucción.

Teniendo claro lo anterior, podemos escribir la configuración inicial del módulo TIMER0 (tipicamente al inicio de la función main),

T0CS = 0;       //Utilizamoselcristalde20MHzconectadoenRA4/T0CKI
TMR0 = 0;       //LedamosunvalorinicialaTMR0}

Veamos ahora como realizar la función de delay. Primero debemos tener en cuenta que si el reloj es de 20 Mhz, entonces en cada ciclo toma 0.05 microsegundos (1/(20×10^6) s). Por lo tanto, necesitamos 20000 ciclos para hacer 1 ms (pues 20000×0.05 microsegundos = 1000 microsegundos = 1 ms). Finalmente, cada instrucción toma 4 ciclos en realizarse por lo que necesitamos 20000/4 = 5000 instrucciones para tener nuestro delay de 1 ms (en el caso de contar ciclos de instrucción en vez de los pulsos en T0CKI).

El problema con nuestro resultado anterior es que (al menos en este PIC), el registro TMR0 posee sólo 8 bits, y por ende no será capaz de alcanzar el valor 20000 (al llegar a 256 pasa a ser 0). Veremos como solucionar este inconveniente de dos maneras.

El módulo TIMER0 posee un prescaler que como su nombre lo indica realiza un pre escalamiento, esto es, cada cierto número de instrucciones aumenta a TMR0 (lo normal es que no haya pre escalamiento y TMR0 se incremente en cada instrucción).

El prescaler puede ser asignado al módulo de Watchdog (WDT) o al módulo TIMER0. El bit que controla esta asignación es PSA, y si su valor es 0, el prescaler estará asignado al módulo TIMER0. Si su valor es 1, el prescaler será asignado al módulo WDT. Agregamos entonces a la configuración inicial,

T0CS = 1;       //Utilizamoselcristalde20MHzconectadoenRA4/T0CKI
TMR0 = 0;       //LedamosunvalorinicialaTMR0
PSA = 0;        //AsignamoselprescaleraTIMER0

Los bits que configuran el comportamiento del prescaler son PS0, PS1 y PS2. La siguiente tabla resume los valores de dichos bits y su correspondiente configuración.

PS2PS1PS0Configuración TMR0
0001 : 2
0011 : 4
0101 : 8
0111 : 16
1001 : 32
1011 : 64
1101 : 128
1111 : 256

En nuestro caso, necesitamos 20000 incrementos de TMR0, por lo que si utilizamos un pre escalamiento de 1 : 128, entonces debemos comparar el valor de TMR0 con 20000/128 = 156 (contiene un error a causa de la división entera). Estamos en condiciones de escribir la función de delay por 1 ms,

//Generaundelayde1mssilafrecuenciadelcristales20MHz
void delay()
{
	//Configuramoselprescalercon1:128
	PS2 = 1;
	PS1 = 1;
	PS0 = 0;
	//InicializamosTMR0
	TMR0 = 2;
	
	//BusywaitingqueesperaaqueTMR0lleguea156
	//Estoesporquegraciasalprescaler,cada
	//128instruccionesseincrementaTMR0
	while (TMR0 != 156);
}

Ahora que se tiene la lógica de la función, podemos ampliarla de manera que reciba como parámetro el número de milisegundos que durará el delay,

//Generaundelaydeimssilafrecuenciadelcristales20MHz
void delay_ms(uns16 i)
{
	//Configuramoselprescalercon1:128
	PS2 = 1;
	PS1 = 1;
	PS0 = 0;
	
	while(i) {
		--i;
		//InicializamosTMR0
		TMR0 = 2;
		
		//BusywaitingqueesperaaqueTMR0lleguea156
		//Estoesporquegraciasalprescaler,cada
		//128instruccionesseincrementaTMR0
		while(TMR0 != 156);
	}
}

El código de este ejemplo y una pequeña aplicación se encuentran en el archivo tut_tim0.c.