# Calcular Timer 0



## Meta (May 14, 2010)

Supuestamente el Timer de 8 bit son de 1/256 de prescaler del 16F84A, el 16F88 tiene un Timer de 16 Bits. Un ejemplo del libro www.16f84a.org



> Temporización = Tcm * Prescaler * (256 - Carga TMR0)


Donde:



_Temporización_, es el tiempo deseado.
Tcm, es el período de un ciclo máquina e igual a Tcm = 4 Tosc. Para los 4 MHz ya se ha calculado en anteriores ocaciones Tcm = 4 * 1/f = 4 * 1/4 = 1 us.
_Prescaler_, es el rango de divisor de frecuencia elegido.
(256-Carga TMR0), es el número total de impulsos a contar por el TMR0 antes de desbordarse en la cuenta ascendente.

*EJEMPLO*: ¿Qué valor hay que cargar en el TMR0 para lograr un tiempo de 500us si se utiliza un Prescaler de 2?

*Solución:* Sustituyendo em ña ecuación anterior queda:

Temporización = Tcm * Prescaler * (256 - Carga TMR0)
              500 = 1 x 2 (256 - Carga TMR0)

de donde se deduce que el valor a cargar tiene que ser:

Carga TMR0 = 6

Como pueden ver el ejemplo de abajo, el parpadeo es de 500us.


```
;************************************** Timer0_02.asm ***********************************
;
;    ===================================================================
;      Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;      E. Palacios, F. Remiro y L. López.        www.pic16f84a.org
;       Editorial Ra-Ma.  www.ra-ma.es
;    ===================================================================
;
; Por la línea 3 del puerto B se genera una onda cuadrada de 1 kHz, por tanto, cada
; semiperiodo dura 500 µs. Los tiempos de temporización se consiguen mediante la
; utilización del Timer 0 del PIC.
;
; A la línea de salida se puede conectar un altavoz, tal como se indica en el esquema
; correspondiente, con lo que se escuchará un pitido.

; El cálculo de la carga del TMR0 se hará de forma simple despreciando el tiempo que 
; tardan en ejecutarse las instrucciones.
;
; ZONA DE DATOS **********************************************************************

    LIST        P=16F84A
    INCLUDE        <P16F84A.INC>
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC

    CBLOCK    0x0C
    ENDC

#DEFINE        Salida    PORTB,3

; ZONA DE CÓDIGOS ********************************************************************

    ORG     0
Inicio
    bsf        STATUS,RP0                ; Acceso al Banco 1.
    bcf        Salida                    ; Esta línea se configura como salida.
    movlw    b'00000000'
    movwf    OPTION_REG                ; Prescaler de 2 asignado al TMR0
    bcf        STATUS,RP0                ; Acceso al Banco 0.
Principal
    bsf        Salida                    ; La salida pasa a nivel alto
    call    Timer0_500us            ; durante este tiempo.
    bcf        Salida                    ; La salida pasa a nivel bajo
    call    Timer0_500us            ; durante este tiempo.
    goto     Principal

; Subrutina "Timer0_500us" -------------------------------------------------------
;
; Como el PIC trabaja a una frecuencia de 4 MHz, el TMR0 evoluciona cada microsegundo.
; Para conseguir un retardo de 500 µs con un prescaler de 2 el TMR0 debe contar 250
; impulsos. Efectivamente: 1 µs x 250 x 2 = 500 µs.
;
TMR0_Carga500us    EQU    d'256'-d'250'

Timer0_500us
    movlw    TMR0_Carga500us            ; Carga el Timer 0.
    movwf    TMR0
    bcf        INTCON,T0IF                ; Resetea el flag de desbordamiento del TMR0. 
Timer0_Rebosamiento
    btfss    INTCON,T0IF                ; ¿Se ha producido desbordamiento?
    goto    Timer0_Rebosamiento        ; Todavía no. Repite.
    return

; Comprobando con la ventana Stopwatch del simulador se obtienen unos tiempos para la onda
; cuadrada de 511 µs para el nivel alto y 513 µs para el bajo.

    END
```
Tanta explicación para una sola pregunta que es:

