PIC16F690 LED's intermitentes consecutivos

2

Tengo problemas para escribir el código para destellar 6 LED de PORTC en el microcontrolador PIC16F690. Los LEDs deberían parpadear como las luces en una pista.

Con el código que tengo actualmente, los LED están parpadeando en pares y fuera de orden.

Aquí está el código que tengo actualmente:

list p=16F690
radix hex
include "P16F690.INC"
__config _WDT_OFF & _BOR_OFF & _PWRTE_ON & _INTOSCIO & _MCLRE_OFF
errorlevel -302
org 0

count equ 20        ;we're going to need two variables
count2 equ 21

call initial
call Blink

initial         ; initialize registers
    bsf STATUS, RP0
    movlw B'00000000'
    movwf TRISC
    bcf STATUS, RP0
    bsf STATUS, RP1
    clrf ANSEL
    clrf ANSELH
    bcf STATUS, RP1
    return

Blink            ;flip the LED on or off
    movlw B'00000001'
    rlf PORTC,F
    call Delay
    call Blink

Delay           ; waste time
    movlw 0xFF
    movwf count
    movwf count2
Delayloop
    decfsz count,f
    goto Delayloop
    decfsz count2,f
    goto Delayloop
    return

END
    
pregunta mrplow911

2 respuestas

3

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!

    
respondido por el Keelan
2

Hay tanta mala programación en tu ejemplo que una respuesta correcta tomaría demasiado tiempo. Existe un modo absoluto, configuración de banco manual, ubicación fija de variables, suposiciones ocultas pero implícitas sobre la configuración de banco y desbordamiento de la pila de llamadas. ¡Que desastre! Tal vez tenga tiempo para vadear todo eso mañana.

Sin embargo, el código en BLINK es particularmente confuso y probablemente sea la fuente del problema. Ni siquiera puedo adivinar lo que crees que se supone que debe cargar 1 en W. La falta de comentarios es francamente irresponsable. En su descripción sobre el código, habla de varios LED, pero el comentario en BLINK solo habla de encender un solo LED. El verdadero error parece ser que RLF no funciona como parece pensar, aunque sin comentarios no se puede decir lo que está pensando. Tenga en cuenta que la rotación se realiza en 9 bits, el registro y el bit C.

Esto debería ser fácil de depurar. Cargue esto en MPLAB y ejecútelo en el simulador. Luego, puede realizar un solo paso a través del programa y ver qué está haciendo cada instrucción.

    
respondido por el Olin Lathrop

Lea otras preguntas en las etiquetas