Calcular Timer 0

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.

Código:
;************************************** 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.
 
Última edición:
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
 
Última edición:
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.

Fig2403_DS1307.gif


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.
 
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.
 
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.
PHP:
#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
 
¿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
 
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.
 
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
 
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.
 
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
/////////////////////////////////////////////////////////////////////////
1592883091600.png
 
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.
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
 

Adjuntos

  • TMR0 500 uS.jpg
    TMR0 500 uS.jpg
    125 KB · Visitas: 6
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
/////////////////////////////////////////////////////////////////////////
Ver el archivo adjunto 192460
///////////////////////////////////////////////////////////
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?

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.
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
///////////////////////////////////////////////
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.
 
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.
Código:
;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
1592957620590.png

Modo de Bajo Consumo
1592957718450.png
 
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í:
Código:
Inicio
    bsf     STATUS,RP0        ; Seleccionar el banco 1
    movlw   .6                ; Puertos A y E como digitales.
    movwf   ADCON1
    call    LCD_Inicializa    ; Inicializar la pantalla.
 
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.
 
Atrás
Arriba