¿Cómo puedo usar 20 minutos de duración con el TIMER0 de 8 bit? 

Si es imposible, al menos para los 16 Bits del PIC-16F88.

A parte de esto, como segunda idea, quiero crear con Visual C# 2010 Express un generador de códigos en asm para los timer de 8 Bits y 16 Bits si es posible, al menos para los PIC16F84A y 16F88, más adelante con más PIC.

20m = 20 minutos.

*20m = 20000s = 20000000us*
*20000000 / 256 = 78125* Parece que no se puede hacer, hay que hacer algo.

Siguiendo con el ejemplo.
Temporización = Tcm * Prescaler * (256 - Carga TMR0)
              20000000 = 1 x 256 (256 - Carga TMR0)

Carga TMR0 = 78125 ; Es mucho, cómo máximo tiene que ser 256, no 78125. ¿Hay algún truco para ello?

Un cordial saludo.


----------



## 1jabato1 (May 15, 2010)

Hola Meta.

20minutos=1200segundos=1200000ms=1200000000us.
Utilizando el timer0 a 8bits con el prescaler mas alto creo que desborda cada 37,x(no recuerdo ahora mismo)ms con un xt de 4mhz,si incrementas una variable de 16bits en cada interrupcion puedes obtener los 20 minutos,para que fuera preciso tendrias que tener en cuenta los tiempos que empleas en las instrucciones.
Quizas seria mejor recurrir a un rtc.

Un saludo.
Javi


----------



## Meta (May 15, 2010)

Hola:

¿Cómo sabes que son 37 desbordamiento? ¿Cuánto tardaría un Timer 16 Bits? Aún así parace que estamos en las mismas.

Pues al final, por lo que cuentas hay que usar un reloj calendario como DS1624 por poner un jemplo.







Es muy complejo de manejar, por lo menos se puede configurar el tiempo que desees y te haga la cuentra atrás. Si es posible,con un 16 Bits podrías hacerlo.

Lo que cuentas que hay que tener precisión es colocando muchos nop.

Saludo.


----------



## 1jabato1 (May 15, 2010)

Te lo decía de cabeza(la tengo muy mal),El tmr0(8bits) con el prescaler de 256 produce la interrupción cada 65,28ms con un xt de 4mz.
A lo que me refería,es que dentro de la interrupción incrementas o decrementas una variable de 16bits,entonces puedes contar hasta 65.28ms*65535.El tmr1 65535us(ciclos de instrucción)*8(prescaler máximo)*65535(si usas una variable de 16bits en la interrupcion).

Si tu aplicación no tiene que ser muy precisa,esto seria suficiente(una insoladora,un temporizador para el horno,etc),pero si es para un cronometro de milésimas,tendrías que tener en cuenta las instrucciones.

Lo del rtc depende de la precision a largo plazo.

Saludos¡¡

Javi.

P.D.:No se si esta claro,dentro de un rato,no lo entiendo ni yo.


----------



## Meta (May 15, 2010)

¿Si lo pongo el cristal a 1 MHz?

El contador lo quiero para una insoladora.


----------



## 1jabato1 (May 15, 2010)

Hace tiempo hice una insoladora con un escaner ,utilizando dos dispalys de 7 segmentos y los botones del mismo,el codigo esta en CCS,el timer0 contaba aproximadamente un minuto,con esto podía temporizar de 99 a 1 minuto.Te lo pongo por si te sirve de algo.

