; CARTEL DE LEDS. de 8x8. 
; Si las letras son de 8x8, maxima cantidad de letras en el mensaje 31
; Xtal = 4 Mhz


                      list p=16F84A                      ;Microcontrolador utilizado
                      #include P16F84A.inc               ;Definicion de registros SFR

 
 __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC



                      CBLOCK 0x0C      	                 ;En esta posicion se declaran los registros de usuario (GPR)
	              STATUS_Temp  	                 ;Registro para guardar temporalmete STATUS
	              W_Temp   		                 ;Registro para guardar temporalmete W
	              Banderas		                 ;Registro para almacenar banderas
	              FilaActual		         ;Fila Actual a refrescar
	              PosicionInicial	                 ;Posicion inicial dentro del mensaje a visualizar en el cartel.- (Entre 0 y LargoMsj-1)
	              PosicionEnviar	                 ;Posicion del registro a enviar.-
	              CuentaRefrescos	                 ;Cuenta la cantidad de refrescos realizados
	              LargoCartel		         ;Guarda largo del cartel.- 32
	              LargoMsj		                 ;largo del mesaje a visualizar-> Max 249 Bytes.-Para aumentar modificar manejo de tabla
	              TempH			         ;Temporal para guardar calculos matemáticos.-
	              TempL			         ;Temporal...
	              VelMovimiento	                 ;Para fijar velocidad de movimiento.
                      ENDC

Velocidad	      equ	d'8'	                 ;Para fijar velocidad de desplazamiento
kbhit_tiempo	      equ	  0		         ;Bandera que indica que han pasado 2ms
kbhit_cuadro	      equ         1
BData	              equ	  3
BClock		      equ	  2


;**************************************************************************************************************************
;               Inicio del Microcontrolador
;**************************************************************************************************************************

Reset
                      org	  0x00
                      goto	  Inicio	         ;Salto a inicio del programa


;**************************************************************************************************************************
;                 Vector de Interrupcion
;**************************************************************************************************************************

                      org	  0x04
                      goto        Inicio_ISR	         ;Atiendo Interrupcion


;**************************************************************************************************************************
;                    Mensaje a Mostrar
;**************************************************************************************************************************

	              org	  0x05
Mensaje
	              addwf	  PCL,1		         ;Se incrementa el contador del programa

	DT 0xC7, 0x83, 0x01, 0x7D, 0x7D, 0x7D, 0xBB, 0xFF	; C
	DT 0x9F, 0x0B, 0x6B, 0x6B, 0x03, 0x07, 0xFF, 0xFF	; a
	DT 0x03, 0x03, 0xF7, 0xFB, 0xFB, 0xFF, 0xFF, 0xFF	; r
	DT 0xFB, 0x01, 0x01, 0x7B, 0xBF, 0xFF, 0xFF, 0xFF	; t
	DT 0x87, 0x03, 0x6B, 0x63, 0xA7, 0xFF, 0xFF, 0xFF	; e
	DT 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; l
	DT 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; Espacio
	DT 0x87, 0x03, 0x7B, 0xB7, 0x01, 0x01, 0xFF, 0xFF	; d
	DT 0x87, 0x03, 0x6B, 0x63, 0xA7, 0xFF, 0xFF, 0xFF	; e
	DT 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; Espacio
	DT 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; l
	DT 0x87, 0x03, 0x6B, 0x63, 0xA7, 0xFF, 0xFF, 0xFF	; e
	DT 0x87, 0x03, 0x7B, 0x87, 0x01, 0x01, 0xFF, 0xFF	; d
	DT 0x77, 0x63, 0x6B, 0x0B, 0x9B, 0xFF, 0xFF, 0xFF	; s
	DT 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; Espacio
	DT 0x77, 0x63, 0x6B, 0x0B, 0x9B, 0xFF, 0xFF, 0xFF	; S
	DT 0x83, 0x03, 0x7F, 0x7F, 0x03, 0x03, 0xFF, 0xFF	; u
	DT 0x01, 0x01, 0xEF, 0xC7, 0x9B, 0x3B, 0x7F, 0xFF	; k
	DT 0xFB, 0x73, 0x47, 0x8F, 0xCF, 0xF7, 0xFB, 0xFF	; y
	DT 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; Espacio
	DT 0x7D, 0x3E, 0x5E, 0x6E, 0x31, 0xFF, 0xFF, 0xFF	; 2
	DT 0x7F, 0x79, 0x7A, 0x76, 0x8E, 0xFF, 0xFF, 0xFF	; 5
	DT 0x3F, 0xC3, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; /
	DT 0x7E, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; 1
	DT 0x81, 0x7E, 0x7E, 0x7E, 0x81, 0xFF, 0xFF, 0xFF	; 0
	DT 0x3F, 0xC3, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; /
	DT 0x81, 0x7E, 0x7E, 0x7E, 0x81, 0xFF, 0xFF, 0xFF	; 0
	DT 0x71, 0x6E, 0xAE, 0x8E, 0xE1, 0xFF, 0xFF, 0xFF	; 9
	DT 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF	; Espacio


