Hay algunos problemas con tu código. Los señalaré por orden de lo que creo que pueden ser el problema real aquí. Los que están en la parte inferior son solo consejos de mejores prácticas.
Inicializar PORTC
Nunca inicializas PORTC
. El valor de PORTC
es desconocido en un reinicio de encendido. Deberá establecerlo en algún valor en su rutina initial
:
movlw 0x01
movwf PORTC
Esto lo configura para tener un LED encendido, que es probablemente lo que quieres. Después de eso, con RLF
, comenzará a girar este bit para encender otros LED.
Puede ser que esta sea la idea detrás de estas líneas en blink
:
movlw B'00000001'
rlf PORTC,F
Sin embargo, la primera línea no tiene ningún efecto: almacena 0b00000001
en W, pero W nunca se usa. RLF
toma el registro PORTC
, lo gira y lo almacena nuevamente en PORTC
- W no se usa. Además, ejecuta movlw B'00000001'
cada vez que recorras blink
. Incluso si esto fuera correcto, el valor de PORTC
nunca cambiaría porque se reinicia todo el tiempo: tienes que inicializar el puerto en la rutina initial
y cambiarlo en la rutina blink
.
Llamar y goto
Blink ;flip the LED on or off
movlw B'00000001'
rlf PORTC,F
call Delay
call Blink
Hay tres tipos diferentes de instrucciones para saltar en el código: GOTO
, CALL
y RETURN
.
-
Con GOTO
, simplemente ingresa el código, es tan fácil como eso.
-
Con CALL
, implementas GOTO
pero también presionas el contador del programa actual en la pila. Esta pila es un módulo de memoria LIFO (último en entrar, primero en salir) en el que en este caso se pueden almacenar las ubicaciones de los programas.
-
Con RETURN
, saca el último elemento de la pila y salta a esa ubicación. Esencialmente, debes saltar a la instrucción después del último CALL
ejecutado. Esto es lo que usa al principio, donde llama a Initial
y luego regresa y llama a Blink
.
La pila de este chip tiene ocho niveles, como se describe en la sección 2.3.2 de la hoja de datos . Eso significa que puedes empujar un máximo de ocho ubicaciones de programas en esta pila. Después de eso, el primer índice se sobrescribe (la pila se implementa como un búfer circular). Básicamente, esto significa que no es posible volver a la primera instrucción CALL
y que el controlador saltará a otra posición. Esto puede causar muchos problemas inexplicables en software más avanzado.
Con el código que cité arriba, continuamente llamas a Blink
, pero no hay una instrucción RETURN
. Esto significa que seguirás empujando cosas a la pila sin hacerla estallar. La pila se sobrescribe todo el tiempo. Ya que no usa RETURN
allí, no importa mucho. Pero en esta situación, realmente deberías usar GOTO
en lugar de CALL
:
Blink ;flip the LED on or off
movlw B'00000001'
rlf PORTC,F
call Delay
goto Blink
Dado que GOTO
no usa la pila, esto no es un problema.
Org 0 y 4
Has puesto muchas cosas en org 0
. Esto no es una buena práctica. Como puede leerse en la sección 2.1 de la hoja de datos , este chip tiene un vector de interrupción en org 4
. Esto significa que cuando se produce una interrupción, el contador del programa saltará a la ubicación 4, casi directamente después de 0. Es por eso que normalmente implementamos solo una instrucción GOTO
en org 0
. Algo como esto:
org 0
goto start
org 4
retfie ; return from interrupt (alternatively you could have
; an interrupt handler here)
start:
; your main code...
Radices explícitas
Como ya mencioné en los comentarios: en la parte superior de tu programa, indicaste radix hex
(y esto también es el valor predeterminado). Debido a esto, puede usar EQU 20
para seleccionar el registro 0x20
. Sin embargo, es mucho más claro cuando solo usas EQU 0x20
o EQU 20h
. Cuando otros leen su código, no tienen que buscar la especificación de radix o el valor predeterminado del ensamblador.
generador de retardo
Tal vez usted ya sepa acerca de esto, pero puede encontrar esto interesante: enlace
Este es un generador de retardo que generará un retardo de un tiempo específico para usted. Su rutina de demora es perfecta hasta donde puedo ver, pero si alguna vez busca algo que lo calcula exactamente, ¡aquí tiene!