```
#include "D:\Proyectos\temporizador insoladora\temporizador.h"
#byte port_a=5
#byte port_b=6
#define start bit_test(port_a,0)
#define inc bit_test(port_a,1)
#define dec bit_test(port_a,2)
#define paro bit_test(port_a,3)
#define salida bit_test(port_a,6)
#use fast_io(a)
#use fast_io(b)

int tiempo;
long i;

void ver(){
   int unidades,decenas;
   unsigned int const dig1[10]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19};
   unsigned int const dig2[10]={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29};   
   decenas=tiempo/10;
   unidades=tiempo-(decenas*10);
   port_b=dig1[unidades];
   delay_ms(5);
   port_b=dig2[decenas];
   delay_ms(5);
   port_b=0;}

void star(void)
{
     if(i>=1838){
         tiempo=tiempo-1;i=0;
         set_rtcc(0x00);}
     if(tiempo==0){
         bit_clear(port_a,6);
         tiempo=read_eeprom(1);}
     if(!paro){
         bit_clear(port_a,6);
         tiempo=read_eeprom(1);
         do{}while(!paro);}
     
     
}
     
void buton(void)
{
      if(!start){
         bit_set(port_a,6);
         i=0;
         set_timer0(0x00);
         do{}while(!start);
      }
      if(!inc){
      tiempo=tiempo+1;
         if(tiempo>99)
         tiempo=99;
         write_eeprom(1,tiempo);
      do{}while(!inc);}
      
 
      if(!dec){
      tiempo=tiempo-1;
         if(tiempo<1)
         tiempo=1;
         write_eeprom(1,tiempo);
      do{}while(!dec);
      }
}
      
    





#int_RTCC
void  RTCC_isr(void) 
{
i=i+1;
}



void main()
{
    
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);

   // TODO: USER CODE!!
   set_tris_a(0b00101111);
   set_tris_b(0b00000000);
   port_b=0;
   bit_clear(port_a,6);
   tiempo=read_eeprom(1);
   do{
   ver();
   if(!salida)
   buton();
   if (salida)
   star();
   }
   while(1);
}
```
Saludos¡¡

Javi


----------



## Meta (May 15, 2010)

Gracias, voy a investigar.


----------



## gongonni (Jul 6, 2010)

¿como sabemos cuánto tarda cada instruccion? por ejemplo, si durante la temporizacion tambien queremos comprobar un sensor, deberemos tener en cuenta ésa instruccion y las que sean necesarias, ¿no? (leer, comprovar, comparar, incrementar una variable, ...) 

salu2


----------



## carlos jara (Jul 9, 2010)

amigo podrias poner este ejemplo en pbp por favor


----------



## jjfonsecaz (Jul 9, 2010)

Que tal compañeros.

Pues yo programe un 10F202 para hacer una temporizacion de 8 horas con intervalos de 20 minutos. Aunque claro esta que no es tan preciso, no he medido el error pero debe de ser de aproximadamente unos 200 us.

Con un temporizador de 8 bits y preescaler de 256 usando un oscilador de 4Mhz al maximo obtendrias un periodo de 65,536 us o 65.5 ms. Si el registro es de 16 bits y el preescaler de 256 la cosa mejora pues tendrias a full un ciclo de 16,777,216 us o lo que es lo mismo un periodo de 16,77 segundos.

Pues bien si yo tuviese que hacerlo me inclinaria por un oscilador de 4 Mhz y un pic con un timer de 16 bits y configurarlo con preescaler de 64 para sacar un periodo de 1 segundo.

haciendo cuentas 1 s = 1000000 us.
1000000/64 = 15625
2^16 = 65536
65536-15625= 49911 = 0xC2F7

ese seria el valor a cargar en mi timer.
luego para obtener los 20 minutos
pues uso un registro que le voy a llamar SEGUNDOS y otro que se llame MINUTOS.
cada que se desborde el timer incremento en 1 SEGUNDOS y cada que llegue este registro a 60 lo borro y le asigno un 0 e incremento en 1 el registro MINUTOS.

y asi sucesivamente puedes conseguir temporizar yo creo que hasta años.
saludos.


----------



## carlos jara (Jul 10, 2010)

AMIGO cuando es el momento que yo devo utilizar el timer y el prescaler de acuerdo a que tiempos son  on interrupt goto podrias  ayudarme con esta pregunta que me vengo haciendo por favor


----------



## bondadoso (Oct 17, 2011)

una preguntota, segun el datasheet del  pic18f2525 puedo ponerle un cristal a 40mhz. la pregunta es en ccs utilizando el timer1 como puedo convertir el valor del timer1 a microsegundos esto lo necesito saber para medir la frecuencia de una señal.


----------



## cisneros626 (Jun 22, 2020)