;**************************************************************************************************************************
;                  Inicio del microcontrolador
;**************************************************************************************************************************



Inicio                bsf         STATUS,RP0             ;Banco 1
                      movlw       0x00
                      movwf       TRISA                  ;ssssssss
                      movlw       0x00
                      movwf       TRISB                  ;ssssssss
                      movlw       b'00000110'
                      movwf       OPTION_REG    
                      bcf         STATUS,RP0             ;Banco 0

	              clrf	  PORTA
	 
                      movlw	  Velocidad	         ;Cargamos velocidad de desplazamiento
	              movwf	  VelMovimiento
	              movlw	  d'8'		         ;Cargamos largo del cartel
	              movwf	  LargoCartel
	              movlw	  d'232' 	         ;Cargamos largo del mensaje
	              movwf	  LargoMsj
	              clrf	  PosicionInicial
	              clrf	  Banderas
	              movlw	  0x01
	              movwf	  FilaActual
	              movlw	  0x08
	              movwf	  CuentaRefrescos

       
                      MOVLW	  D'240'                 ;cargo w con 240
	              MOVWF	  TMR0	                 ;para que el TMR0 se desborde cada 2 ms aprox
                                                         ;T = (256 - 240) x 128 x 1 us = 2048 us = 2,048 ms
                      movlw	  0XA0		         ;cargo w con 10100000 para
	              movwf	  INTCON	         ;habilitar GIE y T0IE


Bucle                 btfss	  Banderas,kbhit_tiempo	 ;Se espera a que pasen 2 ms
	              goto	  $-1
	              bcf	  Banderas,kbhit_tiempo
	              call	  ActualizarCartel       ;Se actuliza fila del cartel
	              goto	  Bucle



;**************************************************************************************************************************
;                 Rutina de servicio de Interrupcion
;**************************************************************************************************************************



Inicio_ISR            movwf       W_Temp                 ;Copiamos W a un registro Temporario
                      swapf       STATUS,W               ;Invertimos nibles de STATUS
                      movwf       STATUS_Temp            ;Guardamos STATUS en un registro temporal

    
                      btfsc       INTCON,T0IF            ;Comprueba si la interrupción ha sido el tmr0 
                      goto        ISR_TIMER0             ;Si, se trata interrupcion


Fin_ISR               swapf       STATUS_Temp,W
                      movwf       STATUS
                      swapf       W_Temp,f
                      swapf       W_Temp,W
                      MOVLW	  D'240'                 ;cargo w con 240
	              MOVWF	  TMR0	                 ;para que el TMR0 se desborde cada 2 ms aprox
                                                         ;T = (256 - 240) x 128 x 1 us = 2048 us = 2,048 ms
                      retfie

ISR_TIMER0            decfsz	  CuentaRefrescos,1	 ;Se refrescaron las 8 filas (Momento adecuado para realizar algun cambio.-)
	              goto	  SetBandera		 ;No, seguimos..		
	              decfsz	  VelMovimiento,1	 ;Si, ya pasaron 16ms x VelMovimiento?
	              goto	  RecargarData		 ;No, seguimos...
	              movlw	  Velocidad	         ;Recargamos Velocidad
	              movwf	  VelMovimiento
	              incf	  PosicionInicial	 ;Si, incrementamos PosicionInicial para efectuar "movimiento"
	              movfw	  LargoMsj		 ;Verificamos si ya se llego al final del Mensaje
	              subwf	  PosicionInicial,0
	              btfss	  STATUS,Z
	              goto	  RecargarData		 ;No, seguimos..
	              clrf	  PosicionInicial	 ;Si, reseteamos PosicionInicial

RecargarData          movlw	  0x01
	              movwf	  FilaActual
                      movlw	  0x08
	              movwf	  CuentaRefrescos

SetBandera            bsf	  Banderas,kbhit_tiempo	 ;Indicamos que han pasado 2 ms, y es necesario actualizar
                      bcf         INTCON,T0IF            ;Borramos bandera
                      goto        Fin_ISR



;**************************************************************************************************************************
; Es (PosicionInicial + LargoCartel <= LargoMsj)?
;**************************************************************************************************************************


