Autor Tema: Matriz de led 8x8 PIC16f887  (Leído 1752 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado dgnr07

  • PIC10
  • *
  • Mensajes: 5
Matriz de led 8x8 PIC16f887
« en: 17 de Julio de 2021, 21:23:55 »
Hola, estuve leyendo muchos topics acerca de los carteles de leds y arme uno pequeño de 8x8 para practicar y luego armar uno mas grande, entiendo la teoria de como funciona y puedo mostrar un texto fijo (en el caso de 8x8 una letra) pero no entiendo come se hace para desplazar un texto largo.
lei acerca de direccionamiento directo, indirecto, punteros, pero me cuesta entenderlo

usando tablas puedo mostrar una letra fija, en este caso la "M"
lo que hago es cargar en una tabla los datos de la letra "M"
luego, tomo el primer bit y si es 1 seteo la salida de datos que va al registro de deplazamiento, o hago un bcf en caso que sea 0
doy el pulso de clock
roto una vez los  bits
repito el proceso 7 veces mas
luego llamo la tabla de filas y muestro la primera por 5ms
apago todo
este proceso se repite 7 veces mas (en total son 8 bits, rotados 8 veces x 8 filas)

Código: [Seleccionar]
list p=16f887 ; list directive to define processor
#include <p16f887.inc> ; processor specific variable definitions

__CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
__CONFIG    _CONFIG2, _WRT_OFF & _BOR21V


DATO EQU 0X05 ;D5 PARA DATOS
ENTER EQU 0X06 ;D6 PARA CLOCK
RESET EQU 0X07 ;D7 PARA RESET DE REGISTROS


CBLOCK H'20'
CONTADATOS ;8 FILA POR LETRA  0X20
CONTAROTAR ;8 BITS POR FILA   0X21
FILA ;NUMERO DE FILA A MOSTRAR B07 A B00  0X22
DATOSALIDA ;BIT A SACAR POR DATA  0X23
Contador1 ;temporizador5ms    0X24
Contador2 ;temporizador5ms    0X25
ENDC


ORG 0X00
GOTO INICIO
ORG 0X05



INICIO 
BCF STATUS,RP0 ;Pone a cero el RP0 del STATUS
BCF STATUS,RP1 ;Pone a cero el RP1 del STATUS y selecionamos banco 0
BSF STATUS,RP0 ;Pone a 1 el bit RP0 del STATUS , se selecciona el banco 1

MOVLW B'01100000'          ;Carga el valor 0X70 en el registro W p/ config la frec a 4 MHz
MOVWF OSCCON ;Carga lo que hay en W a OSCCON osea que pasa el valor de W hacia OSCCON
BANKSEL ANSEL ;
CLRF ANSEL         ;digital I/O pines bajos (0:5)
CLRF ANSELH         ;digital I/O pines altos (6:7)

BANKSEL TRISA
MOVLW B'00000000' ;Config. de entradas y salidas
MOVWF TRISB
MOVLW B'00000000' ;Config. de entradas y salidas
MOVWF TRISC
MOVLW B'00000100'
MOVWF TRISD
MOVLW B'00000000'
MOVWF TRISE
BCF STATUS,RP0          ;VUELVO A BANK0



MOVLW B'11111111' ;APAGO FILAS
MOVWF PORTB ;
INICIA bsf PORTD,7         ;HABILITO RESET

CLRF CONTADATOS        ;PARA INDICAR PRIMER BIT  0X20
CLRF CONTAROTAR        ;PARA INDICAR CANT DE ROTACIONES 0X21
CLRF FILA                ;PARA MUESTREO DE FILAS 0X22

LLAMATABLA    MOVF CONTADATOS,W ;INDICO POSICION TABLA DATOS     0X20
   CALL TABLADATOS
   MOVWF DATOSALIDA ;GUARDO EL VALOR DE LA TABLA 0X23
SIGUEROTANDO BTFSC DATOSALIDA,0 ;PREGUNTO SI EL PRIMER BIT ES 0 - 1
    GOTO SETEADATO ;SETEO SI ES 1 CALL 0X06A
    GOTO RESETEADATO ;RESETEO SI ES 0
HABILITA     CALL CLOCK ;ENVIO DATO A LA SALIDA
     RRF DATOSALIDA,1 ;ROTO BITS  0X23
     INCF CONTAROTAR 0X21
     MOVLW .8
     SUBWF CONTAROTAR,W ;PREGUNTO SI ROTO 8 VECES
     BTFSC STATUS,2
     GOTO YAROTO ;YA ROTO, VA A MUESTREO DE FILAS
    GOTO SIGUEROTANDO ;TODAVIA NO, SIGUE ROTANDO BITS

YAROTO
     CLRF CONTAROTAR
     MOVF FILA,W ;SELECCIONO FILA A MOSTRAR
     CALL TABLAFILAS
     MOVWF PORTB ;ACTIVO FILA
      CALL Demora_5ms

     MOVLW 0XFF ;APAGO TODAS
     MOVWF PORTB ;

      INCF FILA ;0X22
      INCF CONTADATOS ;0X20
      MOVLW .8
      SUBWF CONTADATOS,W ;PREGUNTO SI YA MOSTRO LAS 8 FILAS
      BTFSC STATUS,2
      GOTO  INICIA ;SI, REPITE TODO EL PROGRAMA
       GOTO LLAMATABLA ;NO, VUELVE A ROTAR BITS Y CONTINUA CON OTRA FILA GOTO 0X020




TABLADATOS ADDWF PCL,F
RETLW B'11111111'
RETLW B'00111001'
RETLW B'01010101' ;DIBUJA LAS COLUMNAS
RETLW B'01101101'
RETLW B'01111101'
RETLW B'01111101'
RETLW B'01111101'
RETLW B'01111101'

TABLAFILAS ADDWF PCL,F
RETLW B'01111111'
RETLW B'10111111'
RETLW B'11011111'
RETLW B'11101111' ;MUESTREO DE FILAS
RETLW B'11110111'
RETLW B'11111011'
RETLW B'11111101'
RETLW B'11111110'

goto INICIA






SETEADATO BSF          PORTD,DATO
        GOTO HABILITA

RESETEADATO BCF          PORTD,DATO
        GOTO HABILITA

;...............................
CLOCK         NOP
BSF PORTD,ENTER
NOP
BCF PORTD,ENTER
RETURN
;..............................

Demora_5ms
movlw 0xA0 ; 200
movwf Contador1 ; Iniciamos contador1.-
Repeticion1
movlw 0x05 ;
movwf Contador2 ; Iniciamos contador2
Repeticion2
decfsz Contador2,1 ; Decrementa Contador2 y si es 0 sale.-
goto Repeticion2 ; Si no es 0 repetimos ciclo.-
decfsz Contador1,1 ; Decrementa Contador1.-
goto Repeticion1 ; Si no es cero repetimos ciclo.-
return ; Regresa de la subrutina.-
END

con esto logro que se muestre la letra de manera perfecta, pero quiero desplazarla.
en en final del programa:

                SUBWF   CONTADATOS,W      ;PREGUNTO SI YA MOSTRO LAS 8 FILAS
               BTFSC    STATUS,2
               GOTO     INICIA         ;SI, REPITE TODO EL PROGRAMA
                GOTO    LLAMATABLA      ;NO, VUELVE A ROTAR BITS Y CONTINUA CON OTRA FILA       GOTO 0X020

en el goto inicia, la idea ir a un goto desplazar y ahi rotar una vez mas un bit de cada linea y realizar todo el muestreo nuevamente, pero en este paso se me deforma todo



Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Matriz de led 8x8 PIC16f887
« Respuesta #1 en: 18 de Julio de 2021, 11:39:57 »
En realidad te lo voy a tratar de explicar con un ejemplo y no con codigo. Luego vos vas a tener que realizarlo.

Direccionamiento directo, indirecto, punteros: Todos nombres raros, primero te voy a aclarar esto..

Direccionamiento directo, usando las definiciones de tu programa:
Código: ASM
  1. MOVF DATOS, W

DATOS es lo mismo que 0x05, por lo tanto esa instrucción es MOVF 0x05, W . A la instrucción le estas dando el valor de la dirección a la cual acceder. Junto con la parte alta definida por los bits RP0 y RP1 crean la dirección 0x005 y se accede a esta... En resumen.. Directo = Darle la dirección.

Direccionamiento indirecto, supongamos que quiero acceder a la dirección RAM 0x05, estonces cargo mi valor en el registro FSR el cual es mi puntero, el puntero apunta a la direccion que yo quiero acceder y luego lo accedo desde el registro INDF. Ejemplo, guardar 0xFE en la direccion 0x05

Código: ASM
  1. MOVLW 0x05
  2. MOVWF FSR
  3. MOVLW 0xFE
  4. MOVWF INDF

Para que hacer semejante codigo para guardar un valor te preguntaras, pero ahora veamos si yo quiero llenar las direcciones RAM 0x30 a 0x4F, con los valores 0x11. Si lo hago con direccionamiento directo necesitaria 32 instrucciones, uno por cada direccion mas uno de carga. Con direccionamiento indirecto es mas sencillo.
Código: ASM
  1. RELLENAR_RAM:
  2.    MOVLW 0x30 ;Cargo la dirección inicial
  3.    MOVWF FSR
  4. LOOP:
  5.    MOVLW 0x11 ;Guardo el dato a donde dice FSR
  6.    MOVWF INDF
  7.    INCF FSR, F ; Incremento FSR, es decir ahora cuando acceda a INDF va a ser en la otra posición de memoria
  8.    SUBLW FSR, 0x50 ; Reviso que no me pase.
  9.    BTFSS STATUS,Z ; Si llegue a los 0x50 Salgo, sino repito el LOOP para seguir llenandolo
  10.    GOTO LOOP
  11.    RETURN

-------------------------------------------------------------------------------------------

Ahora vamos a diferenciar dos conceptos parecido pero distintos.
Puntero: Contiene la DIRECCION a la cual queres acceder.
Indice: Contiene la posicion en una tabla.

Si observaste en los ejemplos de antes yo use la RAM, porque el PIC16F887 solo permite el direccionamiento indirecto de la RAM, los PIC18 poseen otras funcionalidades que permiten el acceso a la FLASH de mas misma forma.
Pero tus tablas estan realizadas en la FLASH, por lo que nos vamos a tener que manejar con indices.

¿Como rotar la letra?

Sabes que tenes 8 Filas y 8 Columnas, por lo tanto SABES que son 8 datos. Voy a hacer un ejemplo con una matriz 3 x 3. El cual van a ser 3 datos.

0 1 0
1 1 0
1 0 1

Suponete que quiero que se muestren los leds como arriba. Y quiero que rote. Puedo hacerlo de varias formas, que al rotar se produzca un wrap, es decir aparezca de nuevo en la primer linea:

-----------------------> Rotando
0 1 0            0 0 1            1 0 0
1 1 0            0 1 1            1 0 1
1 0 1            1 1 0            0 1 1


O que desaparezca y luego aparezca de nuevo

-----------------------------------------------------------------------> Rotando
0 1 0            0 0 1            0 0 0             0 0 0             0 0 0             1 0 0
1 1 0            0 1 1            0 0 1             0 0 0             0 0 0             1 0 0
1 0 1            0 1 0            0 0 1             0 0 0             1 0 0             0 1 0


Pensemos como hacer la mas complicada que es la de abajo. Para que desaparezca
La primera vez muestro todo como si fuera fijo, tomando los datos de la tabla, comienzo desde el indice 0. Y muestro todo.
La segunda vez la primer columna la quiero en 0, y luego lo demas, tiene que comenzar desde el indice 0. Hasta un total de 3 datos.
La tercera vez la primera y la segunda columna la quiero en 0, y luego lo demas, tiene que comenzar desde el indice 0. Hasta un total de 3 datos.

Para que aparezca
Solo debemos mostrar la ultima, y luego 2 mas todo 0. 3 datos en total
Mostrar las ultimas 2 y luego todo 0. 3 datos en total.

Siempre son 3 datos. Por lo tanto el loop en este caso se mantiene en los 3 datos que habíamos hablado antes, en tu caso 8. Solamente necesitamos "1 variable mas" que nos indique CUANDO comenzar a mostrar lo de la tabla, o si mostrar o no. Aca entra tu ingenio.

Una idea que se me ocurre en este momento, no la considero la mejor. Pero por ejemplo para mostrar, podria agregar una parte de codigo que revise si el valor de indice que llevo a la TABLADATOS, sea menor a 8, o mayor a 7, como te sea mas comodo. De esa forma tener una variable mas que me diga desde donde comenzar, por ejemplo, COMIENZA = 0.

CONTADATOS  = COMIENZA.
SI CONTADATOS > 7 ?
Si -> POngo un 0
No -> Llamo a TABLADATOS

Cuando quiera rotar, solo hago COMIENZA -1 , y ya con eso logro que comienze antes. Por ejemplo
Al ser COMIENZA 0xFF. En la primer vuelta CONTADATOS es mayor a 7, y por lo tanto se envia un 0 y no se llama a la tabla. Luego en la proxima pasada (de los 8 datos) se va a incrementar CONTADATOS y pasa a tener un valor de 0, y es decir en la segunda columna tendria lo que se mostraba en la primera. Asi hasta los 8 datos.

Observa que en mi ejemplo solo modifico lo que aparecen en las columnas, es decir la parte de los datos y no de los comunes como tenes en TABLAFILAS. Esa parte siempre va rotando y cumpliendo sus 8 datos como siempre.

Y si quiero que aparezca? Primero tengo que detectar cuando COMIENZA llego a hacer desaparecer todo. De forma sencilla
Con 0xFF hicimos desaparecer la primera, con 0xFE hasta la segunda, es decir el complemento a 2 de las filas que queremos hacer desaparecer.
El complemento a 2 se saca de la siguiente forma.  Si quiero el complemento a 2 de 1, entonces primero hago el complemento y luego le sumo 1, en este ejemplo
0000 0001  -> complementado (negado) es ->  1111 1110, si le sumo 1 queda 1111 1111 = 0xFF
A los 8 datos me desaparece todo, pero yo quiero que desaparezca todo como en el ejemplo, por lo tanto debo detectar a los 9. Hago el complemento a 2 de 9
0000 1001 -> 1111 0110 +1 -> 1111 0111 = 0xF7

Es decir... Cuando detecte que COMIENZA es 0xF7, procedo a asignarle el valor 0x07, asi CONTADATOS comienza con el valor 7, y muestra la ultima fila de la tabla.
Continuo restando CONTADATOS como al mostrar.

En resumen el codigo sin mayores cambios

Código: ASM
  1. COMIENZA = 0
  2. Loop:
  3. CONTADATOS  = COMIENZA.
  4.  
  5. ; Comienzo de la muestra de las letras
  6.    REPITO 8 veces (CONTAROTAR):
  7.       ¿CONTADATOS mayor a 7 ?
  8.       Si -> POngo un 0
  9.       No -> Llamo a TABLADATOS
  10.       Llamo a TABLAFILAS indicado por CONTAROTAR
  11.       MUESTRO
  12. ; Fin de la muestra de las letras, repetir para aumentar el tiempo de desplazamiento.
  13. COMIENZA = COMIENZA - 1
  14. ¿COMIENZA igual a 0xF7?
  15. Si-> COMIENZA = 0x07
  16. Goto Loop

Fin del pseudocodigo. En resumen, estas creando un INDICE para decirle donde comenzar. E implementando unas protecciones sobre la tabla para no excederte de los valores permitidos. Es todo lo que hay que agregar.

PD: Si no me equivoco este PIC puede leer la Flah mediante lo que es la EEPROM, no me fije en eso.
« Última modificación: 18 de Julio de 2021, 12:24:26 por KILLERJC »

Desconectado dgnr07

  • PIC10
  • *
  • Mensajes: 5
Re:Matriz de led 8x8 PIC16f887
« Respuesta #2 en: 18 de Julio de 2021, 14:20:42 »
Gracias por tu respuesta tan completa.
Tengo las cosas un poquito mas claras, aunque tengo que releerlo varias veces hasta afianzarlo...

En el momento en que en mi programa pregunto por el bit que voy a enviar al registro hago un "btfsc,0"
siempre es el ultimo bit de registro el que envío,y luego roto los 8 bits 8 veces.

podria hacer que en vez de preguntar siempre por ese ultimo bit, hacer un "btfsc,rot"    y que ese rot sea mi indice?
entonces una vez que haya mostrado toda la letra, incremento rot para que en una segunda vuelta todo el ciclo en vez de comenzar a enviar al registro el bit 0, arranque desde el bit 1 y luego los 7 restantes... finalizada esa vuelta incremento rot y en la 3er vuelta el dato comienza a enviarse desde btfsc,2 y asi las 8 veces? de esta manera usando siempre la misma tabla el envio de datos se va desplazando hacia izquierda...?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Matriz de led 8x8 PIC16f887
« Respuesta #3 en: 18 de Julio de 2021, 16:29:20 »
Parece que estas usando un registro de desplazamiento, no me había fijado en tu programa que lo tenias así.

CONTAROTAR que yo suponía que eran los 8 datos, en realidad son los 8 bits del dato, el cual estas sacando de forma secuencial.. Pido perdon por haberte causado confusion en ese punto.

Pero la forma de programación es "la misma"... Separa las tareas

Una subrutina que indica que dato se debe enviar. Le da formato, es decir lo acomoda asi queda como debe ser enviado y lo guarda en un registro.
Una subrutina que envía el dato. Toma el dato de la subrutina anterior, y lo envia bit a bit. No haces nada raro acá, solo se encarga de enviar.

Eso repetido 8 veces. 1 byte completo por cada fila. Incluso podes usar el registro que uses para llevar las vueltas de esas 8 veces, como referencia de que fila activar.

Citar
podria hacer que en vez de preguntar siempre por ese ultimo bit, hacer un "btfsc,rot"    y que ese rot sea mi indice?
ntonces una vez que haya mostrado toda la letra, incremento rot para que en una segunda vuelta todo el ciclo en vez de comenzar a enviar al registro el bit 0, arranque desde el bit 1 y luego los 7 restantes... finalizada esa vuelta incremento rot y en la 3er vuelta el dato comienza a enviarse desde btfsc,2 y asi las 8 veces? de esta manera usando siempre la misma tabla el envio de datos se va desplazando hacia izquierda...?
La instruccion BTFSC registro, bit... No permite cambiar el bit en un loop, es decir NO puedo hacer algo asi:

Código: ASM
  1. CLRF INDEX
  2. BTFSC DATO, INDEX
  3. INCF INDEX

si podes rotar algunas veces antes por ejemplo para comenzar de otro punto, sin enviar el bit.

Código: ASM
  1. RRF DATO
  2. RRF DATO
  3. ;Recien aca lo envias

Pero OJO!, ya que al rotar incluis el Carry!, asi que antes de rotar deberias setear el carry al bit 0.

Código: ASM
  1. ;Esto para rotarlo 1 vez, sin que moleste el carry.
  2. BCF STATUS, C
  3. BTFSC DATO, 0
  4. BSF STATUS, C
  5. RRF DATO
  6.  
  7. ;Ahora cuando lo envies, va a estar desplazado en 1.
  8. CALL ENVIAR ;Recien aca lo envias

Espero que esto responda tu pregunta.