Está en la página 1de 66

El Módulo Temporizador

1
6. Descripción General del Módulo Temporizador (Timer)
Los PIC 16F87X poseen un módulo para el manejo preciso y eficiente de operaciones que
involucran tiempo o conteo. Este módulo consta de:

• Tres contadores/temporizadores denominados TMR0, TMR1 y TMR2


• Dos módulos CCP (Captura, Comparación y PWM (Modulación de ancho de
pulso) denominados CCP1 y CCP2

En la siguiente tabla se resumen las principales características de los módulos


mencionados:

Módulo Características
 TMR0 es un Contador/Temporizador de 8 bits
 Leíble y escribible
 Reloj interno o externo
TMR0  Selección de flanco activo en el reloj externo
 Preescalador de 8 bits programable
 Solicitud de interrupción opcional en el desbordamiento (de
FFh a 00h)
 TMR1 es un Contador/Temporizador de 16 bits
 Leíble y escribible
 Reloj interno o externo
TMR1  Preescalador programable
 Solicitud de interrupción opcional en el desbordamiento (de
FFFFh a 0000h)
 Reinicialización opcional desde los módulos CCP
 TMR2 es un Temporizador de 8 bits
 Dispone de un registro de periodo de 8 bits (PR2)
 Leíble y escribible
 Preescalador programable
TMR2  Postescalador programable
 Solicitud de interrupción opcional al coincidir TMR2 y PR2
 Posibilidad de generar impulsos al módulo SSP (puerto serie
síncrono)
 Modo de captura
CCP1 y CCP2  Modo de comparación
 Modo PWM (modulación de ancho de pulso)

6.1. El Módulo del Timer 0


El Timer 0 es un contador/temporizador de 8 bits. El registro principal de este módulo es
TMR0 (01h, 101h). Este registro se incrementa continuamente a una frecuencia
seleccionable manejada por un preescalador y el reloj interno Fosc/4 (modo
temporizador) o bien, por un preescalador y una señal externa (modo contador).

El registro TMR0 es un contador, es decir un tipo de registro particular cuyo contenido es


incrementado con una cadencia regular y programable directamente por el hardware del PIC. En
la práctica, a diferencia de los otros registros, el TMR0 no mantiene inalterado el valor que tiene
almacenado, sino que lo incrementa continuamente, si por ejemplo se escribe en él el valor 10
con las siguientes instrucciones:

2
movlw 10
movwf TMR0

después de un tiempo igual a cuatro ciclos de máquina, el contenido del registro comienza a ser
incrementado a 11, 12, 13 y así sucesivamente con una cadencia constante y totalmente
independiente de la ejecución del resto del programa.

Si, por ejemplo, después de haber almacenado un valor en el registro TMR0, se ejecuta un bucle
infinito, como se muestra a continuación:

movlw 10
movwf TMR0
loop
goto loop

el registro TMR0 es en consecuencia incrementado por el hardware interno del PIC al mismo
tiempo que se ejecuta el bucle.

Una vez alcanzado el valor 255, el registro TMR0 es puesto a cero automáticamente reiniciando
entonces el conteo no desde el valor originariamente cargado sino desde cero.

La frecuencia de conteo es directamente proporcional a la frecuencia de reloj aplicada al chip y


puede ser modificada programando adecuadamente algunos bits de configuración.

En la siguiente figura se muestra un diagrama de bloques de este módulo:

A continuación se indican los bits que afectan la operación del módulo TMR0 y la manera en
que lo hacen:

• La señal Fosc/4 y el pin T0CKI, representan las dos posibles fuentes de señal de reloj,
para el contador TMR0, las cuales se indican cómo se obtienen:

- Fosc/4 es una señal generada internamente por el PIC tomada del circuito de reloj y
que es igual a la frecuencia del oscilador dividida por cuatro.

3
- T0CKI es una señal generada por un posible circuito externo y aplicado al pin
T0CKI.

• Las señales T0CS y PSA, son dos conmutadores de señal en cuya salida se presenta una
de las dos señales de entrada en función del valor de los bits T0CS y PSA del registro
OPTION.

• El bloque Preescalador es un divisor programable cuyo funcionamiento se explicará en


el siguiente subtema.

Para obtener diferentes modalidades de conteo para el registro TMR0, se debe actuar sobre estas
señales y bloques, de las siguientes formas:

1. El registro TMR0 como Temporizador. Se programa el bit T0CS a 0 y PSA a 1,


obteniéndose la configuración de funcionamiento la que se representada en la siguiente
figura.

Las partes en rojo evidencian el recorrido que efectúa la señal antes de llegar al contador
TMR0.

Como se había ya dicho anteriormente, la frecuencia Fosc/4 es una cuarta parte de la


frecuencia de reloj. Entonces, utilizando un cristal de 4Mhz se tendrá una Fosc/4 igual a 1
MHz. Tal frecuencia es enviada directamente al registro TMR0 sin sufrir ningún cambio. La
cadencia de conteo que se obtiene es por lo tanto igual a 1 millón de incrementos por
segundo del valor presente en TMR0.

El modo temporizador se selecciona poniendo a cero el bit T0CS (registro OPTION_REG


<5>). En el modo temporizador, el módulo Timer0 se incremento en cada cielo de
instrucción (sin el preescaler). Si el registro TMR0 se escribe, el incremento se inhibe
durante los siguientes dos ciclos de instrucción. EL usuario puede trabajar teniendo en
cuenta esto y ajustando el valor a cargar en el TMR0.

En resumen, en el modo temporizador la señal de reloj que controla el incremento del


registro TMR0 es la frecuencia Fcy = Fosc/4, la cual puede ser dividida
opcionalmente por el preescalador si así se desea. Como se puede ver en la figura
anterior, este modo es seleccionado al limpiar el bit T0CS (OPTION_REG<5>). En este
modo, el contenido del registro TMR0 se incrementará a la frecuencia Fcy dividida de
acuerdo al preescalador, sin embargo, si se realiza una escritura al registro TMR0, su
incremento es inhibido por los siguientes dos ciclos de instrucción (Tcy).
4
2. El registro TMR0 como Contador. Ahora se cambia el estado del bit T0CS de 0 a 1,
obteniéndose la configuración mostrada en la siguiente figura.

El modo contador se selecciona poniendo a uno el bit T0CS (registro OPTION_REG <5>).
El modo contador, Timer0 se incremento en cada flaco de subida o de bajada de la señal que
le llega por RA4/TOCK1. El flanco de incremento se determina por el bit T0SE (registro
OPTION_REG <4>). Poniéndose a cero T0SE se selecciona el flanco ascendente. Las
restricciones de la señal de reloj externa se describen en la sección 5.2.

Esta vez será la señal aplicada al pin TOCKI del PIC la que será enviada directamente al
contador TMR0, determinando esta la frecuencia de conteo. Por ejemplo, aplicando a este
pin una señal con una frecuencia de 100Hz se obtiene una frecuencia de conteo igual a cien
incrementos por segundo.

La presencia de la compuerta lógica XOR (OR exclusiva) en la entrada TOCKI del PIC,
permite determinar por medio del bit T0SE del registro OPTION si el contador TMR0 debe
ser incrementado en correspondencia con el flanco de bajada (T0SE=1) o con el flanco de
subida (T0SE=0) de la señal externa aplicada.

En la siguiente figura se representa la correspondencia entre el camino de la señal externa y


el valor que toma el contador TMR0 en ambos casos:

Cuando no se utiliza el preescaler, la entrada de reloj externa es igual a la salida del


preescaler. La sincronización de TOCKI con los relojes de fase interior se acopla, a la
salida del preescaler en los ciclos Q2 y Q4 de los relojes de fase internos. Por
consiguiente, es necesario que TOCKI está a nivel alto por al menos durante 2Tosc (y un
pequeño retardo de 20ns) y a nivel bajo por lo menos 2Tosc (y un retardo RC de 20ns).Ver
las características eléctricas del dispositivo deseado.

En resumen, en el modo contador, la señal que controla los incrementos del registro
TMR0 es una señal externa que proviene de la patita T0CKI. En la figura anterior se
puede ver que este modo se selecciona poniendo el bit T0CS en alto. Se puede
5
seleccionar la transición que provoca los incrementos mediante el bit “Timer0 Source
Edge Select“ T0SE (OPTION_REG<4>), limpiando este bit se selecciona la
transición de subida, mientras que al ponerlo en alto se selecciona la de bajada.

Observación: En este modo, la señal conectada a TOCKI es muestreada durante los ciclos
Q2 y Q4 del reloj interno, por ello es necesario que permanezca en alto al menos por 2
Tosc más un pequeño retardo de 20nseg y lo mismo en bajo. (es decir, señales demasiado
estrechas (rápidas) no podrán ser detectadas).

6.1.1. Características del Timer 0

Se analizará la bandera T0IF y el preescalador del Timer0:

a. La Bandera T0IF

El registro TMR0 se incrementa continuamente en cualquiera de sus dos modos, desde 00h
hasta FFh y en la siguiente cuenta se reinicia en 00h y así sucesivamente.

Al momento del reinicio se activa la bandera T0IF (INTCON<2>) poniéndose en 1. Esta


activación puede usarse de dos maneras:

• Para solicitar una interrupción


• Para ser consultada por poleo

En ambos casos debe tenerse en cuenta que para poder detectar una activación (un 1) en
esta bandera, previamente habrá que limpiarla por software. Esto debe realizarse en la
inicialización del Timer y después de que un reciclo la ha activado. Lo último puede
hacerse en la rutina de atención a la interrupción, o bien, en la rutina que la consulta por
poleo (según sea el caso).

La interrupción de TMR0 se produce cuando el registro TMR0 se desborda al pasar de FFh


a 00h. Este desbordamiento pone a uno el bit T0IF (INTCON<2>). La ininterrupción puede
enmascararse poniendo a cero el bit T0IE (INTCON <5>). EL bit T0IF debe ponerse a cero
por software al finalizar la rutina de atención a la interrupción del desbordamiento de
TMRO. La ininterrupción de TMRO no saca al microcontrolador del estado de SLEEP,
debido a que el temporizador está desactivado durante el modo SLEEP.

b. El preescalador

El último bloque que queda por analizar para poder utilizar completamente el registro TMR0
es el PRESCALER, el cual determina cómo es posible dividir exteriormente la frecuencia de
conteo, interna ó externa, activando el PRESCALER.

Si se configura el bit PSA del registro OPTION a 0 se envía al registro TMR0 la señal de
salida del PRESCALER, como se puede ver en la figura 6:

6
El PRESCALER consiste en la práctica, en un divisor programable de 8 bits a utilizar en el
caso de que la frecuencia de conteo enviada al contador TMR0 sea demasiado elevada para
propósitos de cualquier aplicación.

Hay sólo un preescaler disponible que está compartido y puede asignarse indistintamente al
moduló de Timerl y el al WDT. La asignación del preescaler al Timer0 hace que no haya
ningún preescaler para el WDT, y viceversa. Este preescaler no se puede leer ni escribir.

El bit PSA y PS2:PS0 (OPTION_REG <3:0>) determinan la asignación del preescaler y el


rango del preescaler. Cuando se le asigna al módulo del Tirner0, todas las instrucciones, que
escriben en el registro TMR0 (por ejemplo CLRF TMR0, MOVWF TMR0, BSF TMR0,x...
etc.) ponen a cero el preescaler. Cuando se le asigna al WDT, una instrucción CLRWDT
limpia el preescaler junto con el temporizador del WDT. EL preescaler no se puede leer ni
escribir.
Nota.- Escribir en TMR0, cuando el preescaler es asignado a Timer0, limpia la cuenta del
preescaler, pero no cambia el contenido del preescaler.

Es decir, el preescalador es un divisor de frecuencia de módulo seleccionable. Como se


puede ver en la figura anterior, el preescalador está compartido entre el timer0 y el
módulo watchdog, sin embargo sólo puede conectarse a uno de los dos y esto se
establece mediante el bit PSA (OPTION_REG<3>), así, con este bit en alto el
preescalador es asignado al reloj del watchdog, mientras que con un nivel bajo en PSA el
preescalador dividirá la frecuencia que maneja al timer 0.

La selección del módulo (valor de división de frecuencia) del preescalador se puede


realizar mediante los bits PS2, PS1, PS0 (OPTION_REG<2:0>) de acuerdo a la siguiente
tabla:

Divisor
PS2 PS1 Divisor
(timer
PS0 (Watchdog)
0)
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

7
El preescaler se comparte exclusivamente entre el Timer0 y el WDT. El preescaler no es de
lectura/escritura.

Nota: Escribir en TMR0, cuando el preescaler es asignado a Timer0, limpia la cuenta del
preescaler, pero no cambia el contenido del preescaler.

6.1.2. Registros del Timer 0

1. Registro OPTION_REG
A manera de resumen se presenta a continuación una descripción de los bits del
registro OPTION_REG, que tienen relación con el Timer 0:

bits 5 T0CS.- Bit de selección de la fuente de reloj para incrementar TMR0. Un 1 en este
bit selecciona como reloj la patita T0CKI (modo contador), mientras que un
0 selecciona el reloj del ciclo de instrucción interno (CLKout) (modo
temporizador).

bit 4 T0SE.- Bit de selección de transición activa del reloj en modo contador. Un 1 en
este bit selecciona el incremento de TMR0 en la transición de alto a bajo de
T0CKI, mientras que un 0 selecciona la la transición de bajo a alto.

bit 3 PSA.- Bit de asignación del preescalador. Un 1 en este bit asigna el preescalador al
watchdog y un 0 lo asigna al Timer0.

bits 2:0 PS2:PS0.- Bits de selección del valor del preescaler (ver tabla anterior).

2. Registros asociados al TIMER0


En la siguiente tabla se muestran los registros principales que controlan el comportamiento
del TIMER0 y la distribución de los bits.

Valor en Valor en el
Dirección Nombre Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
POR,BOR resto de Reset

0bh, 8Bh
INTCON GIE PEIE T0IE INTE RBIE T0IF INTF RBIF 0000 000x 0000 000x
10Bh,18Bh

81h,181h OPTION_REG RBPU INTEDG T0CS T0SE PSA PS2 PS1 PS0 1111 1111 1111 1111

85h TRISA --- --- Registro de direccionamiento de datos del PORTA --11 1111 --11 1111

Leyenda: x = desconocido, u = inalterado; - = no implementado se lee como ‘0’. Las celdas


sombreadas no son usadas por el TIMER0
6.2. El Módulo del Timer 1
El Timer 1 a diferencia del Timer 0 es un contador / temporizador de 16 bits. El conteo es
8
realizado por dos registros de 8 bits: (TMR1H (0Fh) y TMR1L (0Eh)), estos dos
registros son tanto leíbles como escribibles. Al par de registros TMR1H:TMR1L los
denominaremos por comodidad como si fueran un solo registro de 16 bits (TMR1).

Así, el registro TMR1 se incrementa de 0000h a FFFFh y en la siguiente cuenta se reinicia


en 0000h y así sucesivamente, al reciclarse se activa (en alto) la bandera TMR1IF
(PIR1<0>), la cual puede ser utilizada para generar una interrupción, o bien, para ser
consultada por poleo, teniendo las mismas precauciones que ya se explicaron antes para la
bandera T0IF.

En la siguiente figura se muestra un diagrama de bloques de este módulo:

6.2.1. Modos de trabajo del TIMER1

EL TIMER l tiene los siguientes modos de trabajo:

1. Como Temporizador
2. Como contador Síncrono
3. Como contador Asíncrono

El modo de trabajo viene determinado la fuente de los impulsos de reloj, es decir, la señal de
reloj puede ser externa o interna, se selecciona con el bit TMRLCS del registro TlCON<l>,
cuando este bit está a nivel bajo se selecciona el reloj el interno del microcontrolador (Fosc/4) y
cuando está a uno se selecciona el modo contador y cuenta los impulsos que le llegan a través del
pin RC0/TlCKl. Además, como se ver más adelante el TIMER1 tiene la posibilidad de
reinicializarse, a partir del módulo CCP.

A continuación se indica la configuración del modo de funcionamiento del Timer1 como:


Contador Síncrono y Contador Asíncrono:

a. Modo de funcionamiento del Timer1 como Contador Síncrono

Para seleccionar este modo se pone a uno el bit TMR1CS (T1CON <1>). En este modo el
contador se incrementa en cada flanco ascendente de la señal de reloj que se introduce por el
pin RC0/T1OSO/TICK1cuando el bit T1OSCEN está a uno, y por el pin RC1/TlOSI/CCP2,
cuando el bit T1OSCEN está a cero.

9
Si T1SYNC se pone a cero, entonces la entrada de reloj externa se sincroniza con los relojes
de fase interiores. La sincronización se hace después de la fase del preescaler. En el
preescaler la fase de la señal de reloj es por lo tanto asíncrona.

En este modo de trabajo, durante el modo SLEEP el TIMER1 no se incrementa aún cuando
la señal de reloj externa esté’ presente. El preescaler sin embargo continúa incrementándose.

b. Modo de funcionamiento del TIMER1 como Contador Asíncrono

Cuando el bit de control T1SYNC (T1CON <2>) se poner a uno, la señal de reloj externa no
se sincroniza. El contador sigue realizando la cuenta de forma asíncrona respecto a la fase de
la señal de reloj interna. El contador continúa la cuenta incluso en el modo SLEEP y puede
generar una interrupción por desbordamiento que despierta al procesador. Hay que tener
especial cuidado con el software al leer o escribir el contador.

Cuando se trabaja en el modo contador asíncrono, el TIMER1 no puede usarse como base de
tiempos para el módulo CCP (Captura y comparación-PWM).

Por último, a continuación se indica los modos del Timer 1, como temporizador y contador,
indicando los bits que afectan su operación y la manera en que lo hacen:

1. Modo temporizador

En este modo el Timer 0 se incrementa (si no se considera preescalador) en cada ciclo de


instrucción (a la frecuencia Fosc/4). Este modo se selecciona limpiando el bit
TMR1CS (T1CON<1>).

Este modo se selecciona poniendo a cero el bit TMR1CS (T1CON <1>. En este modo la
señal de reloj es el reloj interno del microcontrolador FOSC/4. En este modo de trabajo el
bit T1SYNC (T1CON <2>) no tiene ningún efecto ya que el reloj interno está siempre
sincronizado.

El preescalador que se puede intercalar entre el reloj Fosc/4 y el registro TMR1 puede
tener sólo uno de 4 valores: 1/1, 1/2, 1/4 y 1/8.

2. Modo contador

El Timer 1 también puede operar como contador, en este último caso, la entrada a
contar se toma de la patita externa RC0/T1OSO/T1CKI.

En este modo puede trabajar como contador síncrono o asíncrono. Cuando el TIMER1 se
está incrementando según le llegan los impulsos externos, los incrementos ocurren en los
flancos de subida. Después de que el TIMER1 se ha configurado como contador, debe
producirse un flanco de bajada antes de empezar a contar.

10
Nota. Las flechas indican los incrementos del contador.

6.2.2. Características del TIMER1

A continuación se describen algunas características del TIMER 1:

1. Lectura y escritura en el TIMER1 cuando se trabaja en el modo contador asíncrono

Se pueden leer los contadores TMR1H y TMR1L mientras la señal externa del contador se
está recibiendo (teniendo cuidado con el hardware). Sin embargo, el usuario debe tener en
cuenta que el contador es de 16 bits y se pueden tener ciertos problemas al leer los dos
registros de ocho bits, ya que el contador puede desbordarse entre las lecturas.

Para escribir en él, se recomienda que el usuario simplemente pare el contador y escriba los
valores deseados. Cuando se escribe el registro del contador puede haber conflicto mientras
este se está incrementando. Esto puede producir un valor imprevisible en el contador.

2. Habilitación/deshabilitación del Timer 1

El Timer 1 también posee un bit para habilitación/deshabilitación, este es el bit


TMR1ON (T1CON<0>) y habilita en alto.

Además, el Timer 1 posee una entrada interna de RESET, el cual puede ser activado por
uno cualquiera de los módulos CCP que se describirán más adelante.

3. Registro T1CON: Registro de control del TIMER1 (dirección 10h)

A continuación se describe el principal registro relacionado con el Timer 1 y todos sus


bits, excepto los que tienen que ver con el modo contador:

U-0 U-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0


--- --- TlCKPS1 TlCKPS0 T1OSCEN #TlSYNC TMR1CS TMR1ON
Bit 7 Bit 0

bit 7-6: No implementados: Se lee como “0”

bit 5-4: TlCKPS1:T1CKPS0: bit de selección del preescaler de la señal de reloj


del TIMER1
00 = valor del preescaler 1:1
01 = valor del preescaler 1:2
11
10 = valor del preescaler 1:4
11 = valor del preescaler 1:8

Observación: La cuenta interna del preescalador es limpiada cuando


se hace una escritura a cualquiera de los registros TMR1H o TMR1L.

bit 3: T1OSCEN: bit de habilitación del oscilador del TIMER1. Cuando se


emplea un oscilador externo, hay que poner este bit a 1. El TMR1 puede
trabajar a una frecuencia totalmente independiente de la del sistema.
1 = Habilita el oscilador Nota. El oscilador y la resistencia de
0 = Deshabilita el oscilador desconectan para reducir el consumo

bit 2: #TlSYNC: bit de control de sincronización de la señal de entrada.


Con TMR1CS = 1
1= No sincroniza la entrada de reloj externa
0 = Sincroniza la entrada de reloj externa

Con TMR1CS = 0
En esta condición se ignora. El TIMER1 utiliza el reloj interno cuando
TMRICS=0

bit 1: TMR1CS: bit de selección de la fuente de reloj del TIMER1


1 = Reloj externo por el pin RC0/T1OSO/T1CK1 (flanco ascendente)
0 = Reloj interno (FOSC/4)

bit 0: TMR1ON: TIMER1. activo. Hace entrar o no en funcionamiento el


TIMER1.
1 = Habilita el TIMER1
0 = Deshabilita el TIMER1

4. Resumen de registros asociados al TIMER1

En la siguiente tabla se muestran los registros principales que controlan el comportamiento


del TIMER1 y la distribución de los bits.

Valor en el
Valor en
Dirección Nombre Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 resto de
POR,BOR
Reset
0Bh,8Bh
INTCON GIE PEIE T0IE INTE RBIE TOIF INTE RBIF 0000 000x 0000 000u
10Bh,18Bh
0Ch PIR1 PSPIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF 0000 0000 0000 0000
0Bh PIE1 PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE 0000 0000 0000 0000
0Eh TMR1L Registro de carga del byte de menor peso del registro de 16 bits de TMR1 xxxx xxxx uuuu uuuu
0Fh TMR1H xxxx xxxx uuuu uuuu
10h T1CON --- --- T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON --xx xxxx --uu uuuu

Leyenda: x = desconocido, u = inalterado; - = no implementado se lee como ‘0’. Las celdas


sombreadas no son usadas por el TIMER1.

Nota 1: Los bits PSPIE y PSPIF están reservados para el PIC16F873/876, mantener estos
bit’s a cero.
12
6.3. El Módulo del Timer 2
El Timer 2 es un temporizador (sin opción de trabajar como contador) de 8 bits. Su
registro principal denominado TMR2 (11h) es un registro de 8 bits que se incrementa
continuamente a la frecuencia seleccionada de Fosc/4 dividida por un preescalador.

En la siguiente figura se muestra un diagrama de bloques del módulo del Timer2.

A continuación se describe cada uno de los módulos:

a. El preescalador

La frecuencia que incrementa al registro TMR2 puede ser dividida por un preescalador por
un factor de 1/1, 1/4 o 1/16, seleccionable por los bits T2CKPS1:T2CKPS0
(T2CON<1:0>)

b. El Registro de comparación o de Periodo

En operación, el contenido del registro TMR2 se compara continuamente con un


registro de periodo denominado PR2 (92h) cuyo valor podemos establecer por software.
Cada vez que la cuenta de TMR2 es igual a PR2, se reinicia el conteo en TMR2 desde cero,
y además se genera una señal de salida, la cual es tratada por un postescalador, para poder
generar una señal TMR2IF (PIR1<1>) que puede ser usada para solicitar una
interrupción, o para ser leída por poleo.

c. El Postescalador

El postescalador divide la frecuencia con que ocurre una activación de la bandera


TMR2IF, es decir, si el valor del postescalador es 1/1, esta bandera se activará cada vez
que TMR2 se reinicie, en cambio, si es 1/16 (por ejemplo), TMR2IF se activará cada 16
reinicios de TMR2. En forma similar a los otros dos Timers, esta bandera debe ser
limpiada previamente, si se quiere detectar su activación, esto puede ser hecho en la
rutina de atención a la interrupción, o bien en la rutina que la detecta por poleo.

El valor de división del postescalador puede establecerse por software mediante los bits
T2OUPS3:T2OUPS0 (T2CON<6:3>).
13
6.3.1. Características del Timer 2
1. Operaciones con el TIMER2

El Timer2 tiene emparejado el registro PR2 que ocupa la posición de 92H del banco de
registros especiales, de manera que al incrementarse TMR2 y coincidir con el valor del
registro PR2 se produce un impulso de salida, estos impulsos pueden ser divididos por un
postescaler antes de activar el flag TMR2FI (PIR1<1>).

El registro PR2 es un registro de 8 bits que puede ser escrito y leído, este registro toma el
valor FF después de un Reset.

El postscaler permite dividir la señal por cualquier valor comprendido entre 1:1 hasta 1:16,
para controlar el postescaler se utilizan los bit TOUTPS3: TOUTPS0 (T2CON <6:3>).

El Preescaler y el Postescaler se ponen a cero cuando:

• Se escribe sobre el registro TMR2


• Se escribe sobre el registro T2CON
• Se produce un reset (POR, MCLR restablecido, WDT reestablecido o BOR)

TMR2 no se pone a cero cuando se escribe en T2CON

2. Registro T2CON: Registro de Control del TIMER2 (dirección 12h)

A continuación se describe el principal registro relacionado con el Timer 2 y todos sus


bits.

U-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0


--- TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0
Bit 7 Bit 0

bit 7: No implementado: Se lee como 0

bit 6-3: TOUTPS3:TOUTPS0: bit de selección del rango del divisor del Postescaler
para el TIMER2
0000 = Divisor del postescaler 1:1
0001 = Divisor del postescaler 1:2
0010 = Divisor del postescaler 1:3
0011 = Divisor del postescaler 1:4
0100 = Divisor del postescaler 1:5
0101 = Divisor del postescaler 1:6
0110 = Divisor del postescaler 1:7
0111 = Divisor del postescaler 1:8
1000 = Divisor del postescaler 1:9
1001 = Divisor del postescaler 1:10
1010 = Divisor del postescaler 1:11
1011 = Divisor del postescaler 1:12

14
1100 = Divisor del postescaler 1:13
1101 = Divisor del postescaler 1:14
1110 = Divisor del postescaler 1:15
1111 = Divisor del postescaler 1:16

Observación: La cuenta interna del postescalador y el preescalador


es limpiada cuando ocurre cualquiera de los siguientes eventos: Una
escritura a alguno de los registros TMR2 o T2CON o bien, un Reset
del sistema de cualquier tipo (POR, MCLR, WDT, o BOR).

bit 2: TMR2ON: bit de activación del TIMER2


1:= habilita el funcionamiento del TIMER2
0 = Inhibe el funcionamiento del TIMER2

bit 1-2: T2CKPS1:T2CKPS0 Selección del rango de divisor del Preescaler del TIMER2
00 = Divisor del Preescaler 1:1
01 = Divisor del Preescaler 1:4
1x = Divisor del Preescaler 1:16

3. Interrupciones del TIMER2

El temporizador TMR2 tiene un flag de desbordamiento el TMR2IF (<1>PIR1).

El TMR2 tiene asociado un Registro de Periodo PR2, que ocupa la posición 92h. Cuando el
valor de cuenta de TMR2 coincide con el valor cargado en PR2 se genera un impulso en la
salida EQ (ver la Figura anterior) y se pone a cero el TMR2. Estos impulsos pueden ser
divididos por el postdivisor antes de activar el flag TMR21F(<1> PIR1).

El temporizador puede producir una interrupción si se pone a 1 el bit TMR2IE (<1> PIE1)

4. Registros asociados al TMR2

En la siguiente tabla se muestran los registros principales que controlan el comportamiento


del TIMER2 y la distribución de los bits.

Valor en
Valor en
Dirección Nombre Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
POR,BOR
el resto
de Reset
0Bh,8Bh
10Bh, INTCON GIE PEIE TOIE INTE TOIF RBIE INTE RBIF 0000 000x 0000 000u
18Bh
0Ch PIR1 PSPIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF 0000 0000 0000 0000
0Bh PIE1 PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE 0000 0000 0000 0000
11h TMR2 Módulo Del registro Timer2 0000 0000 0000 0000
12h T2CON --- TOUTPS3 TOUPS2 TOUPS1 TOUPS0 TMR2ON T2CKPS1 T2CKPS0 -000 000 -000 0000
92h PR2 Registro de período del TMR2 1111 1111 1111 1111

Leyenda: x = desconocido, u = inalterado; - = no implementado se lee como ‘0’. Las celdas


sombreadas no son usadas por el TIMER2

15
Nota 1: Los bits PSPIE y PSPIF están reservados para el PIC16F873/876, mantener estos
bits a cero.

16
Ejercicio 1

Manejo del Timer 0 como contador

El siguiente programa realiza el conteo del número de veces que produce una transición
de bajo a alto en la patita T0CKI. El valor del contador se incrementará una vez por cada
ocho transiciones y será enviado a través del puerto serie para ser desplegado en la
pantalla de una PC. El reloj de trabajo del microcontrolador es de 4 MHz.

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

INICIO

W←TMR0

envbayte

W←0x0D

envia

W←0x0A

envia

Los diagramas de flujo de las Subrutinas: envbyte, asc, envia e initrans; están desarrollados en el
Capítulo 5 “El Convertidor Analógico – Digital”.

2. Código en Assembler:
;****************************************************************************
;* Este programa realiza el conteo de una señal conectada a la patita T0CKI *
;* el valor del contador lo envía a través del puerto serie, en 2 bytes *
;* que representan los nibles (hexadecimal) del TMR0, para su despliegue en *
;* en una PC. *
;****************************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"

17
;Setup of PIC configuration flags
__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

;Define variables
CBLOCK 0x20
Msnib
Lsnib
ENDC

org 0x00 ;Vector reset

inic CALL initrans ;inicializa el puerto serie para transmisión


BCF STATUS,RP0 ;Banco 0
CLRF TMR0 ;inicializa la cuenta de TMR0
BSF STATUS,RP0 ;Banco 1
MOVLW 0xE2 ;dato de configuración para el timer0
MOVWF OPTION_REG ;configura modo contador, transición positiva,
;preescalador 1/8 asignado a timer0
BCF STATUS,RP0 ;Banco 0

ciclo MOVF TMR0,W ;lee cuenta actual


CALL Envbyte ;envía el valor por el puerto serie
MOVLW 0x0D ;carga carácter <CR>
CALL envia ;lo envía
MOVLW 0x0A ;carga carácter <LF>
CALL envia ;lo envía
GOTO ciclo ;repite

;***************************************************************
; Subrutina que envía el byte en W por el puerto serie, separado
; en los códigos ASCII de sus dos nibbles hexadecimales
;***************************************************************
msnib EQU 0x22
lsnib EQU 0x23
Envbyte:
MOVWF msnib ;pone byte en msnib
MOVWF lsnib ;y una copia en lsnib
SWAPF msnib,1 ;intercambia nibbles en lsnib
MOVLW 0x0F ;máscara para limpiar el nibble alto
ANDWF msnib,1 ;limpia parte alta de msnib
ANDWF lsnib,1 ;limpia parte alta de lsnib

MOVF msnib,W ;carga msnib en W


CALL asc ;obtiene código ASCII equivalente
CALL envia ;lo envía por el puerto serie
MOVF lsnib,W ;carga lsnib en W
CALL asc ;obtiene código ASCII equivalente
CALL envia ;lo envía por el puerto serie
RETURN

asc ADDWF PCL,1 ;Calcula el código a retornar


;Saltando W instrucciones adelante
DT "0123456789ABCDEF"

;****************************************************************
;Subrutina para inicializar el puerto serie USART como transmisor
;a 9600 Bauds, considerando un cristal de reloj de 4 MHZ
;****************************************************************
initrans:
BCF STATUS,RP1
BSF STATUS,RP0 ;banco 1
BSF TXSTA,BRGH ;pone bit BRGH=1 (velocidad alta)
MOVLW 0x19 ;valor para 9600 Bauds (Fosc=4 Mhz)
MOVWF SPBRG ;configura 9600 Bauds
BCF TXSTA,SYNC ;limpia bit SYNC (modo asíncrono)
BSF TXSTA,TXEN ;pone bit TXEN=1 (habilita transmisión)
BCF STATUS,RP0 ;regresa al banco 0
18
BSF RCSTA,SPEN ;pone bit SPEN=1 (habilita puerto serie)
RETURN

;***************************************************************
;Subrutina para enviar el byte guardado en W por el puerto serie
;***************************************************************
envia BSF STATUS,RP0 ;banco 1
esp BTFSS TXSTA,TRMT ;checa si el buffer de transmisión
GOTO esp ;si está ocupado espera
BCF STATUS,RP0 ;regresa al banco 0
MOVWF TXREG ;envía dato guardado en W
RETURN

END

Observación. Mediante el programa anterior s e p u ed e realizar el conteo cada ocho


“rebotes” provocados por un botón pulsador, basta con conectar la salida de dicho botón a
la patita T0CKI. Al hacer lo anterior se verá que por cada pulsación del botón se incrementa la
cuenta no de uno en uno, sino en un valor mayor por el efecto de los rebotes. Esto también
quiere decir, que si no se desea que el contador se vea afectado por el rebote de la señal a
contar, se deberá incluir un limpiador de rebotes por hardware, externo al PIC.

Análisis del código

En primer lugar configuramos el registro OPTION_REC.

Registro OPTION_REG

OPTION_REG = E2

#RBPU INTEDG T0CS T0SE PSA PS2 PS1 PS0


1 1 1 0 0 0 1 0
Bit 7 Bit 0

T0CS = 1, Seleccionado como reloj la patita T0CKI (modo contador)


T0SE = 0, El incremento de TMR0 en la transición de bajo a alto de T0CKI
PSA = 0, Asigna el preescalador al Timer0.
PS2=0, PS1=1 y PS0=0; Bits de selección del valor del preescaler a 1/8

Programa principal. Este programa lee el valor de la cuenta actual de TMR0, envía el valor por el puerto
serie, luego carga el carácter <CR> y lo envía, y también carga el carácter <LF> y lo envía.

Subrutinas. Son cuatro: Envbyte, asc, initrans y envia:

Envbyte. Subrutina que envía el byte W por el puerto serie, separados en los códigos ASCII de
sus dos nibbles hexadecimales.

Registro TMR0:

Bit 7 Bit 0

Almacenar los nibles de TMR0 en msnib y lsnib, como se muestra en los siguientes gráficos.

19
msnib

Bit 7 Bit 0
lsnib

Bit 7 Bit 0

asc. Subrutina para convertir un nible a código ASCCI.

initrans. Subrutina para inicializar el puerto serie USART como transmisor a 9600 Bauds,
considerando un cristal de reloj de 4 MHZ.

envia. Subrutina para enviar el byte guardado en W por el puerto serie.

Ejemplo 2

Manejo del Timer 0 como temporizador

El siguiente programa utiliza el Timer 0 para realizar una pausa de máxima duración, con un
reloj de trabajo del microcontrolador de 4 MHz, es pausa se intercala en el encendido/apagado
de un LED conectado a la patita RC0. Es decir, el LED parpadeará a la frecuencia F que se
puede calcular como sigue:

F = 1/(TH+TL)

En donde TH es el tiempo de encendido y TL es el tiempo de apagado del LED. Como en el


ejemplo son iguales, usaremos sólo T = TH = TL, por lo tanto

F = 1/(2T)

Para calcular T con una frecuencia de reloj Fosc dada y un valor del preescalador 1/M, para
un ciclo de N incrementos del timer 0 tendremos que la duración (Tciclo) del ciclo será:

TH = Tciclo = N*M*(4/Fosc)

donde:
N, Cuenta (incrementos)
M, Preescaler (divisor de frecuencia)
Fosc, Reloj del cristal

Así, para una duración máxima M = 256, N = 256 tendremos:

TH = TMAX = 262144/Fosc

Para un reloj de 4 Mhz tendremos


20
TH = TMAX = 65,536 mseg
F = 1/(2 TH) = 1/(2*65,536 ms)
F = 7,63 Hertz

Y la frecuencia de parpadeo del LED será F = 7,63 Hertz.

Es decir,

TH = Tciclo = N*M*(4/Fosc)
Fciclo = Fosc/4 * 1/M * 1/N

donde:
Fosc/4, Frecuencia de oscilación (cuenta Timer0)
1/M, Divisor de frecuencia

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

INICIO

RC0←1

pausa

RC0←0

pausa

El diagrama de flujo de la Subrutina iniciatimer0, no es necesario porque esta subrutina únicamente


sirve para inicializar la configuración del Timer0: modo temporizador, preescalador 1/256 asignado a
Timer0.

Diagrama de flujo de la Subrutina pausa:

21
pausa

W←N1

TMR0←W

NO
T0IF=1

SI

T0IF←0

FIN

2. Código en Assembler:
;*****************************************************************
;* Este programa hace parpadear un LED conectado a la patita RC0 *
;* Usa el timer 0 para generar una pausa de 65,536 mseg de *
;* duración (supone un cristal de 4 Mhz). La frecuencia de *
;* parpadeo del LED es de 7.63 Hertz aprox. *
;*****************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"

;Setup of PIC configuration flags


__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

org 0x00 ;Vector reset

call iniciatimer0
inic BSF STATUS,RP0 ;Banco1
BCF TRISC,0 ;patita RC0 como salida
BCF STATUS,RP0 ;Banco 0

rep BSF PORTC,0 ;enciende LED


CALL pausa ;pausa de 65,536 mseg
BCF PORTC,0 ;apaga LED
CALL pausa ;pausa de 65,536 mseg
GOTO rep

;* Subrutina de configuración timer 0


;*************************************
iniciatimer0
N1 EQU 0x00

BCF INTCON,T0IF ;limpia bandera de sobreflujo


BSF STATUS,RP0 ;Banco 1
MOVLW 0xC7 ;dato de configuración para el timer0
22
MOVWF OPTION_REG ;modo temporizador, preescalador 1/256 asignado a timer0
BCF STATUS,RP0 ;Banco 0
Return

;* Subrutina de pausa de 65,536 mseg


;*************************************
pausa MOVLW N1 ;número de incrementos del timer
MOVWF TMR0 ;inicializa la cuenta de TMR0

repite BTFSS INTCON,T0IF ;checa bandera de sobreflujo (cambio de 255 a 0)


GOTO repite ;si no se ha activado, espera
BCF INTCON,T0IF ;si ya se activó, la desactiva
RETURN

END

Análisis del código

En primer lugar configuramos el registro OPTION_REC.

Registro OPTION_REG

OPTION_REG = C7

RBPU# INTEDG T0CS T0SE PSA PS2 PS1 PS0


1 1 0 0 0 1 1 1
Bit 7 Bit 0

T0CS = 0, Selecciona el reloj del ciclo de instrucción interno (CLKout) (modo temporizador)
T0SE = 0, No importa
PSA = 0, Asigna el preescalador al Timer0.
PS2=1, PS1=1 y PS0=1; Bits de selección del valor del preescaler a 1/256

Programa principal. Este programa enciende LED por un tiempo de 65,536 mseg, luego apaga
LED por el mismo tiempo de 65,536 mseg.

Subrutinas. Exite dos subrurinas iniciatimer0 y pausa:

pausa, es una subrutina de pausa de 65.536 mseg, donde N1 es el valor inicial del Timer 0.

iniciatimer0, esta subrutina configura el Timer 0 y chequea la bandera de sobre flujo (cambio de
255 a 0), si no se ha activado T0IF espera, si ya se activó la desactiva.

Observación

La rutina de pausa se puede modificar para una duración de N incrementos del Timer 0,
simplemente definiendo N1 como valor inicial, es decir:

N1 = 256 – N
donde:
N1, Cuenta inicial del Timer0
N, Incrementos Timer0

23
Para el cálculo de cualquier tiempo

tiempo = Tciclo * Mz
donde:
Tciclo, Duración del ciclo
Mz, Número cruces por cero o número de ciclos del TMR0 (Cuentas del TMR0)

Por ejemplo, un retardo de 1 seg se calculará de la siguiente forma:

N =250 (N1 = 256 – 250 = 6), 6 será el valor inicial del TMR0
M = 32
Fosc = 4 MHz
Tciclo = N*M*(4/Fosc)

Tciclo = 250 * 32 * (4/4*106) seg.


= 0,008 seg

tiempo = Tciclo * Mz
Mz = tiempo / Tciclo
= 1 / 0,008
= 125

NOTA. Se debe tener en cuenta que Mz siempre debe ser un valor entero.

El código para la subrutina de 1seg, será:

;* Subrutina de pausa de 1 seg


;*************************************
Mz RES 1
N1 EQU 0x06

Delay
;El registro Mz se inicializa a 125 cruces por cero
movlw 125
movwf Mz

;Lazo de conteo
DelayLoop
movlw N1
movwf TMR0 ;inicializa la cuenta de TMR0 a N1

Loop btfss INTCON,T0IF ;checa bandera de sobreflujo (cambio de 255 a 0)


goto Loop ;si no se ha activado, espera
bcf INTCON,T0IF ;si ya se activó, la desactiva

decfsz Mz,1 ;cuenta Mz cruces por cero


goto DelayLoop

return

Nota: Para un reloj de 4 Mhz, una duración máxima M = 256, N = 256 se tendrá:

Tciclo = N*M*(4/Fosc)

Tciclo = TMAX = 256*256* (4/Fosc)


24
Tciclo = TMAX = 65,536 mseg

Ejemplo Práctico

Realizar un intermitente con cuatro leds cuya frecuencia de intermitencia con un retardo igual a
un segundo utilizando el registro TMR0. El reloj de trabajo del microcontrolador es de 4 MHz.

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

INICIO

Shift←0x01

PORTB←Shift

C←0

Shift←rot.izq. Shift

NO
Shift<4>=0 Shift←Inter. nibles

SI

Delay

Diagrama de flujo de la Subrutina Delay:

25
Delay

Mz←125

TMR0←N1

NO
T0IF=1

SI

T0IF←0

Mz←Mz-1

NO
Z=1

SI

FIN

2. Código en Assembler:

El código de este ejemplo está disponible en SEQTMR0.ASM y se muestra a continuación:

;**************************************************
;
; SEQTMR0.ASM
;
;**************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877.INC"

;Setup of PIC configuration flags


__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

;Define constantes
N1 EQU 0x06

;Define variables

26
CBLOCK 0x20
Mz
Shift
ENDC

org 0x00 ;Vector reset

;Conmuta al segundo banco de registros


bsf STATUS,RP0

;Definicion de las lineas de I/O (0=Salida, 1=Ingreso)


movlw 11110000B
movwf TRISB

;Asigna el PRESCALER a TMR0 en la configuracion a 1:32


movlw 00000100B
movwf OPTION_REG

;Conmuta al primer banco de registro


bcf STATUS,RP0

;El registro Shift se utiliza para desplazar los bit’s


;Shift se setead a 1 para iniciarlizar el ciclo del primer led.
movlw 00000001B
movwf Shift

; Bucle de flujo
MainLoop

;Envia al Puerto B el registro Shift, de modo que cada bit es 1 en


;Shift para que se encienda el LED.
movf Shift,W
movwf PORTB

;Para encender las luces debe utilizar la instrucción RLF


;hacer el cambio a la izquierda de los bits contenidos en
;un registro y el bit 0 del estado del bit carry.
;Por esta razón, antes de la instrucción RLF borrar el bit
;de acarreo de la instrucción: bcf STATUS,C.
bcf STATUS,C
rlf Shift,F

;Cuando llega al cuarto 4 bit se invierte los primeros


;cuatro bits del registro Shift con los segundos cuatro bits,
;con el fin de reiniciar el ciclo desde el bit 0.
;¿Qué pasa con los bits del registro de cambio durante
;la ejecución de este bucle?:
; 00000001 <--- Valor inicial (primer led de acceso)
; 00000010 rlf
; 00000100 rlf
; 00001000 rlf
; 00010000 rlf
; En este momento se ejecuta la instrucción swapf
;obteniendo: 00000001
btfsc Shift,4
swapf Shift,F

;Introducir un retraso entre el encendido de un led y el otro


call Delay

; Volver a ejecutar el bucle


goto MainLoop

;* Subrutina de pausa de 1 seg


;*************************************

;Inserción de un retraso de un segundo utilizando el registro TMR0.


27
;El retraso se obtiene de la frecuencia de salida del PRESCALER
;igual a: 4Mhz / 4 / 32 = 31250 Hz
;... dividido por 250 del TMR0 de 32250 / 250 = 125 Hz
;... y por 125 del contator Count 125 / 125 = 1Hz
;Por lo que debe ser inicializado TMR0 a N1=6, 256 a 6 = 250 veces.
Delay
;El registro Mz se inicializa a 125 cruces por cero
movlw 125
movwf Mz

;Lazo de conteo
DelayLoop
movlw N1
movwf TMR0 ;inicializa la cuenta de TMR0 a N1

Loop btfss INTCON,T0IF ;checa bandera de sobreflujo (cambio de 255 a 0)


goto Loop ;si no se ha activado, espera
bcf INTCON,T0IF ;si ya se activó, la desactiva

decfsz Mz,1 ;cuenta Mz cruces por cero


goto DelayLoop

return

END

Análisis del código SEQTMR0.ASM

En primer lugar programar el PRESCALER para obtener una frecuencia de conteo apropiada,
insertando las siguientes instrucciones al inicio del programa:

movlw 00000100B
movwf OPTION_REG

En la práctica se debe programar el bit T0CS a 0 para seleccionar como fuente de conteo el reloj
del PIC, el bit PSA a 0 para asignar el PRESCALER al registro TMR0 en lugar de al Watch Dog
Timer (del que trataremos más adelante) y los bits de configuración del PRESCALER a 100
para obtener una frecuencia de división igual a 1:32. Como se muestra el registro OPTION en la
figura.

RBU INTDEG T0CS T0SE PSA PS2 PS1 PS0


0 0 0 0 0 1 0 0

TOCS=0 , Selección del reloj para temporizador


PSA=0 , Selección del Preescaler
PS2=1, PSA1=, PS0=0 , Para obtener una frecuencia de división igual a 1:32

Valor de OPTION_REG= 0x04

La frecuencia de conteo que se obtiene en TMR0 será igual a:

Fosc = 1Mhz / 32 = 31.250 Hz

La subrutina Delay deberá utilizar el registro TMR0 para obtener un retardo igual a un segundo.
Entonces, las primeras instrucciones que se escribe en Delay son:

28
movlw 125
movwf Mz
y
movlw N1
movwf TMR0

Las segundas dos almacenan en TMR0 el valor N1=6 de modo que el registro TMR0 alcanza el
cero después de 250 cuentas (256 - 6 = 250), obteniendo así una frecuencia de paso por cero
del TMR0 igual a:

31.250 / 250 = 125 Hz

Las instrucciones siguientes almacenan en un registro de 8 bits (Count) el valor 125, de tal modo
que, decrementando este registro en uno por cada paso por cero de TMR0, se obtenga una
frecuencia de pasos por cero del registro Count igual a:

125/125 = 1Hz

Las instrucciones insertadas en el bucle DelayLoop se ocupan por lo tanto de controlar si TMR0
ha alcanzado el cero, luego de reinicializarlo a 6 y decrementar el valor contenido en Count.
Cuando Count alcance también el valor cero, entonces habrá trascurrido un segundo y la
subrutina podrá retornar control al programa que la llamó.

Ejemplo 3

Manejo del Timer 1 como temporizador

A continuación se describe un programa similar al Ejemplo 2 , en el que se utiliza el Timer


1 para realizar una pausa de máxima duración, co n u n reloj de trabajo del
microcontrolador de 4 MHz, la pausa se intercala en el encendido / apagado de un LED
conectado a la patita RC0, es decir, el LED parpadeará a la frecuencia F que se puede calcular
como sigue:

F = 1/(TH+TL)

En donde TH es el tiempo de encendido y TL es el tiempo de apagado del LED. Como en el


ejemplo son iguales, usaremos sólo T = TH = TL, por lo tanto

F = 1/(2T)

Para calcular T con una frecuencia de reloj Fosc dada y un valor del preescalador 1/M, para
un ciclo de N incrementos del registro TMR1 tendremos que la duración (Tciclo) del ciclo
será:

T = Tciclo = N*M*(4/Fosc)

Así, para una duración máxima M = 8, N = 65536 tendremos:

TMAX = 2097152/Fosc
29
Para un reloj de 4 Mhz tendremos

TMAX = 524,288 mseg

Y por lo tanto la frecuencia de parpadeo del LED será F = 0,95367 Hertz.

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

INICIO

RC0←1

pausa1

RC0←0

pausa1

El diagrama de flujo de la Subrutina iniciatimer1, no es necesario porque esta subrutina únicamente


sirve para inicializar la configuración del Timer1: modo temporizador, preescalador 1/8, habilita Timer1.

Diagrama de flujo de la Subrutina pausa1:

30
pausa1

W←N1

TMR1H←W

W←N0

TMR1L←W

NO
TMR1IF=1

SI

TMR1IF←0

FIN

2. Código en Assembler:
;*****************************************************************
;* Este programa hace parpadear un LED conectado a la patita RC0 *
;* Usa el timer 1 para generar una pausa de 524,288. mseg de *
;* duración (supone un cristal de 4 Mhz). La frecuencia de *
;* parpadeo del LED es de 0,95367 Hertz aprox. *
;*****************************************************************
include "p16f877.inc"

org 0x00

call iniciatimer1

inic BSF STATUS,RP0 ;Banco1


BCF TRISC,0 ;patita RC0 como salida
BCF STATUS,RP0 ;Banco 0

rep BSF PORTC,0 ;enciende LED


CALL pausa1 ;pausa de 524,288 mseg
BCF PORTC,0 ;apaga LED
CALL pausa1 ;pausa de 524,288 mseg
GOTO rep

;* Subrutina configuración Timer 1


;*************************************
iniciatimer1
N1 EQU 0x00
31
N0 EQU 0x00
BCF PIR1,TMR1IF ;limpia bandera de sobreflujo
MOVLW 0x31 ;dato de configuración para el timer1
MOVWF T1CON ;modo temporizador, preescalador 1/8, habilita timer 1
return

;* Subrutina de pausa de 524,288 mseg


;*************************************
pausa1
MOVLW N1 ;número de incrementos del timer msb
MOVWF TMR1H ;inicializa la cuenta de TMR1
MOVLW N0 ;número de incrementos del timer lsb
MOVWF TMR1L ;inicializa la cuenta de TMR1

repite BTFSS PIR1,TMR1IF ;checa bandera de sobreflujo (cuenta=65536)


GOTO repite ;si no se ha activado, espera
BCF PIR1,TMR1IF ;si ya se activó, la desactiva
RETURN ;retorna

end

Análisis del código

En primer lugar configuramos el registro T1CON.

Registro T1CON

T1CON = 0x31

--- --- T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON


0 0 1 1 0 0 0 1
Bit 7 Bit 0

T1CKPS1=1, T1CKPS0=1 , Bits de selección del valor del preescalador 1/8


T1OSCEN=0 , Deshabilita el oscilador externo del TIMER1
T1SYNC=0 , Sincroniza la entrada de reloj externa
TMR1CS=0 , Selecciona el reloj interno (FOSC/4)
TMR1ON=1 , Habilita el Timer1

El programa es idéntico al Ejemplo 2, lo único que cambia son las subrutinas de iniciatimer1 y
pausa1, las cuales ahora se han realizado con el Timer 1 y no con el Timer 0.

Programa principal. Este programa enciende LED por un tiempo de 524,288 mseg, luego apaga
LED por el mismo tiempo de 524,288 mseg.

Subrutinas. Exite dos subrurinas iniciatimer1 y pausa1:

pausa1, es una subrutina de pausa de 524,288 mseg, donde N1 es el valor inicial del Timer 1.

iniciatimer1, esta subrutina configura el Timer 1 y chequea la bandera de sobre flujo (cambio de
65535 a 0), si no se ha activado TMR1IF espera, si ya se activó la desactiva.

Observación

La rutina de pausa se puede adaptar para una duración de N ciclos del Timer 1,
32
simplemente definiendo como N1:N0 valores iniciales, por lo que N es lo falta para ser 65536,
es decir:

N1:N0 = 65536 - N

Por ejemplo, utilizando el Timer1 obtener un Delay de 1.5 seg, con una frecuencia de
oscilación de 4 MHz.

Primero se calcula el Tciclo máximo con los siguientes valores:

N = 65536; es el máximo valor que alcanza con FFFF


M = 8; es el valor máximo del preescalador en el timer1 de 1/8
Fosc = 4MHz

T = Tciclo = N*M*(4 / Fosc)


Tciclomax = 65536*8* (4 / 4MHz)
Tciclomax = 0.524288 seg

Luego, se debe calcular el número de cruces por cero Mz, porque no alcanza Tciclomax = 524,288
mseg a los 1.5 seg, mediante la siguiente ecuación:

tiempo = Tciclo * Mz
Mz = tiempo / Tciclo
Mz = 1,5 seg / 0.524288 seg
Mz = 2,86102

Pero Mz no es entero, por lo que se debe hacer un nuevo cálculo con un nuevo Tciclo, en donde:
tiempo = 1.5 seg
Tciclo = 12 mseg (se escoge cualquier valor entero múltiplo de M*N y mucho menor a
Tciclomax = 0.524288 seg)

Mz = 1,5 seg / 0,012 seg


Mz = 125
Mz = 0x7D

Ahora se debe calcular N y M en base al Tciclo:

T = Tciclo = N*M*(4 / fosc)

Donde:
M = 8 (Valor del preescalador de 1/8)
Fosc = 4MHz

12 mseg = N * 8 *(4 / 4 MHz)


N= (12 mseg * 4MHz) / 32
N= 1500

Por último, se debe determinar el valor inicial de la cuenta del Timer1:


33
N1:N0 = 65536 – N
N1:N0 = 65536 – 1500 = 64036
N1:N0 = 0x FA24

Entonces, TMR1H y TMR1L será:


N1 = TMR1H = 0xFA
N0 = TMR1L = 0x24
;********************************************************
;* Subrutina Delay1,5s *
;* Usa el Timer1 para obtener un Delay *
;* de 1.5 seg, con fosc = 4MHz. *
;********************************************************
N1 EQU 0xFA
N0 EQU 0x24
Mz EQU 0x7D

Delay15s
MOVLW N1 ;número de incrementos del timer msb
MOVWF TMR1H ;inicializa la cuenta de TMR1

MOVLW N0 ;número de incrementos del timer lsb


MOVWF TMR1L ;inicializa la cuenta de TMR1

BCF PIR1,TMR1IF ;limpia bandera de sobre flujo

MOVLW 0x31 ;dato de configuración para el timer1


MOVWF T1CON ;modo temporizador, preescalador 1/8,
;habilita timer 1

ciclo
BTFSS PIR1,TMR1IF ;checa bandera de sobre flujo (cuenta=65536)
GOTO ciclo ;si no, se ha activado, espera
decfsz Mz,1
goto Delay15s

return

Ejemplo 4

Manejo del Timer 2 como temporizador.

¿Cuál es la máxima duración de una pausa realizada mediante el Timer 2, usando el mismo
esquema de los Ejemplos 2 y 3 de dejar pasar el tiempo transcurrido en una sola activación
de TMR2IF?. El reloj de trabajo del microcontrolador es de 4 MHz.

Solución.

Sea Tciclo la duración de la pausa, con una frecuencia de reloj Fosc dada, un valor del
preescalador 1/M, y un valor del postescalador 1/P. Para un ciclo de N incrementos del registro
TMR2, es decir, para un valor de N del registro de periodo PR2, se tiene que la duración de la
pausa dada es:
Tciclo = N*M*P*(4/Fosc)

Así, para una duración máxima P = M = 16, N = 256 (N=PR2) se tendrá:

34
TcicloMAX = 262144/Fosc

Para un reloj de 4 Mhz se tendrá:

TcicloMAX = 65,536 mseg

Y por lo tanto la frecuencia de parpadeo del LED será F = 7,63 Hertz.

Nota: Como se puede apreciar el TcicloMAX del Timer2 es igual al TcicloMAX del Timer0.

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

INICIO

RC0←1

pausa2

RC0←0

pausa2

El diagrama de flujo de la Subrutina iniciatimer2, no es necesario porque esta subrutina únicamente


sirve para inicializar la configuración del Timer2: modo temporizador, preescalador 1/16, postescalador
1/16, habilita Timer2.

Diagrama de flujo de la Subrutina pausa2:

35
pausa2

W←N3

PR2←W

NO
TMR2IF=1

SI

TMR2IF←0

FIN

2. Código en Assembler:
;*****************************************************************
;* Este programa hace parpadear un LED conectado a la patita RC0 *
;* Usa el timer 2 para generar una pausa de 65,536. mseg de *
;* duración (supone un cristal de 4 Mhz). La frecuencia de *
;* parpadeo del LED es de 7,63 Hertz aprox. *
;*****************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877.INC"

;Setup of PIC configuration flags


__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

org 0x00 ;Vector reset

call iniciatimer2

inic BSF STATUS,RP0 ;Banco1


BCF TRISC,0 ;patita RC0 como salida
BCF STATUS,RP0 ;Banco 0

rep BSF PORTC,0 ;enciende LED


CALL pausa2 ;pausa de 65,536 mseg
BCF PORTC,0 ;apaga LED
CALL pausa2 ;pausa de 65,536 mseg
GOTO rep

;* Subrutina configuración Timer 2


;*************************************
iniciatimer2
BCF PIR1,TMR2IF ;limpia bandera de sobreflujo
MOVLW 0x7F ;dato de configuración para el timer 2
MOVWF T2CON ;modo temporizador, preescalador 1/16, postescalador 1/16
;habilita timer 2
36
RETURN

;* Subrutina de pausa de 65,536 mseg


;*************************************
pausa2
N EQU 0xFF

MOVLW N ;número de incrementos del timer 2


BSF STATUS,RP0 ;Banco 1
MOVWF PR2 ;Fin de la cuenta de TMR2
BCF STATUS,RP0 ;Banco 0

repite BTFSS PIR1,TMR2IF ;checa bandera de igualdad TIMER2 y PR2


GOTO repite ;si no se ha activado, espera
BCF PIR1,TMR2IF ;si ya se activó, la desactiva
RETURN

END

Análisis del código

En primer lugar configuramos el registro T2CON.

Registro T2CON

T1CON = 0x7F

--- TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0


0 1 1 1 1 1 1 1
Bit 7 Bit 0

TOUTPS3=1, TOUTPS2=1, TOUTPS1=1, TOUTPS0=1 , Establece postescalador 1/16


TMR2ON=1 , Habilita timer 2
T2CKPS1=1, T2CKPS0=1 , Establece preestescalador 1/16

El programa es idéntico al Ejemplo 2, lo único que cambia son las subrutinas de iniciatimer2 y
pausa2, las cuales ahora se han realizado con el Timer 2 y no con el Timer 0.

Programa principal. Este programa enciende LED por un tiempo de 65,536 mseg, luego apaga
LED por el mismo tiempo de 65,536 mseg.

Subrutinas. Exite dos subrurinas iniciatimer1 y pausa1:

pausa2, es una subrutina de pausa de 65,536 mseg, donde N1 es el valor inicial del Timer 2.

iniciatimer2, esta subrutina configura el Timer 2 y chequea la bandera de sobre flujo (igualdad
TMR2=PR2), si no se ha activado TMR2IF espera, si ya se activó la desactiva.

37
6.4. Los Módulos de CCP (Captura / Comparación / PWM)
El PIC16F87X posee dos módulos CCP, denominados CCP1 y CCP2. Ambos módulos son
prácticamente idénticos con la excepción de la operación del disparo de evento especial.
Cada uno de estos dos módulos poseen un registro de 16 bits, el cual puede operar como:

• Registro de captura de 16 bits


• Registro de comparación de 16 bits
• Registro de Ciclo de Trabajo del módulo PWM de 8 bits.

Cada modo de operación requiere como recurso uno de los timers del PIC. En la
siguiente tabla se muestran los timers usados por cada modo:

Modo de operación Recurso


del CCP utilizado
Captura Timer 1
Comparación Timer 1
PWM Timer 2

A continuación se da un breve resumen de los registros relacionados con cada módulo:

a. El Módulo CCP1

El registro principal de este módulo (CCPR1) se compone de dos registros de 8 bits,


denominados CCPR1H (16h) (parte más significativa) y CCPR1L (15h) (parte menos
significativa). La operación del módulo se controla mediante el registro CCP1CON y el
disparo de evento especial, el cual es generado al alcanzarse la igualdad en un registro de
comparación reseteará el Timer 1.

b. El Módulo CCP2

El registro principal de este módulo (CCPR2) se compone de dos registros de 8 bits,


denominados CCPR2H (parte más significativa) y CCPR2L (parte menos significativa). La
operación del módulo se controla mediante el registro CCP2CON y el disparo de evento
especial, el cual es generado al alcanzarse la igualdad en un registro de comparación
reseteará el Timer 1, e iniciará una conversión analógico/digital (si el módulo
convertidor A/D está habilitado). Esta última característica es la diferencia entre los dos
módulos.

6.4.1. Características del módulo CCP

1. Selección del modo de operación

La selección del modo en que trabajara el módulo CCPx se realiza mediante los cuatro bits
menos significativos del registro CCPxCON, es decir, mediante los bits CCPxM3:CCPxM0
(CCPxCON<3:0>) de acuerdo a la siguiente tabla:

38
CCPxM3:CCPxM0 Modo seleccionado
0000 Captura/Comparación/PWM deshabilitados
0100 Captura cada transición de bajada
0101 Captura cada transición de subida
0110 Captura cada 4 transiciones de subida
0111 Captura cada 16 transiciones de subida
1000 Comparación, pone salida cada coincidencia (Pone 1 a la salida)
1001 Comparación, limpia salida cada coincidencia (Pone 0 a la salida)
Comparación, genera interrupción cada coincidencia (salida
1010 inalterada)
Comparación, dispara evento espacial (CCP1 resetea TMR1; CCP2
1011 resetea TMR1 y arranca una conversión A/D).
11xx Modo PWM

A continuación se describe a detalle cada uno de los modos de operación, comenzando con el
modo PWM. La descripción se realiza sólo para el módulo CCP1, ya que es prácticamente
igual al CCP2.

2. Interacción de los dos módulos CCP

Modo CCPx Modo CCPy Interacción


Captura Captura La misma base de tiempos de TMR1
Captura Comparación El comparador debe configurarse para el modo de
disparo especial que pone a cero el TMR1
Comparación Comparación El Comparador(es) debe configurarse para el modo de
disparo especial que pone a cero el TMR1
PWM PWM El PWM tendrá la misma frecuencia y proporción de
actuación (interrupción de TMR2)
PWM Captura Ninguna
PWM Comparación Ninguna

3. Registro CCP1CON (dirección 17h)/Registro CCP2CON (dirección 1Dh)

U-0 U-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0 R/W-0


--- --- CCPxX CCPxY CCPxM3 CCPxM2 CCPxM1 CCPxM0
Bit 7 Bit 0
bit 7-6: No implementados: Se lee como "0"

bit 5-4: CCPxX: CCPxY: bit menos significativos de PWM


Modo Captura sin usar
Modo Comparación sin usar
Modo PWM: Estos dos bit son los menos significativos del ciclo de PWM. Los ocho bits
más significativos se encuentran en CCPRXL.

bit 3-0:CCPxM3-.CCPxM0; bit de selección del modo de trabajo del módulo comparador
CCPX.
CCPxM3: MÓDO DE TRABAJO DEL MÓDULO
CCPxM0
0000 Módulo Captura/Comparación/PWM desactivado (reset del módulo CCPx)
0100 Modo de captura por flanco descendente RCy/CCP

39
0101 Modo de captura por flanco ascendente en RCy/CCPx
0110 Modo de captura, cada 4 flancos ascendentes en RCy/CCPx
0111 Módo captura. Cada 16 flancos ascendentes en RCy/CCPx
1000 Modo comparación, activa la patilla, se pone a 1 RCy/CCPx al coincidir los valores
(el bit CCPxIF se pone a uno)
1001 Modo de comparación se pone a 0 la patilla RC/CCPx al coincidir los valores (el bit
CCPxIF se pone a uno)
1010 Modo de comparación, genera una interrupción sofware (el bit CCPxIF se pone a
1, el pin de CCPx no es afectado)
1011 Modo de comparación, en el que se produce un disparo especial para cada
módulo (el bit CCPxIF se pone a uno, el pin CCPx no es afectado); CCP1 resetea
TMR1; CCP2 resetea TMR1 y comienza una conversión de A/D (si el módulo de
A/D se habilita)
11xx Modo de PWM

6.4.2. Modo PWM (Modulación de Ancho de Pulso)

En este modo se puede producir una salida de frecuencia fija seleccionable modulada en
ancho de pulso (o ciclo de trabajo) con una resolución de 10 bits, a través de la patita
RC2/CCP1, como se muestra en la figura siguiente:

Debido a que la patita CCP1 está multiplexada con RC2, este bit del puerto C deberá ser
configurado como salida (TRISC<2>=0) para poder usar la salida CCP1.

En la siguiente figura se muestra un diagrama de bloques simplificado que resume la


operación básica del PWM.

40
Nota 1: los 8 bits del registro TMR2 son concatenados con 2 bits del preescalador del timer
para crear una base de tiempo de 10 bits.

A continuación se explica el Control del Periodo del PWM y el Control del Ciclo de Trabajo del
PWM:

a. Control del Periodo del PWM

Para especificar el periodo del PWM se usa el registro PR2, de manera que el valor del
periodo será:

PeriodoPWM = (PR2+1)*4*TOSC*M

Donde 1/M es el valor del preescalador del Timer 2.

Cuando el valor en TMR2 alcanza el valor PR2 los siguientes tres eventos ocurren en el
siguiente ciclo (Ver figura anterior):

• El registro TMR2 es limpiado


• La patita CCP1 es puesta en alto (Excepto si el ciclo de Trabajo del PWM vale
cero).
• El Ciclo de Trabajo es cargado de CCPR1L (15h) a CCPR1H (16h).

De esta manera, de acuerdo a la figura anterior, el siguiente valor de comparación para


TMR2 en el comparador de 10 bits es el Ciclo de Trabajo, el cual al alcanzarse limpiará la
patita CCP1.

b. Control del Ciclo de Trabajo del PWM

41
El ciclo de Trabajo se especifica escribiendo un valor de 10 bits al registro CCPR1L (los 8
bits más significativos (msb)) y los dos bits menos significativos (lsb) a CCP1CON<5:4>
este valor de 10 bits lo representaremos como CT=CCPR1L:CCP1CON<5:4>. El valor de
tiempo que dura el ciclo de trabajo para un valor del preescalador de 1/M, se calcula de
acuerdo a la siguiente ecuación:

TPWM = CT*TOSC*M

donde, TPWM es el valor de la duración del ciclo de trabajo (CT)

Como se puede ver en la figura anterior, el valor que determina la duración de C.T. del
PWM no es el cargado en CT (CCPR1L), sino en CCPR1H, el cual sólo se actualiza
copiando el valor de CT en el momento en que TMR2 alcanza el valor de PR2 (es decir,
cada vez que se completa un periodo). Por ello, aunque CCPR1L puede ser escrito en
cualquier momento, el Ciclo de Trabajo solo se actualiza hasta que termina el periodo
que está en transcurso.

No hay otra manera de escribir al registro CCPR1H, ya que este es un registro de sólo
lectura.

Cuando el valor de TMR2 (concatenado con dos bits CCP1CON<5:4>) alcanza el


valor de CCPR1H (concatenado con dos bits del preescalador) la patita CCP1 es
limpiada (ver figura anterior).

Como puede ver, el número de divisiones que se pueden tener en un Ciclo de


Trabajo será 2r, donde r es el número de bits usados, por lo tanto su duración máxima será
este número de divisiones multiplicada por la duración del ciclo más pequeño del sistema
TOSC. Por lo tanto:
T PWM= (2 r)* T *M OSC

Sin embargo, dependiendo del valor de Ciclo de trabajo máximo (TPWM) deseado, no
será posible realizar las 2r divisiones y por lo tanto no se podrán usar los r bits de
resolución. O al revés, si se elige una resolución deseada r no será posible tener
cualquier Ciclo de Trabajo máximo (TPWM) deseado.

Además, si se elige TPWM mayor que el periodo del PWM (PeriodoPWM) la patita
CCP1 no será limpiada (y por lo tanto no funcionará el PWM).

Ejemplo

Por ejemplo, suponiendo un cristal de 20 Mhz, si s e desea usar la máxima resolución r


= 10 bits, el ciclo de trabajo máximo posible será (para M=1):

TPWM = 1024*0,05x10-6 = 0,0512 mseg (CT Máxima)

O de lo contrario la patita CCP1 no podrá ser limpiada.

42
Para tener este valor de PeriodoPWM se requiere un valor en PR2 que como ya se dijo, está dado
por:

PeriodoPWM = (PR2+1)*4*TOSC*M

Despejando PR2 será:

PR2= (PeriodoPWM / (4*TOSC*M)) – 1

Pero si se desea tener el PeriodoPWM máximo se sustituye, PR2=255 = FFh (valor máximo) y
M=1:

PeriodoPWM = (255+1)*4*0,05x10-6 *1
= 0,0512 mseg

O bien, la “Frecuencia del PWM máxima” definida como FPWM = 1/ PeriodoPWM, tendrá un
valor de:

FPWM = 1/0,0512x10-3 = 19,53125 Khz

En la siguiente tabla se resumen diversas elecciones de resolución r y la


correspondiente frecuencia FPWM máxima, así como el valor de PR2 con el que se logra (para
una frecuencia del cristal de 20 Mhz).

FPWM máxima 1.22 Khz 4.88 Khz 19.53 Khz 78.12 Khz 156.3 Khz 208.3 Khz
Preescalador 16 4 1 1 1 1
PR2 FFh FFh FFh 3Fh 1Fh 17h
Resolución
10 10 10 8 7 5.5
máxima

Secuencia de configuración del PWM

A continuación se resumen los pasos para realizar la configuración inicial del PWM:

1. Establecer el periodo del PWM escribiendo al registro PR2.


2. Establecer el Ciclo de Trabajo del PWM escribiendo al registro CCPR1L y a los bits
CCP1CON<5:4>.
3. Configurar como salida la patita CCP1, limpiando el bit TRISC<2>.
4. Configurar el preescalador del Timer 2 y habilitar el Timer 2, escribiendo al registro
T2CON.
5. Configurar el módulo CCP1 para operación PWM. Poniendo en alto los bits
CCP1CON <3:2>.

6.4.3. El Modo Comparador

En el modo de comparación el registro de 16 bits CCPR1 (CCPR1H:CCPR1L) se


compara constantemente con el valor del registro de 16 bits TMR1. De manera que cuando
sus valores coinciden además de activarse la bandera para solicitar interrupción CCP1IF
43
(PIR1<2>), puede ocurrir en la patita RC2/CCP1 (previa configuración) alguna de las
siguientes acciones:

• RC2/CCP1 Se pone en alto


• RC2/CCP1 Se pone en Bajo
• RC2/CCP1 no cambia

La acción que ocurra en esta patita se configura mediante los bits de control
CCP1M3:CCP1M0 (CCP1CON<3:0>). En la figura siguiente se muestra un diagrama de
bloques en donde se ilustra la manera en que trabaja el módulo CCP en modo
comparador

Configuración del modo de comparación

A continuación se hace un resumen de algunas consideraciones que se deberán hacer para


configurar adecuadamente el modo de comparación:

• La patita RC2/CCP1 deberá configurarse como salida limpiando el bit TRISC<2>.


• Al limpiar el registro CCP1CON el latch de salida de la patita RC2/CCP1 se forza
a su valor “default” de cero.
• El Timer 1 debe estar corriendo en modo temporizador (o en modo contador
sincronizado)
• Si se está manejando por poleo la bandera de solicitud de interrupción, se
deberá limpiar por software antes de un posible evento que la active, de lo
contrario no se notará la activación.

Nota: El manejo de evento especial no se describe en estos apuntes.

6.4.4. El Modo de Captura

En el modo de captura el registro CCPR1 (CCPR1H:CCPR1L) captura el valor de 16 bits


d e l registro TMR1, cuando ocurre un evento en la patita RC2/CCP1. El evento en
cuestión puede especificarse previamente como alguno de los siguientes:

• Cada transición de bajada


• Cada transición de subida
44
• Cada 4 transiciones de subida
• Cada 16 transiciones de subida

Además de que el valor de TMR1 es capturado, la bandera de solicitud de interrupción


CCP1IF es activada, la cual deberá ser limpiada por software para poder detectarla si se está
consultando por poleo.

El tipo de acción que se desea detectar en esta patita se configura mediante los bits de control
CCP1M3:CCP1M0 (CCP1CON<3:0>). Si ocurre otro evento de captura antes de que haya
sido leído el registro CCPR1, el valor capturado anterior se perderá, ya que con la nueva
captura este registro es reescrito.

En la figura siguiente se muestra un diagrama de bloques en donde se ilustra la manera en que


trabaja el módulo CCP en modo de captura:

El preescalador del CCP

El valor d el preescalador d el C C P se configura mediante los bits CCP1M3:CCP1M0. Sin


embargo, al realizar un cambio en la configuración del preescalador d el C C P se puede
generar una interrupción falsa, para evitar lo anterior se deberá apagar el modulo
CCP (limpiando el registro CCP1CON) previamente al cambio de valor del preescalador d e l
CCP.

Este preescalador d e l C C P es independiente al preescalador del Timer 1 (el cual puede


usarse como ya se explicó con sus posibles divisores de 1/1, 1/2, 1/4, 1/8).

Configuración del modo de captura

A continuación se hace un resumen de algunas consideraciones que se deberán hacer para


configurar adecuadamente el modo de captura:

• En el modo de captura la patita RC2/CCP1 deberá configurarse como entrada


poniendo en alto el bit TRISC<2>. Si por alguna razón la patita RC2/CCP1 es
configurada como salida, se deberá tener en cuenta que una escritura al puerto
C puede causar una condición de captura.
• El Timer 1 debe estar corriendo en modo temporizador (o en modo contador
sincronizado), de lo contrario el modo de captura puede no funcionar.
• Cuando se realiza un cambio de un modo de captura a otro modo de captura se
puede generar una solicitud de interrupción falsa. Esto debe ser evitado
45
limpiando la máscara de interrupción correspondiente (CCP1IE (PIE1<2>))
cuando se realice un cambio de estos para evitar una interrupción falsa.
• Si se está manejando por poleo la bandera de solicitud de interrupción, se
deberá limpiar por software antes de un posible evento que la active, de lo
contrario no se notará la activación.

El valor del dato (N) de 16 bits capturado se puede convertir a segundos (T) de acuerdo a la
relación, donde Q representa el peescalador de CCP y M el peescalador del TIMER 1:

T = N M Q*4/Fosc seg

O bien, como frecuencia:

F= 1/T= Fosc/(4*N M Q) Hertz.

46
Ejemplo 5

Control de iluminación en lazo abierto

En el siguiente ejemplo se ilustra el uso de la salida PWM para controlar el nivel de


iluminación producido por una lámpara de acuerdo a la siguiente figura:

Elección de la frecuencia de operación del PWM:

Como la carga que se desea controlar es de tipo resistivo, no tendrá limitaciones


respecto a frecuencias altas de operación, salvo las limitaciones de baja frecuencia que le
impone la respuesta térmica para que el parpadeo no sea visible, es decir, se puede usar desde
una frecuencia lenta (del orden de unos 20 hertz) hasta frecuencias tan altas como el PWM
pueda soportar (del orden de los kilohertz).

Para usar los 10 bits de resolución, repetimos el cálculo del ejemplo para un reloj de
20MHz, pero ahora s e supone una FOSC = 4 Mhz, es decir, TOSC = 0,25 µseg,
entonces, el ciclo de trabajo máximo posible será (para M=1):

TPWM = (2 r)* TOSC*M, r = 10


TPWM = 1024*0,25x10-6 = 0,256 mseg (CT máximo)

Y para lograr esto, se necesita:

PR2= (PeriodoPWM / (4*TOSC*M)) – 1,

El PeriodoPWM máximo se tendrá sustituyendo, PR2=255 = FFh. (valor máximo)

PeriodoPWM = (PR2+1)*4*TOSC*M
= (255+1)*4*0,25x10-6 *1
= 0,256 mseg

O bien, la “Frecuencia del PWM” definida como FPWM = 1/ PeriodoPWM, tendrá un valor de:

FPWM = 3,9 Khz

47
1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

INICIO

CTL←0
CTH←0

NO
RB0=0 incre

SI

NO
RB1=0 decre

SI

Actualiza parte alta


CCPR1L←CTH
del CT

W←0xCF Máscara

Limpiar los 2 lsbits


CCP1CON←CCP1CON AND W
del CT

W←0x03 Máscara

Limpia los 6 bits


CTH←CTL AND W
altos en CTL

Copia los 2 bits bajos de


W← int. nibles CTL
CTL en nible alto de W

Pone los 2 bits


CCP1CON←CCP1CON OR W
bajos del CT

Diagrama de flujo de la Subrutina incre:

48
incre

d20ms

CTL←CTL+1

W←0x04

W←W-CTL

NO
Z=1

SI

CTL←0

CTH←CTH+1

FIN

Diagrama de flujo de la Subrutina decre:

49
Diagrama de flujo de la Subrutina d20ms:

50
2. Código en Assembler:
;****************************************************************
;* Este programa controla el ciclo de trabajo de la salida PWM *
;* (patita CCP1) con la cual controlará el nivel de iluminación *
;* promedio producido por una lámpara controlada con esta señal.*
;* Se usa un botón conectado a RB0 para incrementar el nivel y *
;* otro conectado a RB1 para disminuirlo. *
;* Se supone un cristal de 4 Mhz *
;****************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877.INC"

;Setup of PIC configuration flags


__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

;Define constantes
N EQU 0x1A
M EQU 0x0

;Define variables
CBLOCK 0x20
cont1
cont2
CTH

51
CTL
ENDC

org 0x00 ;Vector reset

inic BSF STATUS,RP0 ;Banco1


BSF TRISB,0 ;Configura RB0 como entrada
BSF TRISB,1 ;Configura RB1 como entrada
MOVLW 0xFF ;carga periodo
MOVWF PR2 ;lo establece para el PWM (PR2 = 255)
BCF TRISC,2 ;patita RC2/CCP1 como salida
BCF STATUS,RP0 ;Banco 0
CLRF CCPR1L ;inicializa Ciclo de Trabajo en cero
BCF CCP1CON,CCP1X ;Bits 4 y 5 de CCP1CON menos significativos
BCF CCP1CON,CCP1Y ;del ciclo PWM
MOVLW 0x04 ;configura Timer 2
MOVWF T2CON ;preescalador 1/1, habilita Timer 2
BSF CCP1CON,CCP1M3 ;Configura el modulo CCP1 para operación PWM
BSF CCP1CON,CCP1M2

;en este punto la salida PWM tiene un Ciclo de trabajo CT=0


CLRF CTL ;inicializa CT de 10 bits en cero
CLRF CTH

Esp0 BTFSC PORTB,0 ;Checa Botón RB0


CALL incre ;si está presionado incrementa CT
BTFSC PORTB,1 ;si no se ha presionado Checa botón RB1
CALL decre ;si está presionado Decrementa CT

MOVF CTH,W ;obtiene copia de CT parte alta


MOVWF CCPR1L ;actualiza parte alta del CT real

;**** a continuación actualiza la parte baja del CT real


MOVLW 0xCF ;máscara
ANDWF CCP1CON,1 ;limpia los dos lsbits del CT real
MOVLW 0x03 ;máscara
ANDWF CTL,1 ;limpia los 6 bits altos en CTL
SWAPF CTL,W ;copia los 2 bits bajos de CTL en el nibble alto de W
IORWF CCP1CON,1 ;pone bits que deben ser los dos lsb del CT real
;**** con esto queda actualizada la parte baja del CT real

GOTO Esp0 ;repite

;************************************************************************************
;**incrementa parte baja y alta de la copia de CT
incre
CALL d20ms ;pausa para eliminar rebores
INCF CTL,1 ;incrementa parte baja de la copia de CT
MOVLW 0X04
SUBWF CTL,W ;resta 4 menos CTL
BTFSS STATUS,Z ;checa si se llega a 4 la parte baja, cuenta màxima 3
RETURN ;si no, retorna
CLRF CTL
INCF CTH,1 ;si se llego a 4 la parte baja, incrementa parte alta de CT
RETURN

;**decrementa parte baja y alta de la copia de CT


decre
CALL d20ms ;pausa para eliminar rebores
DECF CTL,1 ;decrementa parte baja de la copia de CT
COMF CTL,W ;Copia negado de CTL a W (para ver si CTL=0xFF),
;para ver el valor 11111111
BTFSS STATUS,Z ;checa si W es cero
RETURN ;si no, retorna
MOVLW 0X03
MOVWF CTL
DECF CTH,1 ;si sí, decrementa parte alta de CT
52
RETURN

;**Subrutina de pausa 20 mseg para reloj 4 MHz


d20ms MOVLW N ;(1) Carga dato N
MOVWF cont1 ;(1) inicializa contador1 ciclo externo
rep1 MOVLW M ;(1) Carga dato M
MOVWF cont2 ;(1) inicializa contador2 ciclo interno
rep2 DECFSZ cont2,1 ;(1,2)Decrementa contador2 y escapa si cero
GOTO rep2 ;(2) si no es cero, repite ciclo interno
DECFSZ cont1,1 ;(1,2)Decrementa contador1 y escapa si cero
GOTO rep1 ;(2) si no es cero repite ciclo externo
RETURN ;(2) regresa de esta subrutina

END

Análisis del código

En primer lugar configuramos los registros CCPR1L, CCP1CON y T2CON.

Registro CCPR1L

0 0 0 0 0 0 0 0
Bit 7 Bit 0

El registro CCPR1L es el registro que pasa a ser la parte más significativa del ciclo PWM, que comienza
con el valor 0.

Registro CCP1CON

--- --- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0


0 0 1 1 0 0
Bit 7 Bit 0

Los bits CCP1X y CCP1Y de CCP1CON<5:4>, son los bits menos significativos del ciclo PWM, que
comienzan con el valor 0.
CCP1X = 0,
CCP1Y = 0,

Configura el Módulo CCP1 para operación PWM


CCP1M3=1
CCP1M2=1
CCP1M1=0
CCP1M0=0

Registro T2CON

T2CON = 0x04

--- T2OUPS3 T2OUPS2 T2OUPS1 T2OUPS0 TMR20N T2CKPS1 T2CKPS0


0 0 0 0 0 1 0 0
Bit 7 Bit 0

TMR20N = 1, Enciende el Timer 2


53
Postescaler 1/1:
T2OUPS3=0
T2OUPS2=0
T2OUPS1=0
T2OUPS0=0

Preescaler 1/1:
T2CKPS1=0
T2CKPS0=0

Programa principal. Este programa comienza la salida PWM con un ciclo de trabajo CT=0
(CTH:CTL), inicializa CT de 10 bits en cero. Luego checa Botón RB0; si está presionado
incrementa CT, si no se ha presionado chequea botón RB1; si está presionado decrementa CT.
Luego actualiza parte alta de CT real y a continuación realiza el proceso que actualiza la parte
baja del CT real.

Para la actualización de la parte baja del CT real, se realiza las siguientes tareas:

• Limpia los dos bits menos significativos del CT real en CCP1CON=UU00XXVV, con la
máscara 11001111 (0xCF),

MOVLW 0xCF ;máscara


ANDWF CCP1CON,1 ;limpia los dos lsbits del CT real

• Limpia los seis bits altos en CTL=000000YY, con la máscara 00000011 (0x03),

MOVLW 0x03 ;máscara


ANDWF CTL,1 ;limpia los 6 bits altos en CTL

• Copia los 2 bits bajos de CTL= 000000YY en el nibble alto de W=00YY0000,

SWAPF CTL,W ;copia los 2 bits bajos de CTL en el nibble alto de W

• Pone los dos bits menos significativos de CT real en CCP1CON=UUYYXXVV,

IORWF CCP1CON,1 ;pone bits que deben ser los dos lsb del CT real

con esto queda actualizada la parte baja del CT real.

Por último, una pausa para moderar la velocidad de incremento/decremento. Repitiendo todo
nuevamente,

GOTO Esp0 ;repite

El Periodo de PWM es fijo, el CT cambia de 0x000 a 0x3FF.

Subrutinas. Son tres: incre, decre y pausa50ms:

incre, incrementa parte baja y alta de la copia de CT.

decre, decrementa parte baja y alta de la copia de CT. No controla cuando todo está en cero.

54
Pausa50ms, pausa de 50 milisegundos aproximadamente.

55
Ejemplo 6

Generador de Frecuencia Variable.

En este programa se usa el modo de comparación para realizar la conmutación de una señal
cada vez que transcurre un tiempo, el cual se ajusta al oprimir un botón de incremento o uno
de decremento. El hardware utilizado es similar al del ejemplo anterior, con un cristal de 4 Mhz

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

56
Diagrama de flujo de la Subrutina incre:

incre

CCPR1L←CCPR1L+1

NO
Z=1

SI

CCPR1H←CCPR1H+1

FIN

Diagrama de flujo de la Subrutina decre:

decre

CCPR1L←CCPR1L-1

W←COMP CCPR1L

NO
Z=1

SI

CCPR1H←CCPR1H-1

FIN

El diagrama de flujo de la Subrutina d20ms se encuentra en el ejercicio anterior:

2. Código en Assembler:
57
;**************************************************************
;* Este programa genera a través de la patita RC2, una señal *
;* oscilatoria. Se usa un botón conectado a RB0 para incremen-*
;* tar el periodo y otro conectado a RB1 para disminuirlo. *
;* Se supone un cristal de 4 Mhz *
;**************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877.INC"

;Setup of PIC configuration flags


__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

;Define constantes
N EQU 0x1A
M EQU 0x0

;Define variables
CBLOCK 0x20
cont1
cont2
ENDC

ORG 0x00 ;Vector reset

inic BSF STATUS,RP0 ;Banco1


BSF TRISB,0 ;Configura RB0 como entrada
BSF TRISB,1 ;Configura RB1 como entrada
BCF TRISC,2 ;patita RC2/CCP1 como salida
BCF STATUS,RP0 ;Banco 0
MOVLW 0x01
MOVWF T1CON ;Configura Timer1 modo temporizador, preesc 1/1

CLRF TMR1H ;Inicializa en cero el timer 1


CLRF TMR1L

CLRF CCPR1H ;inicializa periodo de comparación


CLRF CCPR1L ;al mínimo (cero)

CLRF CCP1CON ;limpia latch de CCP1


BSF CCP1CON,CCP1M3 ;Habilita modulo CCP1 para modo de comparación
BCF CCP1CON,CCP1M0 ;pone salida en 1 al coincidir
BCF PIR1,CCP1IF ;limpia bandera de interrupción.

checa BTFSS PIR1,CCP1IF ;checa bandera (lazo de espera)


GOTO checa ;si no se ha activado espera
BCF PIR1,CCP1IF ;si ya se activó, la limpia
MOVLW 0x01 ;máscara
XORWF CCP1CON,1 ;conmuta la acción al coincidir próxima comparación.
CLRF TMR1L ;limpia la cuenta del timer 1
CLRF TMR1H

BTFSC PORTB,0 ;Checa Botón RB0


GOTO RB0_1 ;si está presionado incrementa CT
Esp1 BTFSC PORTB,1 ;si no se ha presionado Checa botón RB1
GOTO RB1_1 ;si está presionado Decrementa CT

GOTO checa ;repite

;******************
;**acciones del menú
RB0_1
CALL d20ms ;pausa para eliminar rebores
CALL incre
GOTO Esp1

RB1_1
58
CALL d20ms ;pausa para eliminar rebores
CALL decre
GOTO checa ;repite
;******************

;************************************************************************************
;**Inncrementa parte baja y alta del periodo
incre INCF CCPR1L,1 ;incrementa parte baja del periodo
BTFSS STATUS,Z ;checa si se recicló a cero
RETURN ;si no, retorna
INCF CCPR1H,1 ;si llegó a cero incrementa parte alta del periodo
RETURN

;**Decrementa parte baja y alta del periodo


decre DECF CCPR1L,1 ;Decrementa parte baja del periodo
COMF CCPR1L,W ;copia negado de CCPR1L a W (para ver si es=0xFF)
BTFSS STATUS,Z ;checa si W es cero
RETURN ;si no, retorna
DECF CCPR1H,1 ;si sí, Decrementa parte alta del periodo
RETURN

;**Subrutina de pausa 20 mseg para reloj 4 MHz


d20ms MOVLW N ;(1) Carga dato N
MOVWF cont1 ;(1) inicializa contador1 ciclo externo
rep1 MOVLW M ;(1) Carga dato M
MOVWF cont2 ;(1) inicializa contador2 ciclo interno
rep2 DECFSZ cont2,1 ;(1,2)Decrementa contador2 y escapa si cero
GOTO rep2 ;(2) si no es cero, repite ciclo interno
DECFSZ cont1,1 ;(1,2)Decrementa contador1 y escapa si cero
GOTO rep1 ;(2) si no es cero repite ciclo externo
RETURN ;(2) regresa de esta subrutina

END

Análisis del código

En primer lugar configuramos el registro T1CON.

Registro T1CON

T1CON=0x01

--- --- T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON


0 0 0 0 0 0 0 1
Bit 7 Bit 0

Divisor de frecuencia del preescaler a 1/1,


T1CKPS1=0
T1CKPS0=0

TMR1ON=1, habilitación del Timer1

Registro CCP1CON

--- --- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0


0 0 1 0 0 0
Bit 7 Bit 0

59
Los bits CCP1X y CCP1Y de CCP1CON<5:4>, no importan.

Configura el Módulo CCP1 para operación Comparación con salida 1.


CCP1M3=1
CCP1M2=0
CCP1M1=0
CCP1M0=0

Luego, configura el Módulo CCP1 para operación Comparación con salida 0.


CCP1M3=1
CCP1M2=0
CCP1M1=0
CCP1M0=1

Programa principal. Este programa genera a través de la patita RC2, una señal oscilatoria. Se usa un
botón conectado a RB0 para incrementar el periodo y otro conectado a RB1 para disminuirlo,
como se muestra en la siguiente figura:

Se comienza inicializando el periodo de comparación al mínimo (cero), limpia latch de CCP1, habilita
módulo CCP1 para modo de comparación; poniendo la salida en 1 al coincidir los valores, y limpia
bandera de interrupción,

CLRF CCPR1H ;inicializa periodo de comparación


CLRF CCPR1L ;al mínimo (cero)
CLRF CCP1CON ;limpia latch de CCP1
BSF CCP1CON,CCP1M3 ;Habilita modulo CCP1 para modo de comparación
BCF CCP1CON,CCP1M0 ;pone salida en 1 al coincidir
BCF PIR1,CCP1IF ;limpia bandera de interrupción.

obteniéndose en el Registro CCP1CON:

--- --- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0


0 0 1 0 0 0
Bit 7 Bit 0

configurado el Módulo CCP1 para modo comparación, se pone a la patilla RC2/CCP1 a 1 al coincidir los
valores (el bit CCP1IF se pone en 1)

CCP1M3=1
CCP1M2=0
CCP1M1=0
CCP1M0=0

Checa bandera (lazo de espera); si no se ha activado espera, si ya se activó la limpia.

60
checa BTFSS PIR1,CCP1IF ;checa bandera (lazo de espera)
GOTO checa ;si no se ha activado espera
BCF PIR1,CCP1IF ;si ya se activó, la limpia

Invierte el bit CCP1CON<0>, con la máscara 00000001 (0x01),

MOVLW 0x01 ;máscara


XORWF CCP1CON,1 ;conmuta la acción al coincidir próxima comparación.

obteniéndose en el Registro CCP1CON:

--- --- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0


0 0 1 0 0 1
Bit 7 Bit 0

configurado el Módulo CCP1 para modo comparación, se pone a la patilla RC2/CCP1 a 0 al coincidir los
valores (el bit CCP1IF se pone en 1),
CCP1M3=1
CCP1M2=0
CCP1M1=0
CCP1M0=1

A continuación limpia la cuenta del timer 1 y checa botón RB0; si está presionado incrementa el
periodo, si no se ha presionado checa botón RB1; si está presionado decrementa el periodo.

Repitiendo todo nuevamente,

GOTO checa ;repite

Subrutinas. Son dos, incre y decre:

incre, incrementa el periodo tanto parte baja y alta (16 bits)

decre, decrementa el periodo tanto parte baja y alta (16 bits)

61
Ejemplo 7

Medición de Periodo

En este programa usa el modo de captura para realizar la medición del periodo de una
señal oscilatoria. Para ello se configura el evento de captura para que ocurra cada vez que la
patita RC2/CCP1 detecte una subida en la señal oscilatoria de entrada. El valor capturado se
envía por el puerto serie para su despliegue.

1. Diagrama de Flujo:

Diagrama de flujo del Programa Principal:

62
INICIO

CCPIF←0

NO
CCPIF=1

SI

CCPIF←0

TMR1L←0
TMR1H←0

W←

envbayte

W←

envbayte

W←0x0D

envia

W←0x0A

envia

Los diagramas de flujo de las Subrutinas: envbyte, asc, envia e initrans; están desarrollados en el
Capítulo 5 “El Convertidor Analógico – Digital”.

2. Código en Assembler:
63
;****************************************************************
;* Este programa mide el periodo de una señal oscilatoria en la *
;* patita RC2/CCP1. El valor de periodo capturado representa el *
;* número de ciclos Tcy por periodo y se envía continuamente por*
;* el puerto serie. Se supone un cristal de 4 Mhz *
;****************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877.INC"

;Setup of PIC configuration flags


__CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

;Define variables
CBLOCK 0x20
msnib
lsnib
ENDC

ORG 0x00 ;Vector reset

inic CALL initrans ;inicializa puerto serie como transmisor


BSF STATUS,RP0 ;Banco1
BSF TRISC,2 ;patita RC2/CCP1 como entrada
BCF STATUS,RP0 ;Banco 0
MOVLW 0x01
MOVWF T1CON ;Configura Timer1 modo temporizador, preesc 1/1
CLRF TMR1H ;Inicializa en cero el timer 1
CLRF TMR1L ;
CLRF CCP1CON ;limpia latch de CCP1
BSF CCP1CON,CCP1M2 ;Habilita modulo CCP1 para modo de captura
BSF CCP1CON,CCP1M0 ;en transición de subida

BCF PIR1,CCP1IF ;limpia bandera de interrupcion.

checa BTFSS PIR1,CCP1IF ;checa bandera


GOTO checa ;si no se ha activado espera. Cuenta del periodo
BCF PIR1,CCP1IF ;si ya se activó, la limpia
CLRF TMR1L ;limpia la cuenta del timer 1
CLRF TMR1H
MOVF CCPR1H,W ;copia periodo capturado
CALL envbyte ;y lo envía por el puerto serie
MOVF CCPR1L,W
CALL envbyte
MOVLW 0x0D ;envía separador
CALL envia
MOVLW 0x0A
CALL envia
GOTO checa ;repite

;***************************************************************
; Subrutina que envía el byte en W por el puerto serie, separado
; en los códigos ASCII de sus dos nibbles hexadecimales
;***************************************************************
envbyte:
MOVWF msnib ;pone byte en msnib
MOVWF lsnib ;y una copia en lsnib
SWAPF msnib,1 ;intercambia nibbles en lsnib
MOVLW 0x0F ;máscara para limpiar el nibble alto
ANDWF msnib,1 ;limpia parte alta de msnib
ANDWF lsnib,1 ;limpia parte alta de lsnib
MOVF msnib,W ;carga msnib en W
CALL asc ;obtiene código ASCII equivalente
CALL envia ;lo envía por el puerto serie
MOVF lsnib,W ;carga lsnib en W
CALL asc ;obtiene código ASCII equivalente
64
CALL envia ;lo envía por el puerto serie
RETURN

asc ADDWF PCL,1 ;Calcula el código a retornar


;Saltando W instrucciones adelante
DT "0123456789ABCDEF"

;****************************************************************
;Subrutina para inicializar el puerto serie USART como transmisor
;a 9600 Bauds, considerando un cristal de reloj de 4 MHZ
;****************************************************************
initrans:
BCF STATUS,RP1
BSF STATUS,RP0 ;banco 1
BSF TXSTA,BRGH ;pone bit BRGH=1 (velocidad alta)
MOVLW 0x19 ;valor para 9600 Bauds (Fosc=4 Mhz)
MOVWF SPBRG ;configura 9600 Bauds
BCF TXSTA,SYNC ;limpia bit SYNC (modo asíncrono)
BSF TXSTA,TXEN ;pone bit TXEN=1 (habilita transmisión)
BCF STATUS,RP0 ;regresa al banco 0
BSF RCSTA,SPEN ;pone bit SPEN=1 (habilita puerto serie)
RETURN

;***************************************************************
;Subrutina para enviar el byte guardado en W por el puerto serie
;***************************************************************
envia BSF STATUS,RP0 ;banco 1
esp BTFSS TXSTA,TRMT ;checa si el buffer de transmisión
GOTO esp ;si está ocupado espera
BCF STATUS,RP0 ;regresa al banco 0
MOVWF TXREG ;envía dato guardado en W
RETURN

END

En el ejemplo anterior, el valor del dato (N) de 16 bits desplegado se puede convertir a
segundos (T) de acuerdo a la relación, con un reloj de 4MHz:

T = N M Q * 4/Fosc = (1*10-6) N M Q seg.

O bien, como frecuencia:

F= 1/T= F= 1/T= 1*106/(N M Q) Hertz.

Observación

El programa debería leer sin problemas periodos entre Tmáx= 65,536 mseg (Fmin = 15,2587
Hz) y un Tmin=1µseg (Fmáx = 1 Mhz), sin embargo debido al retardo de la rutina de
transmisión del dato, (en la realidad el programa no puede detectar ninguna transición de
subida durante la transmisión del dato) el programa sólo puede procesar correctamente la
transición hasta una frecuencia Fmáx =160Hz (Tmin = 6,25 mseg).

Análisis del código

En primer lugar configuramos el registro T1CON y CCP1CON.

Registro T1CON

65
T1CON=0x01

--- --- T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON


0 0 0 0 0 0 0 1
Bit 7 Bit 0

Divisor de frecuencia del preescaler a 1/1,


T1CKPS1=0
T1CKPS0=0

TMR1CS=0, selección de la fuente de reloj a modo temporizador


TMR1ON=1, habilitación del Timer1

Registro CCP1CON:

--- --- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0


0 0 0 1 0 1
Bit 7 Bit 0

Configurado el Módulo CCP1 para modo captura por flanco ascendente en RC2/CCP1, como se muestra
en la siguiente figura:
CCP1M3=0
CCP1M2=1
CCP1M1=0
CCP1M0=1

Programa principal. Este programa mide el periodo de una señal oscilatoria en la patita RC2/CCP1.
El valor de periodo capturado representa el número de ciclos Tcy por periodo y se envía
continuamente por el puerto serie.

Checa bandera; si no se ha activado espera, si ya se activó la limpia, a continuación limpia la


cuenta del timer 1, copia la cuenta del Timer 1 capturado y lo envía por el puerto serie, luego
envía 0x0D y 0x0A.

Repitiendo todo nuevamente,


GOTO checa ;repite

Subrutinas. Son tres, envbyte, initrans y envia:

envbyte, subrutina que envía el byte en W por el puerto serie, separado en los códigos ASCII de
sus dos nibbles hexadecimales.

initrans, subrutina para inicializar el puerto serie USART como transmisor a 9600 Bauds,
considerando un cristal de reloj de 4 MHZ.

envia, subrutina para enviar el byte guardado en W por el puerto serie.


66

También podría gustarte