Soy un novato con la programación de microcontroladores. Tengo conocimientos de programación de alto nivel, pero me estoy involucrando en el desarrollo de CPU/microcontroladores de bajo nivel.
Quiero hacer este simple ejercicio de encender y apagar una serie de LED durante 1 segundo cada uno.
Probé este montaje (pensando en dos leds):
List P=18F4550
include <P18F4550.inc>
CONFIG FOSC = INTOSC_EC ;INTOSC_EC ; Internal oscillator
CONFIG PWRT= ON ; Power-up Timer Enable bit
CONFIG BOR=OFF ; Brown-out Reset disabled in hardware and software
CONFIG WDT=OFF ; WDT disabled
CONFIG MCLRE=ON ; MCLR pin enabled
CONFIG PBADEN=OFF ; PORTB<4:0> pins are configured as digital I/O
CONFIG LVP=OFF ; Single-Supply ICSP disabled
CONFIG DEBUG = OFF ; Background debugger disabled
CONFIG XINST = OFF ; Extended Instruction disabled
;******************************Variables***********************************
count equ 0x00
;**********************************************************************************
org 0x0000
movlw 0x62
movwf OSCCON ;Working at 4 MhZ
clrf TRISD ;D port as output
;leds OFF so far
LGHTLOOP
bcf PORTD,0
call DELAY
bsf PORTD,0
CALL DELAY
bcf PORTD,1
call DELAY
bsf PORTD,1
CALL DELAY
bra LIGHTLOOP
DELAY
movlw .1000
movwf count
LOOP2
DECFSZ count,F
bra LOOP2
nop
return
end
Intenté simularlo en el software Proteus, teniendo esta configuración:
De hecho, puedo ver los LED encendiéndose y apagándose, pero nada como un segundo, sin importar cuánto cambie movlw .255
en DELAY
la subrutina. Probé con diferentes valores más altos y obtuve el mismo comportamiento extraño.
¿En qué me equivoqué?
movlw .255
Creo que contar los ciclos de instrucciones en las subrutinas debería ser más de 1 segundo. Pero aún así la simulación lo muestra más rápido. Agregar dos leds más lo hace parecer aún más rápido.
El problema es que la decfsz
instrucción funciona implícitamente en un registro de un byte (8 bits). El valor más grande que puede contener dicho registro es FF hexadecimal (decimal 255). Cuando intenta inicializar count
a decimal 1000 (hexadecimal 3E8), en realidad solo está configurando ese registro en los 8 bits de orden inferior de ese valor, o E8 (decimal 232).
Para eludir esta limitación de la decfsz
instrucción, la técnica habitual es crear un "nido" de dos bucles, cada uno con una variable separada. Esto le permitiría ejecutar el cuerpo del bucle interno hasta 65535 veces (0xFFFF hexadecimal).
; control variable for inner loop
i equ 0
; control variable for outer loop
j equ 1
; initialize j with the MSBs of the loop count
movlw .1000 >> 8
movwf j
; initialize i with the LSBs of the loop count
movlw .1000 & 0xFF
movwf i
loop:
; body of loop here
nop
; end of inner loop
decfsz i
bra loop
; end of outer loop
decfsz j
bra loop
Tenga en cuenta que el ciclo interno se ejecuta la cantidad de veces i
que se inicializa en la primera iteración del ciclo externo. Cada vez después de eso, se ejecuta 256 veces.
nop
, cada iteración requerirá 4 ciclos de máquina, lo que significa que deberá ejecutar 250,000 iteraciones. Esto es demasiado para el bucle anidado doble, por lo que puede poner más instrucciones en el cuerpo del bucle o puede agregar un tercer nivel de bucle.Esto es lo que necesitas:
http://www.piclist.com/cgi-bin/delay.exe
probablemente el sitio más útil jamás creado. (¡Después de este!)
Cabe señalar que, si bien esto resolverá su problema, tampoco le enseñará absolutamente nada sobre cómo programar el suyo propio, aunque si lee el código que genera, puede resolverlo.
La otra respuesta debe leerse correctamente si desea una comprensión real. Esto es solo para que las cosas funcionen.
diegoaguilar
diegoaguilar
diegoaguilar
Samuel
diegoaguilar
nop
por fin. Eso debería estar induciendo al retardado.Samuel
Spehro Pefhany