Hola, me surgió una duda con el TIMER 0 como temporizador usando el código que pongo a continuación.
Usando la siguiente ecuación " Temporización = Tcm * Prescaler * (256 - Carga TMR0) "

_Temporización_, es el tiempo deseado.
Tcm, es el período de un ciclo máquina e igual a Tcm = 4 Tosc. Para los 4 MHz ya se ha calculado en anteriores ocaciones Tcm = 4 * 1/f = 4 * 1/4 = 1 us.
_Prescaler_, es el rango de divisor de frecuencia elegido.
(256-Carga TMR0), es el número total de impulsos a contar por el TMR0 antes de desbordarse en la cuenta ascendente.
Al calcular el valor que de mi semiciclo (500us) con un prescalador de 2 me dice que tengo que cargar un valor de 6 al TMR0.
Pero en la simulación me aparece lo que está en la imagen.

Mi duda reside en: 
Si mis cálculos son correctos, entonces por qué me salen esos valores en el osciloscopio?
Si no son correctos, cuál es la manera adecuada de hacer los cálculos?

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

;ZONA DE DATOS
    LIST P=16F877A
    INCLUDE <P16F877A.INC>
    __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

    CBLOCK  0x20
    ENDC

    #DEFINE Salida PORTB,3

;ZONA DE CÓDIGOS
    ORG 0x00
Incio
    bsf        STATUS,RP0
    movlw   b'00000000'
    movwf   OPTION_REG
    bcf        Salida
    bcf        STATUS,RP0
Principal
    bsf        Salida
    call    TIMER0_500us
    bcf        Salida
    call    TIMER0_500us
    goto    Principal

;SUBRUTINAS


TIMER0_1ms
    movlw   .6
    movwf   TMR0
    bcf        INTCON,TMR0IF
Comprobacion
    btfss   INTCON,TMR0IF
    goto    Comprobacion
    return

    END
/////////////////////////////////////////////////////////////////////////


----------



## D@rkbytes (Jun 23, 2020)

cisneros626 dijo:


> Al calcular el valor que de mi semiciclo (500us) con un prescalador de 2 me dice que tengo que cargar un valor de 6 al TMR0.


Sí, está bien, siempre y cuando FOsc = 4 MHz.


cisneros626 dijo:


> Si mis cálculos son correctos, ¿entonces por qué me salen esos valores en el osciloscopio?


Parece que en lugar de 4 MHz tuvieras 1 MHz como FOsc en el microcontrolador.
Como son dos flancos deberías tener una onda cuadrada de aproximadamente 1000 Hz.
Si pasamos 500 uS a Hertz serían 2000 Hz. (1/T) 1/0.0005 = 2000
Pero como son dos flancos la salida quedará dividida entre dos.
Como estás usando instrucciones en la rutina, se perderá precisión.
Esa pérdida de precisión por ciclos de instrucción suele complementarse con un ajuste en el valor de precarga del Timer 0

Ahora, si requieres de más precisión, entonces usa la interrupción por desborde del Timer 0 y realiza un toggle cuando desborde.
Con eso será más seguro que con un desborde cada 500 uS obtengas 1000 Hz de onda cuadrada al 50% en RB3

Postdata:
Asegúrate de que el microcontrolador esté funcionando a 4 MHz.
La rutina TIMER0_500us no existe, seguramente la cambiaste por TIMER0_1ms que para 500 uS @ 4 MHz sí corresponde con la precarga de 6


----------



## cisneros626 (Jun 23, 2020)

cisneros626 dijo:


> Hola, me surgió una duda con el TIMER 0 como temporizador usando el código que pongo a continuación.
> Usando la siguiente ecuación " Temporización = Tcm * Prescaler * (256 - Carga TMR0) "
> 
> _Temporización_, es el tiempo deseado.
> ...


///////////////////////////////////////////////////////////
Hola, me he dado cuenta de que mis cálculos son correctos pero en mi simulador, no sé la razón, me lo multiplica por 4.
En el programa que puse se supone que es un tiempo de encendido de 500us pero en el  osciloscopio del simulador me sale de 2ms. 
500us x 4 = 2ms.
De igual manera sucede cuando pongo un tiempo de encendido de 1ms (simula un tiempo de 4ms), 2ms (simula un tiempo de 8ms), 4ms (simula un tiempo de 16ms).

