Timer 0 Pic18fxxxx Rutinas de acceso a interrupcion, configuracion, overflow. Con CCS

Hola a todos, he estado buscando por el foro solo he encontrado trabajos con el timer 0 en asm, no en c con CCS.

En palabras llanas quiero utilizar el timer 0 en CCS en modo 16 bits, cargarle un valor al registro y cuando llegue a 0xFFFF salte la interrupcion, borrar el flag, recargar el valor y así sucesivamente. esto me permitiría contar el número de interrupciones y así contar tiempos más largos.

Voy a investigar sobre los siguientes temas (Enumero los temas antes de irme a dormir y seguiré investigando). Conforme avance lo dejaré todo bien escrito en el foro.

Y si tengo alguna duda se la preguntaré, que seguro me la saben resolver.

1. Como saber que reloj se aplica al timer, divisores y demás.... (Teorico y practico)
2. Configurar el timer en modo 16 bits (tanto teorico como practico)
3. Cargar el valor en el registro de 16bits, supongo que habrá que separar parte alta y baja, ya veremos.
4. Iniciar o parar el timer.
5. Definir una RAI (Rutina de atención a interrupción).
6. Borrar flags y reiniciar la cuenta. (Mirar también si existe algun tipo de autorrecarga, el 8051 lo tiene)

La verdad, me cuesta un poco entenderlo y voy a intentar aclararme a la vez que lo escribo.

P.D. Tendré que pediros ayuda, ya se verá.

1. Como saber que reloj se aplica al timer, divisores y demás.... (Teorico y practico)
A continuación se muestra el esquema del oscilador del micro.Fig 1_1.GIF
Fig 1_2.GIF

Supongamos que tenemos un cristal de 20Mhz,(Patas OSC1 y OSC2) entonces, para poder utilizar el USB hace falta dividir entre 5 la frecuencia del cristal, esto se hace con PLLDIV.
En CCS:
Código:
#fuses PLL5
De esta forma hemos conseguido 4Mhz, que entrando al PLL genera 96Mhz, es dividia /2 lo que genera una frecuencia de 48Mhz que es la que deseamos. A continuación entra al multiplexor, para indicar que esa es la frecuencia que deseamos poner USBDIV a 1.
En CCS:
Código:
#fuses USBDIV
FSEN no se como se controla pero se debe poner a 1. lo preguntaré.

Emplearemos como fuente para la cpu y los periféricos el la salida del PLL 96Mhz, esto se hace seleccionando HSPLL
En CCS:
Código:
 #fuses HSPLL
Esta frecuencia se dividirá /2 mediante CPUDIV, existen CPUDIV1,CPUDIV2,CPUDIV3,CPUDIV4, que son respectivamente /2, /3, /4, /6
En CCS:
Código:
  #fuses CPUDIV1
Ya tenemos 48 Mhz aplicados a la CPU y a los periféricos.

2. Configurar el timer 0.
El registro principal que controla el timer 0 es T0CON:
Fig 2.GIF
Fig 3.GIF

TMR0ON: 1 Habilita el timer 0.
000000000 Para el timer 0.

T08BIT: 1 Lo configura como un temporizador/Contador de 8 bits.
00000000 Lo configura como un temporizador/contador de 16 bits.

T0CS: 1 La frecuencia de temporizacion/conteo procede de un pin externo llamado T0CKI.
0000000 La frecuencia de temporizacion procede del bus de periféricos DIVIDIDA ENTRE 4

T0SE: 1 El incremento de cuenta se realiza en flanco descendente.
0000000 El incremento de cuenta se realiza en flanco ascendente.
000000Solo utilizable cuando el origen del reloj es una fuente externa.
000000S
PSA: 1 Deshabilita el divisor de frecuencia.
000000 Habilita el divisor de frecuencia.

T0PS2, T0PS1, T0PS0: Divisor de frecuencia,
00000000000000000000000 Divide la frecuencia entre 2
00000000000000000000001 Divide la frecuencia entre 4
00000000000000000000.
00000000000000000000.
00000000000000000000.
00000000000000000000111 Divide la frecuencia entre 256

Consideraciones importantes:

*Cuando se escribe en el registro TMR0, el incremento de este contador se inhibe durante los siguientes dos ciclos de instrucción, en temporizaciones con mucha precisión, esto se debe tener en cuenta.

*Cuando trabajamos con el temporizador/contador en modo 16 bits, TMR0H es la parte alta y TMR0L la parte baja, sin embargo, TMR0H solo se actualiza cuando se lee o escribe TM0L, es decir: En la lectura, debemos leer primero TMR0L y después TMR0H. En la escritura debemos escribir primero TMR0H y después TMR0L.


El valor de precarga deberia se:
2^16-(tiempo/(divisor_de_frecuencia/(48.000.000/4))) Nota: 48000000 es la frecuencia del bus de perifericos

Como acceder desde CCS a un registro:
Código:
#BYTE T0CON = 0xFD5
0xFD5 es la dirección de memoria donde está mapeado el registro T0CON en los micros 15f2455/2550/4455/4550, para otras modelos mirar la hoja de características, hay una tabla en la que vienen las direcciones de todos los puertos.

CCS incorpora un programa que te hace esto automaticamente, de aquí he sacado una serie de definiciones para poder acceder bit a bit al registro del timer 0
Código:
#byte MCU_T0CON = 0xFD5
#bit    MCU_T0PS0 = MCU_T0CON.0
#bit    MCU_T0PS1 = MCU_T0CON.1
#bit    MCU_T0PS2 = MCU_T0CON.2
#bit    MCU_PSA = MCU_T0CON.3
#bit    MCU_T0SE = MCU_T0CON.4
#bit    MCU_T0CS = MCU_T0CON.5
#bit    MCU_T08BIT = MCU_T0CON.6
#bit    MCU_TMR0ON = MCU_T0CON.7
Las interrupciones
Para habilitar las interrupciones habrá que:
Código:
MCU_T0CON=0x00;      /*Para que al habilitar las interrupciones el timeresté apagado, lo encenderemos cuando lo necesitemos.*/
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
Rutina de acceso a la interrupcion, se coloca antes del main ;)
Código:
#INT_TIMER0
void timer0_isr(void) 
   {
   /*Aquí escribo lo que quiero que haga la rutina de atención de interrupcion, yo he puesto un ejemplo, pero aquí se incluyen las cosas que se quieran. La RAI no debe ser demasiado larga.*/
   /*1ºBorrar su flag OBLIGATORIO*/
   clear_interrupt(int_timer0);
   /*2ºRecargar el contador con el valor deseado*/
   set_timer0(tiempo_de_precarga); //Debe ser un valor de 16 bits
   /*3ºActuar sobre el LED*/
   
   
   
   /*4ºActivar el flag que me permite contar tiempo*/

}//Final de la rutina de acceso a la interrupcion
Cuando "salte" la interrupcion del timer 1 se activa un flag,e ste hay que borrarlo por software:
Clears the interrupt flag for the given level. This function is designed for use with a specific interrupt, thus eliminating the GLOBAL level as a possible parameter. Some chips that have interrupt on change for individual pins allow the pin to be specified like INT_RA1.
Código:
clear_interrupt(int_timer0);

Un saludo a todos y gracias.
 
Última edición:
Hola a todos, ¿Alguien que entienda un poco le podría echar un vistazo al post por si hay algún error? Si no hay errores, esto se queda así, espero que a alguien le sirva de algo.

A mi me ha funcionado a la perfección, soy capaz de temporizar un rango de tiempos increiblemente grande.
 
Atrás
Arriba