ActualizarCartel      clrf	  TempH			 ;Borramos Byte alto de variable de 16bits temporal.
	              bcf	  STATUS,C		 ;Aseguramos que el carry sea 0 :P
	              movfw	  PosicionInicial	 ;Sumamos PosicionInicial + largoCartel.
	              addwf	  LargoCartel,0		 ;Y lo guardamos en W.
	              movwf	  TempL			 ;Cargamos el resultado bajo en variable temporal.-
	              btfsc	  STATUS,C		 ;y si hay carry incrementamos registro alto del resultado temporal.-
	              incf	  TempH			 ;(Esto se da porque el resultado es mayor a 255)
	
	              btfsc	  TempH,0		 ;Es mayor a 255?
	              goto	  $+4			 ;(Solo lo hacemos así porque LargoMsj debe ser menor o igual a 255)
	              movfw	  TempL			 ;No es mayor a 255, verficamos Byte bajo.-
	              subwf	  LargoMsj,0		
	              btfss	  STATUS,C
	              goto	  DividoEnDosPartes	 ;Es mayor...


;**************************************************************************************************************************
; Es menor...
; Hay que de la posicion actual sumar el largo de leds y despues comenzar a actualizar el cartel.
;**************************************************************************************************************************


	              movfw	  TempL			 ;Cargamos posicion de donde comenzar a cargar mensaje.-
	              movwf	  PosicionEnviar

CicloEnvio	      call	  EnviaBit		 ;Se envia bits actual del byte seleccionado.-
	              decf	  PosicionEnviar,1	 ;Se decrementa direccionador del byte a enviar.-
	              movfw	  PosicionInicial	 ;Es igual a la posicion inicial de donde se comienza a visualizar mensaje??
	              subwf	  PosicionEnviar,0	
	              btfss	  STATUS,Z			
	              goto	  CicloEnvio		 ;No, seguimos con el siguiente byte.
	              goto	  Efectivizamos		 ;Ahora se habilitará Strobe para efectivizar los cambios y activaremos la Fila correspondiente.


;**************************************************************************************************************************
; Es mayor...
;(LargoMsj - PosicionInicial):
;**************************************************************************************************************************


DividoEnDosPartes     movfw	  PosicionInicial
	              subwf	  LargoMsj,0
	              movwf	  TempL			 ;Guardamos resultado de la resta en registro temporal.

;[LargoCartel - (LargoMsj - PosicionInicial)]:

	              movfw	  TempL
	              subwf	  LargoCartel,0
	              movwf	  PosicionEnviar	 ;Guardamos desde donde comenzamos a enviar disminuyendo hasta 1...

CicloEnvio_1	      call	  EnviaBit		 ;Se envia bits actual del byte seleccionado.
	              decf	  PosicionEnviar,1	 ;Se decrementa direccionador del byte a enviar.
	              movlw	  0x00
	              subwf	  PosicionEnviar,0	 ;Es igual a 0x00??
	              btfss	  STATUS,Z
	              goto	  CicloEnvio_1

; Enviamos Segunda parte.	

	              movfw	  LargoMsj
	              movwf	  PosicionEnviar

CicloEnvio_2	      call	  EnviaBit		 ;Se envia bits actual del byte seleccionado.-
	              decf	  PosicionEnviar,1	 ;Se decrementa direccionador del byte a enviar.-
	              movfw	  PosicionInicial	 ;Es igual a la posicion inicial de donde se comienza a visualizar mensaje??
	              subwf	  PosicionEnviar,0
	              btfss	  STATUS,Z
	              goto	  CicloEnvio_2		 ;No, seguimos con el siguiente byte.-
	              goto	  Efectivizamos		 ;Ahora se habilitará Strobe para efectivizar los cambios y activaremos la Fila correspondiente.


;*************************************************************************************************************************
;                 Rutina envia bit
;**************************************************************************************************************************



EnviaBit              movlw	  0xFF			 ; Desactivamos todas las filas.
	              movwf	  PORTB			
                      decf	  PosicionEnviar,0	 ;Cargamos posicion en W del byte a visualizar.
	              call	  Mensaje		 ;Cargamos en W el byte actual a refrescar.
	              andwf	  FilaActual,0		 ;Hacemos ByteActual (AND) FilaActual para determinar el bit a enviar.
	              subwf	  FilaActual,0		 ;[ByteActual(AND)FilaActual] - FilaActual, si esto es cero el bit a enviar es 1, sino 0.
	              bcf	  PORTA,BData		 ;Primero cargamos un 0.
	              btfsc	  STATUS,Z		 ;La operacion anterior es 0?
	              bsf	  PORTA,BData		 ;Si, cargamos un 1 en el bit
	              bsf	  PORTA,BClock		 ;Generamos clock.
	              nop				 ;demora
	              bcf	  PORTA,BClock		 ;..
	              return


;*************************************************************************************************************************
;                 Rutina efectivizar
;**************************************************************************************************************************


Efectivizamos         movlw	  0xFF			; Desactivamos todas las filas.
	              movwf	  PORTB			
	              comf	  FilaActual,0		; Complementamos FilaActual para activar Fila actual a refrescar.-
	              movwf	  PORTB
	              bcf	  STATUS,C		
	              rlf	  FilaActual,1		; Rotamos Fila actual para proxima actualizacion.-
	              return
	             

                      end