Alguien sabe por qué mi simulador está haciendo eso?



D@rkbytes dijo:


> Sí, está bien, siempre y cuando FOsc = 4 MHz.
> 
> Parece que en lugar de 4 MHz tuvieras 1 MHz como FOsc en el microcontrolador.
> Como son dos flancos deberías tener una onda cuadrada de aproximadamente 1000 Hz.
> ...


///////////////////////////////////////////////
Ahhhhhh Perfecto perfecto, ya vi que el microcontrolador no lo tengo a 4Mhz.
Muchas gracias por tomarte el tiempo de leer mi duda y responderla.


----------



## cisneros626 (Jun 23, 2020)

Disculpa que vuelva a molestar.
Tengo una duda con respecto a un programa. Consiste en un contador usando el LCD.
Debo contar los pulsos que entrar e imprimir en la LCD "xx Pulsaciones" donde xx es el número de pulsaciones que llevo.
Si el programa no recibe un pulso por más de 1 segundo entra en modo de bajo consumo y me arroja un mensaje que dice "MLP".

He configurado el OPTION_REG como contador, incrementa en cada flanco descendente de la señal, el divisor de frecuencia de 64 asignado al WDT.
También he configurado el puerto A como digital.

Al momento de correr el programa en la LCD solo me aparece el número de pulsaciones que llevo sin el mensaje de "Pulsaciones".
Y al momento de que entra en modo de bajo consumo no aparece el mensaje "MLP".

No sé si sea la posición de la memoria en donde se encuentran los mensajes.

```
;ZONA DE DATOS
    LIST P=16F877A
    INCLUDE <P16F877A.INC>
    __CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _XT_OSC

    CBLOCK  0x20
    Contador
    ENDC

    #DEFINE Pulsador PORTA,4

    ;ZONA DE CÓDIGOS
    ORG    0x00

Inicio
    call    LCD_Inicializa  ;Inicializamos LCD.
    btfss   STATUS,NOT_TO   ;Reset producido por WDT?. TO = 1?
    goto    ResetPorWDT        ;Sí. TO = 0
    movlw   MensajePulso    ;No. T = 1. Aparece el texto
    call    LCD_Mensaje        ;"Pulsaciones"
    bsf        STATUS,RP0        ;Seleccionamos banco 1
    movlw   .6            ;Puerto A como digital
    movwf   ADCON1
    bsf        Pulsador        ;Pulsador como entrada
    movlw   b'00011110'        ;Configuramos como contador, incremento en flanco...
    movwf   OPTION_REG        ;...descendente. PRescaler de 64 asignado al WDT
    bcf        STATUS,RP0        ;Seleccionamos banco 0
    clrf    Contador        ;Limpiamos el contador
    call    VisualizaContador    ;Visualizamos el valor inicial del contador

Principal
    btfss   Pulsador        ;Pulsador = 1?
    call    Incremento        ;No. Se ha presionado, incrementa
    goto    Principal        ;Sí. No se ha presionado

;SUBRUTINAS
ResetPorWDT
    call    LCD_Linea1        ;Cursor al principio de la línea 1
    movlw   MensajeWDT        ;Cargamos literal a W
    call    LCD_Mensaje        ;Leemos el mensaje cargado a W
    sleep
    goto    ResetPorWDT

Incremento
    clrwdt            ;Reiniciamos Watchdog
    call    Retardo_20ms    ;Retardo 20 milisegundos
    btfsc   Pulsador        ;Pulsador = 0?
    goto    FinIncremento   ;No. Se ha dejado de presionar
    incf    Contador,F        ;Sí. Se sigue presionando

VisualizaContador
    call    LCD_Linea1        ;Cursor al ´principio de línea 1
    movf    Contador,W        ;Movemos el contador a W
    call    BIN_a_BCD        ;Valor de W. Binario -> BCD
    call    LCD_Byte        ;Mostramos valor de W en BCD
Comprobacion
    clrwdt            ;Reiniciamos WDT
    btfss   Pulsador        ;Pulsador = 1?
    goto    Comprobacion    ;No. Comprobamos
FinIncremento
    return

;MENSAJES
Mensajes
    addwf   PCL,F
MensajePulso
    DT "   Pulsaciones",0x00
MensajeWDT
    DT "MLP",0x00

    INCLUDE <RETARDOS.INC>
    INCLUDE <BIN_BCD.INC>
    INCLUDE <LCD_4BIT.INC>
    INCLUDE <LCD_MENS.INC>
    END
```
Contando Pulsos


