PIC16F690 LED intermitentes consecutivos

Tengo problemas para escribir el código para hacer parpadear 6 LED de PORTC en el microcontrolador PIC16F690. Los LED deben parpadear como las luces de una pista.

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

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
Explique el comportamiento exacto que espera de los LED y el comportamiento que está viendo ahora.
¿Y qué hace ese "movlw B'00000001'" justo después de la etiqueta Blink?
Suponiendo que todo lo demás funcione, probablemente solo necesite mover su (intento de) inicialización de PORTC justo al final de Initial sub.
En este momento, los LED parpadean en pares a través de los pines en PORTC. Sin embargo, me gustaría que los LED parpadeen uno por uno, desde RC0 hasta RC7.

Respuestas (2)

Hay algunos problemas con su código. Los señalaré en el orden en que creo que pueden ser el problema real aquí. Los que se encuentran en la parte inferior son solo consejos de mejores prácticas.


Inicializar PORTC

Nunca inicializas PORTC. PORTCSe desconoce el valor de en un restablecimiento de encendido. Tendrá que establecerlo en algún valor en su initialrutina:

movlw 0x01
movwf PORTC

Esto lo configura para tener un LED encendido, que es probablemente lo que desea. 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: se almacena 0b00000001en W, pero W nunca se usa. RLFtoma el registro PORTC, lo gira y lo almacena de nuevo en PORTC- W no se usa. Además, ejecuta movlw B'00000001'cada vez que recorre blink. Incluso si esto se corrigiera, el valor de PORTCnunca cambiaría porque se reinicia todo el tiempo: debe inicializar el puerto en la initialrutina y cambiarlo en la blinkrutina.


Llama y ve a

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, CALLy RETURN.

  • Con GOTO, simplemente ingrese el código, es tan fácil como eso.

  • Con CALL, implementa GOTOpero también empuja 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 ubicaciones de programas.

  • Con RETURN, extrae el último elemento de la pila y salta a esa ubicación. Esencialmente, salta a la instrucción después de la última ejecución CALL. Esto es lo que usa al principio donde llama Initialy 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 puede insertar un máximo de ocho ubicaciones de programas en esta pila. Después de eso, se sobrescribe el primer índice (la pila se implementa como un búfer circular). Básicamente, esto significa que no es posible volver a la primera CALLinstrucción 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, llamas continuamente Blink, pero no hay RETURNinstrucciones. Esto significa que seguirás empujando cosas a la pila sin hacerlas estallar. La pila se sobrescribe todo el tiempo. Como no usas RETURNallí, no importa tanto. Pero en esta situación, realmente debería usar GOTOen lugar de CALL:

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

Como GOTOno usa la pila, esto no es problema.


Organizaciones 0 y 4

Has puesto un montón de cosas org 0. Esta no es una buena práctica. Como se puede leer 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 ocurre 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 GOTOinstrucción 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...

Raíces explícitas

Como ya mencioné en los comentarios: en la parte superior de su programa indicó radix hex(y este también es el valor predeterminado). Debido a esto, puede usar EQU 20para seleccionar el registro 0x20. Sin embargo, es mucho más claro cuando solo usa EQU 0x20o EQU 20h. Cuando otros leen su código, no tienen que buscar la especificación radix o el valor predeterminado del ensamblador.


Generador de retardo

Tal vez ya sepa sobre esto, pero puede encontrarlo interesante: http://www.piclist.com/techref/piclist/codegen/delay.htm

Este es un generador de retraso que generará un retraso de un tiempo específico para usted. Su rutina de retraso es perfecta por lo que puedo ver ahora, pero si alguna vez está buscando algo que lo calcule exactamente, ¡aquí lo tiene!

¿También ayudó? :)
Hasta ahora todavía estoy tratando de depurar. A partir de ahora, ningún LED se enciende. Pero entiendo mucho mejor mi código.
Miraré por la mañana a ver si encuentro algo más.
Hola, Camil, gran respuesta, sobre la instrucción "RLF rx,d", usa 'F' como 'd', mientras que en la especificación 'd' debería ser 0 o 1. Supongo que 'F' es igual a '1' en este caso, pero ¿no sería mejor simplemente poner '1' ahí?
@VladimirCravero F de hecho es igual a 1 en estos casos, y en lugar de 0 se podría usar W. Mi opinión sería que F y W son más expresivos y preferibles (al igual que usar BANKSEL en lugar de cambiar los bits RPx manualmente, y como usar PORTA en su lugar de 0x05), pero son todas opiniones, por supuesto. ¿Tiene alguna razón en particular para preferir 1 a F?
Pensé que F era el dígito F, pero parece que F y W son caracteres especiales, así que F es mejor, sin duda.

Hay tanta mala programación en su ejemplo que una respuesta adecuada llevaría demasiado tiempo. Existe el modo absoluto, la configuración manual del banco, la ubicación fija de las variables, las suposiciones ocultas pero implícitas sobre la configuración del banco y el desbordamiento de la pila de llamadas. ¡Que desastre! Tal vez tenga tiempo para leer 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 lograr la carga de 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 habla solo de cambiar un solo LED. El error real parece ser que RLF no funciona como parece pensar, aunque sin comentarios uno no puede saber 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 pasar un solo paso por el programa y ver qué está haciendo cada instrucción.