3.4 Temporizador TIMER0
El temporizador Timer0 tiene una amplia gama de aplicaciones en la práctica. Sólo unos pocos programas no lo utilizan de alguna forma. Es muy conveniente y fácil de utilizar en programas o subrutinas para generar pulsos de duración arbitraria, en medir tiempo o en contar los pulsos externos (eventos) casi sin limitaciones.
El módulo del temporizador Timer0 es un temporizador/contador de 8 bits con las siguientes características:
- Temporizador/contador de 8 bits;
- Pre-escalador de 8 bits (lo comparte con el temporizador perro guardián);
- Fuente de reloj interna o externa programable;
- Generación de interrupción por desbordamiento; y
- Selección del flanco de reloj externo programable.
La siguiente figura muestra el esquema del temporizador Timer0 con todos los bits que determinan su funcionamiento. Estos bits se almacenan en el registro OPTION_REG.
Registro OPTION_REG
- RBPU - PORTB Pull-up enable bit (resistencia Pull Up del puerto PORTB)
- 0 - Resistencias pull-up del puerto PORTB están deshabilitadas.
- 1 - Pines del puerto PORTB pueden estar conectados a las resistencias pull-up.
- INTEDG - Interrupt Edge Select bit (bit selector de flanco activo de la interrupción externa)
- 0 - Interrupción por flanco ascendente en el pin INT (0-1).
- 1 - Interrupción por flanco descendente en el pin INT (1-0).
- T0CS - TMR0 Clock Select bit (bit selector de tipo de reloj para el Timer0)
- 0 - Los pulsos se llevan a la entrada del temporizador/contador Timer0 por el pin RA4.
- 1 - El temporizador utiliza los pulsos de reloj internos (Fosc/4).
- T0SE - TMR0 Source Edge Select bit (bit selector de tipo de flanco)
- 0 - Incrementa en flanco descendente en el pin TMR0.
- 1 - Incrementa en flanco ascendente en el pin TMR0.
- PSA - Prescaler Assignment bit (bit de asignación del pre-escalador)
- 0 - Pre-escalador se le asigna al WDT.
- 1 - Pre-escalador se le asigna al temporizador/contador Timer0.
- PS2, PS1, PS0 - Prescaler Rate Select bit (bit selector del valor del divisor de frecuencias)
- El valor del divisor de frecuencias se ajusta al combinar estos bits. Como se muestra en la tabla a la derecha, la misma combinación de bits proporciona los diferentes valores del divisor de frecuencias para el temporizador/contador y el temporizador perro guardián, respectivamente.
PS2 |
PS1 |
PS0 |
TMR0 |
WDT |
0 |
0 |
0 |
1:2 |
1:1 |
0 |
0 |
1 |
1:4 |
1:2 |
0 |
1 |
0 |
1:8 |
1:4 |
0 |
1 |
1 |
1:16 |
1:8 |
1 |
0 |
0 |
1:32 |
1:16 |
1 |
0 |
1 |
1:64 |
1:32 |
1 |
1 |
0 |
1:128 |
1:64 |
1 |
1 |
1 |
1:256 |
1:128 |
Cuando el bit PSA está a 0, el pre-escalador se le asigna al temporizador/contador Timer0, como se muestra en la siguiente figura.
Vamos a hacerlo en mikroC...
// En este ejemplo, Timer0 se configura como un temporizador y se le asigna un pre-escalador.
unsigned cnt; // Declarar la variable cnt
void interrupt() { // Rutina de interrupción
cnt++; // Interrupción causa el incremento de cnt por 1
TMR0 = 155; // Temporizador (o contador) Timer0 devuelve su valor inicial
INTCON = 0x20; // Bit T0IE está a 1, bit T0IF está a 0
}
void main() {
OPTION_REG = 0x04; // Pre-escalador (1:32) se le asigna al temporizador Timer0
TMR0 = 155; // Temporizador T0 cuenta de 155 a 255
INTCON = 0xA0; // Habilitada la generación de interrupción para el
// temporizador Timer0
...
...
// En el siguiente ejemplo, Timer0 se configura como un temporizador
// y se le asigna un pre-escalador.
OPTION_REG = 0x20; // Pre-escalador (1:2) se le asigna al contador Timer0
TMR0 = 155; // Contador T0 cuenta de 155 a 255
INTCON = 0xA0; // Habilitada la generación de interrupción por el
// temporizador Timer0
...
...
Cuando el bit PSA está a 1, el pre-escalador se le asigna al temporizador perro guardián como se muestra en la siguiente figura.
Vamos a hacerlo en mikroC...
// En este ejemplo, el pre-escalador (1:64) se le asigna al temporizador perro guardián.
void main() {
OPTION_REG = 0x0E; // Pre-escalador se le asigna al WDT (1:64)
asm CLRWDT; // Comando en ensamblador para reiniciar el WDT
...
...
asm CLRWDT; // Comando en ensamblador para reiniciar el WDT
...
Aparte de lo dicho anteriormente, cabe destacar lo siguiente:
- Al asignarle el pre-escalador al temporizador/contador, el pre-escalador se pondrá a 0 con cualquier escritura en el registro TMR0.
- Al asignar el pre-escalador al temporizador perro guardián, tanto el WDT como el preescalador se pondrán a 0 con la instrucción CLRWDT.
- Al escribir en el registro TMR0, utilizado como un temporizador, no se inicia el conteo de los pulsos inmediatamente, sino con retraso de dos ciclos de instrucciones. Por consiguiente, es necesario ajustar el valor escrito en el registro TMR0.
- Al poner el microcontrolador en el modo de reposo se apaga el oscilador de reloj. No puede ocurrir el desbordamiento ya que no hay pulsos a contar. Es la razón por la que la interrupción por el desbordamiento del TMR0 no puede“despertar” al procesador del modo de reposo.
- Si se utiliza como un contador de reloj externo sin pre-escalador, la longitud de pulso mínima o tiempo muerto entre dos pulsos deberá ser 2 Tosc + 20 nS (Tosc es el período de señal de reloj del oscilador).
- Si se utiliza como un contador de reloj externo con pre-escalador, la longitud de pulso mínima o tiempo muerto entre dos pulsos es sólo 10nS.
- El registro del pre-escalador de 8 bits no está disponible al usuario, lo que significa que no es posible leerlo o escribir en él directamente.
- Al cambiar de asignación del pre-escalador del Timer0 al temporizador perro guardián, es necesario ejecutar la siguiente secuencia de instrucciones escritas en ensamblador para impedir reiniciar el microcontrolador:
BANKSEL TMR0
CLRWDT ;PONER A CERO WDT
CLRF TMR0 ;PONER A CERO TMR0 Y PRE-ESCALADOR
BANKSEL OPTION_REG
BSF OPTION_REG,PSA ;ASIGNARLE EL PRE-ESCALADOR AL WDT
CLRWDT ;PONER A CERO WDT
MOVLW b'11111000' ;SELECCIONAR LOS BITS PS2,PS1,PS0 Y PONERLOS
ANDWF OPTION_REG,W ;A CERO POR LA INSTRUCCIÓN 'Y LÓGICO'
IORLW b'00000101' ;BITS PS2, PS1, Y PS0 PONEN EL VALOR
MOVWF OPTION_REG ;DEL DIVISOR DE FRECUENCIAS A 1:32
- De manera similar, al cambiar de asignación del pre-escalador del WDT al Timer0, es necesario ejecutar la siguiente secuencia de instrucciones, también escritas en ensamblador:
BANKSEL TMR0
CLRWDT ;PONER A CERO WDT Y PRE-ESCALADOR
BANKSEL OPTION_REG
MOVLW b'11110000' ;SELECCIONAR SÓLO LOS BITS PSA,PS2,PS1,PS0
ANDWF OPTION_REG,W ;Y PONERLOS A CERO POR LA INSTRUCCIÓN 'Y LÓGICO'
IORLW b'00000011' ;VALOR DEL DIVISOR DE FRECUENCIAS ES 1:16
MOVWF OPTION_REG
Para utilizar el Timer0 apropiadamente, es necesario:
Paso 1: Seleccionar el modo:
- El modo de temporizador se selecciona por el bit TOSC del registro OPTION_REG (TOSC: 0=temporizador, 1=contador).
- Cuando se asigna el pre-escalador al temporizador/contador se debe poner a cero el bit PSA del registro OPTION_REG. El valor del divisor de frecuencias se configura al utilizar los bits PS2-PS0 del mismo registro.
- Al utilizar una interrupción, los bits GIE y TMR0IE del registro INTCON deben estar a uno.
Paso 2: Medir y contar
Para medir tiempo:
- Reiniciar el registro TMR0 o escribir un valor conocido en él.
- El tiempo transcurrido(en microsegundos al utilizar el oscilador de 4MHz) se mide al leer el registro TMR0.
- El bit de bandera TMR0IF del registro INTCON se pone a uno automáticamente siempre que ocurra el desbordamiento del registro TMR0. Si está habilitada, ocurre una interrupción.
Para contar pulsos:
- La polaridad de pulsos a contar en el pin RA4 se selecciona por el bit TOSE del registro OPTION_REG (T0SE: 0=pulsos positivos, 1=pulsos negativos).
- Varios pulsos se pueden leer del registro TMR0. El pre-escalador y la interrupción se utilizan de la misma forma que en el modo de temporizador.