Encender un led cada 0.5 segundos usando temporizador


27 de Noviembre del 2016

Buenas a todos, tengo el siguiente código que consiste en simplemente encender y apagar un led cada 0.5 segundos en el PICF84A , pero lo necesito usando un TMR0 como temporizador, si alguien sabe como se lo agradecería

LIST P=16F84A
INCLUDE
CBLOCK 0x0C ; In this position starts user´s RAM.
ENDC
.#DEFINE LED PORTB,0

;***************************************************************************************** ORG 0x00
INICIO
bsf STATUS,RP0............................................................; Access to bank 1
bcf LED .........................................................................; LED line configurated like OUTPUT
bcf STATUS,RP0 ..........................................................; Access to Bank 0.
PRINCIPAL
bsf LED .........................................................................; Turn on the LED
call Retardo_200ms ......................................................; while the sum of this time
call Retardo_200ms
bcf LED ..........................................................................; It turns off while the sum of the next retardos
call Retardo_200ms
call Retardo_100ms
goto PRINCIPAL

; Subrutinas "Retardo_200ms" y "Retardo_100ms"-------------------------------------------

CBLOCK
R_ContA ......................................................................; Counters for the retardos
R_ContB
ENDC
Retardo_200ms ...........................................................; The named "call" aports 2 machine cycles.
movlw d'200' ................................................................; It Aports 1 machine cycle. This is the value of "M".
goto Retardos_ms ........................................................; It aports 2 machine cycles.
Retardo_100ms ............................................................; The named "call" aports 2 machine cycles.
movlw d'100' ................................................................; It aports 1 machine cycle.This is the value of "M".
goto Retardos_ms ........................................................; It aport 2 machine cycles.
Retardo_1ms ...............................................................; The named "call" aports 2 machine cycles.
movlw d'1' ....................................................................; It aports 1 machine cycle. This is the value of "M".
Retardos_ms
movwf R_ContB .......................................................; It aports 1 machine cycle.
R1ms_BucleExterno
movlw d'249' .......................................................; It aports Mx1 machine cycles. This is the value of "K".
movwf R_ContA .......................................................; It aports Mx1 machine cycles.
R1ms_BucleInterno
nop ; It aports KxMx1 machine cycles.
decfsz R_ContA,F .....................................................; (K-1)xMx1 cm (when it doesn´t jump) + Mx2 cm (when it jumps).
goto R1ms_BucleInterno .................................................; It aports (K-1)xMx2 machine cycles.
decfsz R_ContB,F .......................................................; (M-1)x1 cm (when it doesn´t jump) + 2 cm (when it jumps).
goto R1ms_BucleExterno ................................................; It aports (M-1)x2 machine cycles.
return.................................................................; The return Jump aports 2 machine cycles.
END


David Carrero
12 de Agosto del 2026

Hola,

Tu código actual hace el retardo «a mano», con bucles de nop contando ciclos de instrucción. Con TMR0 la idea cambia: dejas que el hardware del PIC cuente por ti, y tu programa solo comprueba periódicamente si ya ha desbordado.

Primero, en el banco 1, configuras OPTION_REG para que TMR0 use el reloj interno con el prescaler más alto (1:256), que es el que te da retardos más largos antes de desbordar:

bsf STATUS,RP0
movlw B'00000111'     ; TMR0 con reloj interno, prescaler asignado a TMR0, division 1:256
movwf OPTION_REG
bcf STATUS,RP0

Con un cristal de 4MHz (el más habitual con el 16F84A), cada ciclo de instrucción dura 1µs. Con el prescaler a 1:256, TMR0 se incrementa cada 256µs, y como es un registro de 8 bits, desborda (pasa de 255 a 0 y activa el flag T0IF) cada 256 incrementos, es decir, aproximadamente cada 256 × 256µs ≈ 65,5ms.

Para llegar a 0.5 segundos, cuentas cuántos desbordamientos hacen falta (500ms ÷ 65,5ms ≈ 8 desbordamientos) y esperas ese número de veces:

Retardo_500ms
    movlw d'8'         ; numero de desbordamientos necesarios, ajustalo a tu cristal real
    movwf ContOverflow

EsperaOverflow
    bcf INTCON,T0IF       ; limpiamos el flag antes de esperar el siguiente
CheckFlag
    btfss INTCON,T0IF     ; esperamos a que TMR0 desborde
    goto CheckFlag
    decfsz ContOverflow,F
    goto EsperaOverflow
    return

Y en tu bucle principal, sustituyes las llamadas a los Retardo_200ms/Retardo_100ms por una única llamada a Retardo_500ms:

PRINCIPAL
    bsf LED
    call Retardo_500ms
    bcf LED
    call Retardo_500ms
    goto PRINCIPAL

El valor d'8' de ContOverflow depende de la frecuencia real de tu cristal, si no es de 4MHz, recalcula cuánto tarda cada desbordamiento con tu frecuencia real y ajusta el número de vueltas. Este enfoque por polling (comprobar el flag en un bucle) es el más simple de entender; si más adelante necesitas que el PIC haga otras cosas mientras espera, la evolución natural es usar el TMR0 con interrupción real en vez de sondear el flag a mano, pero para encender/apagar un LED sin más lógica de por medio, el polling es perfectamente válido y más fácil de depurar.

David Carrero