Modo de Bajo Consumo


----------



## D@rkbytes (Jun 23, 2020)

cisneros626 dijo:


> Al momento de correr el programa en la LCD solo me aparece el número de pulsaciones que llevo sin el mensaje de "Pulsaciones".
> Y al momento de que entra en modo de bajo consumo no aparece el mensaje "MLP".


Antes de usar la pantalla debes de configurar los puertos como digitales.
No se muestran los mensajes porque lo estás haciendo después.

Creí que esto ya te había quedado claro anteriormente.
Debe ser así:

```
Inicio
    bsf     STATUS,RP0        ; Seleccionar el banco 1
    movlw   .6                ; Puertos A y E como digitales.
    movwf   ADCON1
    call    LCD_Inicializa    ; Inicializar la pantalla.
```


----------



## cisneros626 (Jun 23, 2020)

Ahhh, debe ser antes de inicializar la LCD, una disculpa.
Gracias por tu ayuda.


----------



## D@rkbytes (Jun 23, 2020)

También te recomiendo que establezcas el fuse LVP en OFF porque no lo has usado y quedará en ON.
Si LVP está en ON el pin RB3 (PGM) no funcionará porque estará dedicado a la programación por bajo voltaje.


----------



## cisneros626 (Jun 23, 2020)

Ese se configura en el encabezado?

__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _XT_OSC & _LVP_OFF


----------



## D@rkbytes (Jun 23, 2020)

Sí, así está bien, pero el fuse _CP_OFF es OFF por defecto, así que se puede omitir y el valor de la palabra de configuración quedaría igual.
En este caso: 0x2007 = 0x3F75 ya que el fuse BOREN es ON por defecto y no lo estás ingresando.
Existen más fuses para este PIC pero como tienen valores por defecto se pueden omitir, quedando más corta la palabra de configuración e igual de funcional.
Muchas personas escriben más código en la palabra de configuración que en el programa. 
Pero bueno, al menos es mejor a que no la escriban y luego no sepan por qué no funciona el programa.


----------



## elvi (Sep 11, 2020)

Hola a tod@s! Tengo una duda... tal vez alguien me puede ayudar, en el datasheet del timer0 dice que  el TMR0 no se incrementará hasta el tercer ciclo de instrucciones posterior... Aplicado  la formula T = Tcm * Prescaler* (256 -CargaTMR0) para calcular una interrupcion de 18ms, con el reloj interno de 4MHZ y un prescaler de 128. La CargaTMR0 es 256- 140.625 aproximadamente . En este ejemplo -->  PIC timer calculation made easy.  le añade 2 unidades *TMR0 = 256-141+2  *dejando como resultado 117, o sea empieza a contar desde ahi

Considerando que timer0 empieza desde el tercer ciclo deberia ser  *TMR0 = 256-141- 2, *es decir empezar a contar desde 113 ?

Que es lo correcto añadirle 2, restar 2 u omitir ese valor?


----------



## D@rkbytes (Sep 11, 2020)

Yo nunca he agregado esas dos unidades.
Por ejemplo:
Prescaler = 128
Fosc = 4000000
Tosc = (1 / Fosc) * 4

Tosc = (1 / 4000000) * 4 = 0.000001

Valor_Timer0 = (256 - Precarga) * (Prescaler * Tosc)

Entonces...
256 - 115 = 141
128 * 0.000001 = 0.000128
Valor_Timer0 = 141 * 0.000128 = 0.018048 (18.048 mS)

Y no sumé ni resté 2


----------

