Autor Tema: Problema libro "Microcontrolador PIC16F84. Desarrollo de proyectos" de Palacios  (Leído 6679 veces)

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

Desconectado jerarca

  • PIC10
  • *
  • Mensajes: 5
Que tal. Me compré la tercera edición del libro "Microcontrolador PIC16F84. Desarrollo de proyectos" del autor Palacios y Cuando hago la simulación con el proteus de ciertos programas, no funcionan correctamente.
Los programas que no me funcionan del CD son Int_Cuadradas_01, Int_Cuadradas_03 y Int_Cuadradas_04. Les pregunté a los autores y nunca me respondieron.
Acá les dejo el primero con las bilbiotecas abajo, que es el que más me interesa, a ver si me pueden ayudar.

Saludos amigos!

Facundo


;******************************** Int_Cuadradas_01.asm **********************************
;
;   ===================================================================
;     Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;     E. Palacios, F. Remiro y L. López.      www.pic16f84a.com
;      Editorial Ra-Ma.  www.ra-ma.es
;   ===================================================================
;
; Por la línea 3 del puerto B se genera una onda cuadrada. La frecuencia de la onda cuadrada cambia
; mediante activación del pulsador conectado al pin 7 del puerto B, de la siguiente forma:
;
;    PULSACIÓN   FRECUENCIA           SEMIPERIODO
;    ---------   ----------      -----------------------
;    (Inicial)     10 kHz         50 µs. =   1 x 50 µs
;    Primera           5 kHz        100 µs. =   2 x 50 µs
;    Segunda           2 kHz        250 µs. =   5 x 50 µs
;    Tercera           1 kHz        500 µs. =  10 x 50 µs
;    Cuarta       500  Hz       1000 µs. =  20 x 50 µs
;    Quinta       200  Hz       2500 µs. =  50 x 50 µs
;    Sexta       100  Hz       5000 µs. = 100 x 50 µs
;    Septima         50  Hz      10000 µs. = 200 x 50 µs
;
; Al conectarlo por primera vez se genera una frecuencia de 10 kHz, al activar el
; pulsador cambia a 5 kHz, al actuar una segunda vez cambia a 2 kHz, y así sucesivamente.
;
; El módulo LCD visualizará la frecuencia generada. A la línea de salida se puede conectar
; un altavoz que producirá un pitido.

; ZONA DE DATOS **********************************************************************

   LIST      P=16F84A
   INCLUDE      <P16F84A.INC>
   __CONFIG   _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC

   CBLOCK   0x0C
   ApuntadorFrecuencia
   Semiperiodo
   ENDC

TMR0_Carga50us      EQU   d'256'-d'42'; El semiperiodo patrón va a ser de 50 µs.
NUM_FRECUENCIA      EQU   d'8'      ; Ocho posibles frecuencias: 10 kHz, 5 kHz, 2 kHz,
                           ; 1 kHz, 500 Hz, 200 Hz, 100 Hz y 50 Hz.
#DEFINE  Salida   PORTB,3
#DEFINE  Pulsador PORTB,7

; ZONA DE CÓDIGOS ********************************************************************

   ORG    0
   goto   Inicio
   ORG   4
   goto   ServicioInterrupcion

; Subrutina "CargaContador" -------------------------------------------------------------

CargaContador
   addwf   PCL,F
   retlw   .1      ; Semiperiodo   1 x 50 =    50 µs, frecuencia =  10 kHz.
   retlw   .2      ; Semiperiodo   2 x 50 =   100 µs, frecuencia =   5 kHz.
   retlw   .5      ; Semiperiodo   5 x 50 =   250 µs, frecuencia =   2 kHz.
   retlw   .10      ; Semiperiodo  10 x 50 =   500 µs, frecuencia =   1 kHz.
   retlw   .20      ; Semiperiodo  20 x 50 =  1000 µs, frecuencia = 500  Hz.
   retlw   .50      ; Semiperiodo  50 x 50 =  2500 µs, frecuencia = 200  Hz.
   retlw   .100   ; Semiperiodo 100 x 50 =  5000 µs, frecuencia = 100  Hz.
   retlw   .200   ; Semiperiodo 200 x 50 = 10000 µs, frecuencia =  50  Hz.

; Subrutina "CargaMensaje" -------------------------------------------------------------

CargaMensaje
   addwf   PCL,F
   retlw   Mensaje10kHz
   retlw   Mensaje5kHz
   retlw   Mensaje2kHz
   retlw   Mensaje1kHz
   retlw   Mensaje500Hz
   retlw   Mensaje200Hz
   retlw   Mensaje100Hz
   retlw   Mensaje50Hz

; Subrutina "Mensajes" ------------------------------------------------------------------
;
Mensajes
   addwf   PCL,F
MensajeFrecuencia
   DT "Frec.: ", 0x00
Mensaje10kHz
   DT "10 kHz. ", 0x00
Mensaje5kHz
   DT "5 kHz.  ", 0x00
Mensaje2kHz
   DT "2 kHz.  ", 0x00
Mensaje1kHz
   DT "1 kHz.  ", 0x00
Mensaje500Hz
   DT "500 Hz. ", 0x00
Mensaje200Hz
   DT "200 Hz. ", 0x00
Mensaje100Hz
   DT "100 Hz. ", 0x00
Mensaje50Hz
   DT "50 Hz.  ", 0x00

; Programa Principal ------------------------------------------------------------------

Inicio
   call   LCD_Inicializa
   bsf      STATUS,RP0
   bcf      Salida
   bsf      Pulsador
   movlw   b'00001000'            ; TMR0 sin prescaler.
   movwf   OPTION_REG
   bcf      STATUS,RP0
   call   EstadoInicial         ; Visualiza la frecuencia inicial.
   movlw   TMR0_Carga50us         ; Carga el TMR0.
   movwf   TMR0   
   movlw   b'10101000'
   movwf   INTCON               ; Activa interrupciones del TMR0, RBI y general.
Principal
   goto   Principal

; Subrutina "ServicioInterrupcion" ------------------------------------------------------
;
; Detecta qué ha producido la interrupción y ejecuta la subrutina correspondiente.

ServicioInterrupcion
   btfsc   INTCON,T0IF            ; ¿Interrupción por desbordamiento del TMR0?.
   call   Timer0_Interrupcion
   btfsc   INTCON,RBIF            ; ¿Interrupción por cambio en el Puerto B?.
   call   Pulsador_Interrupcion
   bcf      INTCON,T0IF            ; Repone flag del TMR0.
   bcf      INTCON,RBIF            ; Repone flag del RBI.
   retfie

; Subrutina "Pulsador_Interrupcion" -----------------------------------------------------
;
; Subrutina de atención a la interrupción por cambio en la línea RB7 donde se ha
; conectado un pulsador.
; Incrementa el registro (ApuntadorFrecuencia) desde b'00000000' (que corresponde a una
; frecuencia de 10 kHz) hasta b'00000111' (que corresponde a una frecuencia de 50 Hz),
; según la tabla especificada en el enunciado del ejercicio.
;
Pulsador_Interrupcion
   call   Retardo_20ms
   btfsc   Pulsador
   goto   Fin_PulsadorInterrupcion
   incf   ApuntadorFrecuencia,F   ; Apunta a la siguiente frecuencia.
   movlw   NUM_FRECUENCIA         ; Va a comprobar si ha llegado al máximo.
   subwf   ApuntadorFrecuencia,W   ; (W)=(ApuntadorFrecuencia)-NUM_FRECUENCIA
   btfsc   STATUS,C            ; ¿Ha llegado a su máximo?
EstadoInicial
   clrf   ApuntadorFrecuencia      ; Si llega al máximo lo inicializa.
   movf   ApuntadorFrecuencia,W   ; Va a cargar el valor del factor de
   call   CargaContador         ; multiplicación del semiperiodo según la
   movwf   Semiperiodo            ; tabla.
   movwf   Timer0_ContadorA
   call   LCD_Linea1            ; Visualiza la frecuencia seleccionada.
   movlw   MensajeFrecuencia
   call   LCD_Mensaje
   movf   ApuntadorFrecuencia,W
   call   CargaMensaje
   call   LCD_Mensaje
EsperaDejePulsar
   btfss   Pulsador
   goto   EsperaDejePulsar
Fin_PulsadorInterrupcion
   return

; Subrutina "Timer0_Interrupcion" -------------------------------------------------------
;
   CBLOCK
   Timer0_ContadorA
   ENDC

Timer0_Interrupcion
   movlw   TMR0_Carga50us
   movwf   TMR0               ; Recarga el TMR0.
   decfsz   Timer0_ContadorA,F      ; Decrementa el contador.
   goto   Fin_Timer0_Interrupcion
   movf   Semiperiodo,W         ; Repone el contador nuevamente.
   movwf   Timer0_ContadorA
   btfsc   Salida               ; Testea el último estado de la salida.
   goto   EstabaAlto
EstabaBajo
   bsf      Salida               ; Estaba bajo y lo pasa a alto.
   goto   Fin_Timer0_Interrupcion
EstabaAlto
   bcf      Salida               ; Estaba alto y lo pasa a bajo.
Fin_Timer0_Interrupcion
   return

   INCLUDE  <LCD_MENS.INC>
   INCLUDE  <LCD_4BIT.INC>
   INCLUDE  <RETARDOS.INC>
   END

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

;**************************** Librería "LCD_MENS.INC" ********************************
;
;   ===================================================================
;     Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;     E. Palacios, F. Remiro y L. López.      www.pic16f84a.com
;      Editorial Ra-Ma.  www.ra-ma.es
;   ===================================================================
;
; Librería de subrutinas para el manejo de mensajes a visualizar en un visualizador LCD.

   CBLOCK
   LCD_ApuntaCaracter            ; Indica la posición del carácter a visualizar
                           ; respecto del comienzo de todos los mensajes,
                           ; (posición de la etiqueta "Mensajes").
   LCD_ValorCaracter            ; Código ASCII del carácter a
   ENDC                     ; visualizar.

; Los mensajes tienen que estar situados dentro de las 256 primeras posiciones de la
; memoria de programa, es decir, no pueden superar la dirección 0FFh.

; Subrutina "LCD_Mensaje" ---------------------------------------------------------------
;
; Visualiza por pantalla el mensaje apuntado por el registro W.
;
; Los mensajes deben localizarse dentro de una zona encabezada por la etiqueta "Mensajes" y que
; tenga la siguiente estructura:
;
; Mensajes                     ; ¡Etiqueta obligatoria!
;   addwf   PCL,F
; Mensaje0                     ; Posición inicial del mensaje.
;   DT ".. ..", 0x00            ; Mensaje terminado en 0x00.
; Mensaje1
;   ...   
;   ...
; FinMensajes
;
; La llamada a esta subrutina se realizará siguiendo este ejemplo:
;
;   movlw   Mensaje0            ; Carga la posición del mensaje.
;   call   LCD_Mensaje            ; Visualiza el mensaje.
;
LCD_Mensaje
   movwf   LCD_ApuntaCaracter      ; Posición del primer carácter del mensaje.
   movlw   Mensajes            ; Halla la posición relativa del primer carácter
   subwf   LCD_ApuntaCaracter,F   ; del mensaje respecto de etiqueta "Mensajes".
   decf   LCD_ApuntaCaracter,F   ; Compensa la posición que ocupa "addwf PCL,F".
LCD_VisualizaOtroCaracter
   movf   LCD_ApuntaCaracter,W
   call   Mensajes            ; Obtiene el código ASCII del carácter apuntado.
   movwf   LCD_ValorCaracter      ; Guarda el valor de carácter.
   movf   LCD_ValorCaracter,F      ; Lo único que hace es posicionar flag Z. En caso
   btfsc   STATUS,Z            ; que sea "0x00", que es código indicador final   
   goto   LCD_FinMensaje         ; de mensaje, sale fuera.
LCD_NoUltimoCaracter
   call   LCD_Caracter         ; Visualiza el carácter ASCII leído.
   incf   LCD_ApuntaCaracter,F   ; Apunta a la posición del siguiente carácter
   goto   LCD_VisualizaOtroCaracter   ; dentro del mensaje.
LCD_FinMensaje
   return                     ; Vuelve al programa principal.

; Subrutina "LCD_MensajeMovimiento" -----------------------------------------------------
;
; Visualiza un mensaje de mayor longitud que los 16 caracteres que pueden representarse
; en una línea, por tanto se desplaza a través de la pantalla.
;
; En el mensaje debe dejarse 16 espacios en blanco, al principio y al final para
; conseguir que el desplazamiento del mensaje sea lo más legible posible.
;
   CBLOCK   
   LCD_CursorPosicion            ; Contabiliza la posición del cursor dentro de la
   ENDC                     ; pantalla LCD

LCD_MensajeMovimiento
   movwf   LCD_ApuntaCaracter      ; Posición del primer carácter del mensaje.
   movlw   Mensajes            ; Halla la posición relativa del primer carácter
   subwf   LCD_ApuntaCaracter,F   ; del mensaje respecto de la etiqueta "Mensajes".
   decf   LCD_ApuntaCaracter,F   ; Compensa la posición que ocupa "addwf PCL,F".
LCD_PrimeraPosicion
   clrf   LCD_CursorPosicion      ; El cursor en la posición 0 de la línea.
   call   LCD_Borra            ; Se sitúa en la primera posición de la línea 1 y
LCD_VisualizaCaracter            ; borra la pantalla.
   movlw   LCD_CaracteresPorLinea   ; ¿Ha llegado a final de línea?
   subwf   LCD_CursorPosicion,W
   btfss   STATUS,Z
   goto   LCD_NoEsFinalLinea
LCD_EsFinalLinea
   call   Retardo_200ms         ; Lo mantiene visualizado durante este tiempo.
   call   Retardo_200ms
   movlw   LCD_CaracteresPorLinea-1; Apunta a la posición del segundo carácter visualizado
   subwf   LCD_ApuntaCaracter,F   ; en pantalla, que será el primero en la siguiente
   goto   LCD_PrimeraPosicion       ; visualización de línea, para producir el efecto
LCD_NoEsFinalLinea               ; de desplazamiento hacia la izquierda.
   movf   LCD_ApuntaCaracter,W
   call   Mensajes            ; Obtiene el ASCII del carácter apuntado.
   movwf   LCD_ValorCaracter      ; Guarda el valor de carácter.
   movf   LCD_ValorCaracter,F      ; Lo único que hace es posicionar flag Z. En caso
   btfsc   STATUS,Z            ; que sea "0x00", que es código indicador final   
   goto   LCD_FinMovimiento      ; de mensaje, sale fuera.
LCD_NoUltimoCaracter2
   call   LCD_Caracter         ; Visualiza el carácter ASCII leído.
   incf   LCD_CursorPosicion,F   ; Contabiliza el incremento de posición del
                           ; cursor en la pantalla.
   incf   LCD_ApuntaCaracter,F   ; Apunta a la siguiente posición por visualizar.
   goto   LCD_VisualizaCaracter   ; Vuelve a visualizar el siguiente carácter
LCD_FinMovimiento               ; de la línea.
   return                     ; Vuelve al programa principal.

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

;**************************** Librería "LCD_4BIT.INC" ***********************************
;
;   ===================================================================
;     Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;     E. Palacios, F. Remiro y L. López.      www.pic16f84a.com
;      Editorial Ra-Ma.  www.ra-ma.es
;   ===================================================================
;
; Estas subrutinas permiten realizar las tareas básicas de control de un módulo LCD de 2
; líneas por 16 caracteres, compatible con el modelo LM016L.
;
; El visualizador LCD está conectado al Puerto B del PIC mediante un bus de 4 bits. Las
; conexiones son:
; -   Las 4 líneas superiores del módulo LCD, pines <DB7:DB4>  se conectan a las 4
;   líneas superiores del Puerto B del PIC, pines <RB7:RB4>.
; -   Pin RS del LCD a la línea RA0 del PIC.
; -   Pin R/W del LCD a la línea RA1 del PIC, o a masa.
; -   Pin Enable del LCD a la línea RA2 del PIC.
;
; Se utilizan llamadas a subrutinas de retardo de tiempo localizadas en la librería
; RETARDOS.INC.
;
; ZONA DE DATOS *********************************************************************

   CBLOCK
   LCD_Dato
   LCD_GuardaDato
   LCD_GuardaTRISB
   LCD_Auxiliar1
   LCD_Auxiliar2
   ENDC

LCD_CaracteresPorLinea   EQU   .16         ; Número de caracteres por línea de la pantalla.

#DEFINE  LCD_PinRS   PORTA,0
#DEFINE  LCD_PinRW   PORTA,1
#DEFINE  LCD_PinEnable   PORTA,2
#DEFINE  LCD_BusDatos   PORTB

; Subrutina "LCD_Inicializa" ------------------------------------------------------------
;
; Inicialización del módulo LCD: Configura funciones del LCD, produce reset por software,
; borra memoria y enciende pantalla. El fabricante especifica que para garantizar la
; configuración inicial hay que hacerla como sigue:
;
LCD_Inicializa
   bsf      STATUS,RP0            ; Configura las líneas conectadas al pines RS,
   bcf      LCD_PinRS            ; R/W y E.
   bcf      LCD_PinEnable
   bcf      LCD_PinRW
   bcf      STATUS,RP0
   bcf      LCD_PinRW            ; En caso de que esté conectado le indica
                           ; que se va a escribir en el LCD.
   bcf      LCD_PinEnable         ; Impide funcionamiento del LCD poniendo E=0.
   bcf    LCD_PinRS            ; Activa el Modo Comando poniendo RS=0.
   call   Retardo_20ms
   movlw   b'00110000'   
   call   LCD_EscribeLCD         ; Escribe el dato en el LCD.
   call   Retardo_5ms   
   movlw   b'00110000'   
   call   LCD_EscribeLCD
   call   Retardo_200micros
   movlw   b'00110000'   
   call   LCD_EscribeLCD
   call   Retardo_20micros      ; Este retardo es necesario para simular en PROTEUS.
   movlw   b'00100000'            ; Interface de 4 bits.
   call   LCD_EscribeLCD
   call   Retardo_20micros      ; Este retardo es necesario para simular en PROTEUS.
   
; Ahora configura el resto de los parámetros:

   call   LCD_2Lineas4Bits5x7      ; LCD de 2 líneas y caracteres de 5x7 puntos.
   call   LCD_Borra            ; Pantalla encendida y limpia. Cursor al principio
   call   LCD_CursorOFF         ; de la línea 1. Cursor apagado.
   call   LCD_CursorIncr         ; Cursor en modo incrementar.
   return

; Subrutina "LCD_EscribeLCD" -----------------------------------------------------------
;
; Envía el dato del registro de trabajo W al bus de dato y produce un pequeño pulso en el pin
; Enable del LCD. Para no alterar el contenido de las líneas de la parte baja del Puerto B que
; no son utilizadas para el LCD (pines RB3:RB0), primero se lee estas líneas y después se
; vuelve a enviar este dato sin cambiarlo.

LCD_EscribeLCD
   andlw   b'11110000'            ; Se queda con el nibble alto del dato que es el
   movwf   LCD_Dato            ; que hay que enviar y lo guarda.
   movf   LCD_BusDatos,W         ; Lee la información actual de la parte baja
   andlw   b'00001111'            ; del Puerto B, que no se debe alterar.
   iorwf   LCD_Dato,F            ; Enviará la parte alta del dato de entrada
                           ; y en la parte baja lo que había antes.
   bsf      STATUS,RP0            ; Acceso al Banco 1.
   movf   TRISB,W               ; Guarda la configuración que tenía antes TRISB.
   movwf   LCD_GuardaTRISB
   movlw   b'00001111'            ; Las 4 líneas inferiores del Puerto B se dejan
   andwf   PORTB,F               ; como estaban y las 4 superiores como salida.
   bcf      STATUS,RP0            ; Acceso al Banco 0.
;
   movf   LCD_Dato,W            ; Recupera el dato a enviar.
   movwf   LCD_BusDatos         ; Envía el dato al módulo LCD.
   bsf      LCD_PinEnable         ; Permite funcionamiento del LCD mediante un pequeño
   bcf      LCD_PinEnable         ; pulso y termina impidiendo el funcionamiento del LCD.
   bsf      STATUS,RP0            ; Acceso al Banco 1. Restaura el antiguo valor en
   movf   LCD_GuardaTRISB,W      ; la configuración del Puerto B.
   movwf   TRISB
   bcf      STATUS,RP0            ; Acceso al Banco 0.
   return

; Subrutinas variadas para el control del módulo LCD -----------------------------------------
;
;Los comandos que pueden ser ejecutados son:
;
LCD_CursorIncr                  ; Cursor en modo incrementar.
   movlw   b'00000110'
   goto   LCD_EnviaComando
LCD_Linea1                     ; Cursor al principio de la Línea 1.
   movlw   b'10000000'            ; Dirección 00h de la DDRAM
   goto   LCD_EnviaComando
LCD_Linea2                     ; Cursor al principio de la Línea 2.
   movlw   b'11000000'            ; Dirección 40h de la DDRAM
   goto   LCD_EnviaComando
LCD_Linea3                     ; Cursor al principio de la Línea 3
   movlw   b'10010100'            ; Dirección 14h de la DDRAM
   goto   LCD_EnviaComando
LCD_Linea4                     ; Cursor al principio de la Línea 4
   movlw   b'11010100'            ; Dirección 54h de la DDRAM
   goto   LCD_EnviaComando
LCD_PosicionLinea1               ; Cursor a posición de la Línea 1, a partir de la
   iorlw   b'10000000'            ; dirección 00h de la DDRAM más el valor del
   goto   LCD_EnviaComando      ; registro W.
LCD_PosicionLinea2               ; Cursor a posición de la Línea 2, a partir de la
   iorlw   b'11000000'            ; dirección 40h de la DDRAM más el valor del
   goto   LCD_EnviaComando      ; registro W.
LCD_OFF                        ; Pantalla apagada.
   movlw   b'00001000'
   goto   LCD_EnviaComando
LCD_CursorON                  ; Pantalla encendida y cursor encendido.
   movlw   b'00001110'
   goto   LCD_EnviaComando
LCD_CursorOFF                  ; Pantalla encendida y cursor apagado.
   movlw   b'00001100'
   goto   LCD_EnviaComando
LCD_Borra                     ; Borra toda la pantalla, memoria DDRAM y pone el
   movlw   b'00000001'            ; cursor a principio de la línea 1.
   goto   LCD_EnviaComando
LCD_2Lineas4Bits5x7               ; Define la pantalla de 2 líneas, con caracteres
   movlw   b'00101000'            ; de 5x7 puntos y conexión al PIC mediante bus de
;   goto   LCD_EnviaComando      ; 4 bits.

; Subrutinas "LCD_EnviaComando" y "LCD_Caracter" ------------------------------------
;
; "LCD_EnviaComando". Escribe un comando en el registro del módulo LCD. La palabra de
; comando ha sido entregada a través del registro W.  Trabaja en Modo Comando.
; "LCD_Caracter". Escribe en la memoria DDRAM del LCD el carácter ASCII introducido a
; a través del registro W. Trabaja en Modo Dato.
;
LCD_EnviaComando
   bcf      LCD_PinRS            ; Activa el Modo Comando, poniendo RS=0.
   goto   LCD_Envia
LCD_Caracter
   bsf      LCD_PinRS            ; Activa el "Modo Dato", poniendo RS=1.
   call   LCD_CodigoCGROM         ; Obtiene el código para correcta visualización.
LCD_Envia
   movwf   LCD_GuardaDato         ; Guarda el dato a enviar.
   call   LCD_EscribeLCD         ; Primero envía el nibble alto.
   swapf   LCD_GuardaDato,W      ; Ahora envía el nibble bajo. Para ello pasa el
                           ; nibble bajo del dato a enviar a parte alta del byte.
   call   LCD_EscribeLCD         ; Se envía al visualizador LCD.
   btfss   LCD_PinRS            ; Debe garantizar una correcta escritura manteniendo
   call   Retardo_2ms            ; 2 ms en modo comando y 50 µs en modo cáracter.
   call   Retardo_50micros
   return   

; Subrutina "LCD_CodigoCGROM" -----------------------------------------------------------
;
; A partir del carácter ASCII número 127 los códigos de los caracteres definidos en la
; tabla CGROM del LM016L no coinciden con los códigos ASCII. Así por ejemplo, el código
; ASCII de la "Ñ" en la tabla CGRAM del LM016L es EEh.
;
; Esta subrutina convierte los códigos ASCII de la "Ñ", "º" y otros, a códigos CGROM para que
; que puedan ser visualizado en el módulo LM016L.
;
; Entrada:   En (W) el código ASCII del carácter que se desea visualizar.
; Salida:   En (W) el código definido en la tabla CGROM.

LCD_CodigoCGROM
   movwf   LCD_Dato            ; Guarda el valor del carácter y comprueba si es
LCD_EnheMinuscula               ; un carácter especial.
   sublw   'ñ'                ; ¿Es la "ñ"?
   btfss   STATUS,Z
   goto   LCD_EnheMayuscula      ; No es "ñ".
   movlw   b'11101110'            ; Código CGROM de la "ñ".
   movwf   LCD_Dato
   goto   LCD_FinCGROM
LCD_EnheMayuscula
   movf   LCD_Dato,W            ; Recupera el código ASCII de entrada.
   sublw   'Ñ'                ; ¿Es la "Ñ"?
   btfss   STATUS,Z
   goto   LCD_Grado            ; No es "Ñ".
   movlw   b'11101110'            ; Código CGROM de la "ñ". (No hay símbolo para
   movwf   LCD_Dato            ; la "Ñ" mayúscula en la CGROM).
   goto   LCD_FinCGROM   
LCD_Grado
   movf   LCD_Dato,W            ; Recupera el código ASCII de entrada.
   sublw   'º'                ; ¿Es el símbolo "º"?
   btfss   STATUS,Z
   goto   LCD_FinCGROM         ; No es "º".
   movlw   b'11011111'            ; Código CGROM del símbolo "º".
   movwf   LCD_Dato
LCD_FinCGROM
   movf   LCD_Dato,W            ; En (W) el código buscado.
   return

; Subrutina "LCD_DosEspaciosBlancos" y "LCD_LineaBlanco" --------------------------------
;
; Visualiza espacios en blanco.

LCD_LineaEnBlanco
   movlw   LCD_CaracteresPorLinea
   goto   LCD_EnviaBlancos
LCD_UnEspacioBlanco
   movlw   .1
   goto   LCD_EnviaBlancos
LCD_DosEspaciosBlancos
   movlw   .2
   goto   LCD_EnviaBlancos
LCD_TresEspaciosBlancos
   movlw   .3
LCD_EnviaBlancos
   movwf   LCD_Auxiliar1         ; (LCD_Auxiliar1) se utiliza como contador.
LCD_EnviaOtroBlanco   
   movlw   ' '                  ; Esto es un espacio en blanco.
   call   LCD_Caracter         ; Visualiza tanto espacios en blanco como se
   decfsz   LCD_Auxiliar1,F         ; haya cargado en (LCD_Auxiliar1).
   goto   LCD_EnviaOtroBlanco
   return

; Subrutinas "LCD_ByteCompleto" y "LCD_Byte" --------------------------------------------
;
; Subrutina "LCD_ByteCompleto", visualiza el byte que almacena el registro W en el
; lugar actual de la pantalla. Por ejemplo, si (W)=b'10101110' visualiza "AE".
;
; Subrutina "LCD_Byte" igual que la anterior, pero en caso de que el nibble alto sea cero
; visualiza en su lugar un espacio en blanco. Por ejemplo si (W)=b'10101110' visualiza "AE"
; y si (W)=b'00001110', visualiza " E" (un espacio blanco delante).
;
; Utilizan la subrutina "LCD_Nibble" que se analiza más adelante.
;
LCD_Byte
   movwf   LCD_Auxiliar2         ; Guarda el valor de entrada.
   andlw   b'11110000'            ; Analiza si el nibble alto es cero.
   btfss   STATUS,Z            ; Si es cero lo apaga.
   goto   LCD_VisualizaAlto      ; No es cero y lo visualiza.
   movlw   ' '                  ; Visualiza un espacio en blanco.
   call   LCD_Caracter
   goto   LCD_VisualizaBajo

LCD_ByteCompleto
   movwf   LCD_Auxiliar2         ; Guarda el valor de entrada.
LCD_VisualizaAlto
   swapf   LCD_Auxiliar2,W         ; Pone el nibble alto en la parte baja.
   call   LCD_Nibble            ; Lo visualiza.
LCD_VisualizaBajo
   movf   LCD_Auxiliar2,W         ; Repite el proceso con el nibble bajo.
;   call   LCD_Nibble            ; Lo visualiza.
;   return

; Subrutina "LCD_Nibble" ----------------------------------------------------------------
;
; Visualiza en el lugar actual de la pantalla, el valor hexadecimal que almacena en el nibble
; bajo del registro W. El nibble alto de W no es tenido en cuenta. Ejemplos:
; - Si (W)=b'01010110', se visualizará "6".
; - Si (W)=b'10101110', se visualizará "E".
;
LCD_Nibble
   andlw   b'00001111'            ; Se queda con la parte baja.
   movwf   LCD_Auxiliar1         ; Lo guarda.
   sublw   0x09               ; Comprueba si hay que representarlo con letra.
   btfss   STATUS,C   
   goto   LCD_EnviaByteLetra
   movf   LCD_Auxiliar1,W
   addlw   '0'                  ; El número se pasa a carácter ASCII sumándole
   goto    LCD_FinVisualizaDigito   ; el ASCII del cero y lo visualiza.
LCD_EnviaByteLetra
   movf   LCD_Auxiliar1,W
   addlw   'A'-0x0A            ; Sí, por tanto, se le suma el ASCII de la 'A'.
LCD_FinVisualizaDigito
   goto   LCD_Caracter         ; Y visualiza el carácter. Se hace con un "goto"
            
-----------------------

;**************************** Librería "RETARDOS.INC" *********************************
;
;   ===================================================================
;     Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;     E. Palacios, F. Remiro y L. López.      www.pic16f84a.com
;      Editorial Ra-Ma.  www.ra-ma.es
;   ===================================================================
;
; Librería con múltiples subrutinas de retardos, desde 4 microsegundos hasta 20 segundos.
; Además se pueden implementar otras subrutinas muy fácilmente.
;
; Se han calculado para un sistema microcontrolador con un PIC trabajando con un cristal
; de cuarzo a 4 MHz. Como cada ciclo máquina son 4 ciclos de reloj, resulta que cada
; ciclo máquina tarda 4 x 1/4MHz = 1 µs.
;
; En los comentarios, "cm" significa "ciclos máquina".
;
; ZONA DE DATOS *********************************************************************

   CBLOCK
   R_ContA                  ; Contadores para los retardos.
   R_ContB
   R_ContC
   ENDC
;
; RETARDOS de 4 hasta 10 microsegundos ---------------------------------------------------
;
; A continuación retardos pequeños teniendo en cuenta que para una frecuencia de 4 MHZ,
; la llamada a subrutina "call" tarda 2 ciclos máquina, el retorno de subrutina
; "return" toma otros 2 ciclos máquina y cada instrucción "nop" tarda 1 ciclo máquina.
;
Retardo_10micros            ; La llamada "call" aporta 2 ciclos máquina.
   nop                     ; Aporta 1 ciclo máquina.
   nop                     ; Aporta 1 ciclo máquina.
   nop                     ; Aporta 1 ciclo máquina.
   nop                     ; Aporta 1 ciclo máquina.
   nop                     ; Aporta 1 ciclo máquina.
Retardo_5micros               ; La llamada "call" aporta 2 ciclos máquina.
   nop                     ; Aporta 1 ciclo máquina.
Retardo_4micros               ; La llamada "call" aporta 2 ciclos máquina.
   return                  ; El salto del retorno aporta 2 ciclos máquina.
;
; RETARDOS de 20 hasta 500 microsegundos ------------------------------------------------
;
Retardo_500micros            ; La llamada "call" aporta 2 ciclos máquina.
   nop                     ; Aporta 1 ciclo máquina.
   movlw   d'164'            ; Aporta 1 ciclo máquina. Este es el valor de "K".
   goto   RetardoMicros      ; Aporta 2 ciclos máquina.
Retardo_200micros            ; La llamada "call" aporta 2 ciclos máquina.
   nop                     ; Aporta 1 ciclo máquina.
   movlw   d'64'            ; Aporta 1 ciclo máquina. Este es el valor de "K".
   goto   RetardoMicros      ; Aporta 2 ciclos máquina.
Retardo_100micros            ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'31'            ; Aporta 1 ciclo máquina. Este es el valor de "K".
   goto   RetardoMicros      ; Aporta 2 ciclos máquina.
Retardo_50micros            ; La llamada "call" aporta 2 ciclos máquina.
   nop                     ; Aporta 1 ciclo máquina.
   movlw   d'14'            ; Aporta 1 ciclo máquina. Este es el valor de "K".
   goto   RetardoMicros      ; Aporta 2 ciclos máquina.
Retardo_20micros            ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'5'            ; Aporta 1 ciclo máquina. Este es el valor de "K".
;
; El próximo bloque "RetardoMicros" tarda:
; 1 + (K-1) + 2 + (K-1)x2 + 2 = (2 + 3K) ciclos máquina.
;
RetardoMicros
   movwf   R_ContA            ; Aporta 1 ciclo máquina.
Rmicros_Bucle
   decfsz   R_ContA,F         ; (K-1)x1 cm (cuando no salta) + 2 cm (al saltar).
   goto   Rmicros_Bucle      ; Aporta (K-1)x2 ciclos máquina.
   return                  ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_500micros:   2 + 1 + 1 + 2 + (2 + 3K) = 500 cm = 500 µs. (para K=164 y 4 MHz).
; - Retardo_200micros:   2 + 1 + 1 + 2 + (2 + 3K) = 200 cm = 200 µs. (para K= 64 y 4 MHz).
; - Retardo_100micros:   2     + 1 + 2 + (2 + 3K) = 100 cm = 100 µs. (para K= 31 y 4 MHz).
; - Retardo_50micros :   2 + 1 + 1 + 2 + (2 + 3K) =  50 cm =  50 µs. (para K= 14 y 4 MHz).
; - Retardo_20micros :   2     + 1     + (2 + 3K) =  20 cm =  20 µs. (para K=  5 y 4 MHz).
;
; RETARDOS de 1 ms hasta 200 ms. --------------------------------------------------------
;
Retardo_200ms               ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'200'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_100ms               ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'100'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_50ms               ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'50'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_20ms               ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'20'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_10ms               ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'10'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_5ms                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'5'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_2ms                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'2'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
   goto   Retardos_ms         ; Aporta 2 ciclos máquina.
Retardo_1ms                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'1'            ; Aporta 1 ciclo máquina. Este es el valor de "M".
;
; El próximo bloque "Retardos_ms" tarda:
; 1 + M + M + KxM + (K-1)xM + Mx2 + (K-1)Mx2 + (M-1) + 2 + (M-1)x2 + 2 =
; = (2 + 4M + 4KM) ciclos máquina. Para K=249 y M=1 supone 1002 ciclos máquina
; que a 4 MHz son 1002 µs = 1 ms.
;
Retardos_ms
   movwf   R_ContB            ; Aporta 1 ciclo máquina.
R1ms_BucleExterno
   movlw   d'249'            ; Aporta Mx1 ciclos máquina. Este es el valor de "K".
   movwf   R_ContA            ; Aporta Mx1 ciclos máquina.
R1ms_BucleInterno
   nop                     ; Aporta KxMx1 ciclos máquina.
   decfsz   R_ContA,F         ; (K-1)xMx1 cm (cuando no salta) + Mx2 cm (al saltar).
   goto   R1ms_BucleInterno   ; Aporta (K-1)xMx2 ciclos máquina.
   decfsz   R_ContB,F         ; (M-1)x1 cm (cuando no salta) + 2 cm (al saltar).
   goto   R1ms_BucleExterno    ; Aporta (M-1)x2 ciclos máquina.
   return                  ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_200ms:   2 + 1 + 2 + (2 + 4M + 4KM) = 200007 cm = 200 ms. (M=200 y K=249).
; - Retardo_100ms:   2 + 1 + 2 + (2 + 4M + 4KM) = 100007 cm = 100 ms. (M=100 y K=249).
; - Retardo_50ms :   2 + 1 + 2 + (2 + 4M + 4KM) =  50007 cm =  50 ms. (M= 50 y K=249).
; - Retardo_20ms :   2 + 1 + 2 + (2 + 4M + 4KM) =  20007 cm =  20 ms. (M= 20 y K=249).
; - Retardo_10ms :   2 + 1 + 2 + (2 + 4M + 4KM) =  10007 cm =  10 ms. (M= 10 y K=249).
; - Retardo_5ms  :   2 + 1 + 2 + (2 + 4M + 4KM) =   5007 cm =   5 ms. (M=  5 y K=249).
; - Retardo_2ms  :   2 + 1 + 2 + (2 + 4M + 4KM) =   2007 cm =   2 ms. (M=  2 y K=249).
; - Retardo_1ms  :   2 + 1     + (2 + 4M + 4KM) =   1005 cm =   1 ms. (M=  1 y K=249).
;
; RETARDOS de 0.5 hasta 20 segundos ---------------------------------------------------
;
Retardo_20s                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'200'            ; Aporta 1 ciclo máquina. Este es el valor de "N".
   goto   Retardo_1Decima      ; Aporta 2 ciclos máquina.
Retardo_10s                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'100'            ; Aporta 1 ciclo máquina. Este es el valor de "N".
   goto   Retardo_1Decima      ; Aporta 2 ciclos máquina.
Retardo_5s                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'50'            ; Aporta 1 ciclo máquina. Este es el valor de "N".
   goto   Retardo_1Decima      ; Aporta 2 ciclos máquina.
Retardo_2s                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'20'            ; Aporta 1 ciclo máquina. Este es el valor de "N".
   goto   Retardo_1Decima      ; Aporta 2 ciclos máquina.
Retardo_1s                  ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'10'            ; Aporta 1 ciclo máquina. Este es el valor de "N".
   goto   Retardo_1Decima      ; Aporta 2 ciclos máquina.
Retardo_500ms               ; La llamada "call" aporta 2 ciclos máquina.
   movlw   d'5'            ; Aporta 1 ciclo máquina. Este es el valor de "N".
;
; El próximo bloque "Retardo_1Decima" tarda:
; 1 + N + N + MxN + MxN + KxMxN + (K-1)xMxN + MxNx2 + (K-1)xMxNx2 +
;   + (M-1)xN + Nx2 + (M-1)xNx2 + (N-1) + 2 + (N-1)x2 + 2 =
; = (2 + 4M + 4MN + 4KM) ciclos máquina. Para K=249, M=100 y N=1 supone 100011
; ciclos máquina que a 4 MHz son 100011 µs = 100 ms = 0,1 s = 1 décima de segundo.
;
Retardo_1Decima
   movwf   R_ContC            ; Aporta 1 ciclo máquina.
R1Decima_BucleExterno2
   movlw   d'100'            ; Aporta Nx1 ciclos máquina. Este es el valor de "M".
   movwf   R_ContB            ; Aporta Nx1 ciclos máquina.
R1Decima_BucleExterno
   movlw   d'249'            ; Aporta MxNx1 ciclos máquina. Este es el valor de "K".
   movwf   R_ContA            ; Aporta MxNx1 ciclos máquina.
R1Decima_BucleInterno         
   nop                     ; Aporta KxMxNx1 ciclos máquina.
   decfsz   R_ContA,F         ; (K-1)xMxNx1 cm (si no salta) + MxNx2 cm (al saltar).
   goto   R1Decima_BucleInterno   ; Aporta (K-1)xMxNx2 ciclos máquina.
   decfsz   R_ContB,F         ; (M-1)xNx1 cm (cuando no salta) + Nx2 cm (al saltar).
   goto   R1Decima_BucleExterno   ; Aporta (M-1)xNx2 ciclos máquina.
   decfsz   R_ContC,F         ; (N-1)x1 cm (cuando no salta) + 2 cm (al saltar).
   goto   R1Decima_BucleExterno2   ; Aporta (N-1)x2 ciclos máquina.
   return                  ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_20s:   2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 20000807 cm = 20 s.
;         (N=200, M=100 y K=249).
; - Retardo_10s:   2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 10000407 cm = 10 s.
;         (N=100, M=100 y K=249).
; - Retardo_5s:      2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  5000207 cm =  5 s.
;         (N= 50, M=100 y K=249).
; - Retardo_2s:      2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  2000087 cm =  2 s.
;         (N= 20, M=100 y K=249).
; - Retardo_1s:      2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  1000047 cm =  1 s.
;         (N= 10, M=100 y K=249).
; - Retardo_500ms:   2 + 1     + (2 + 4N + 4MN + 4KMN) =   500025 cm = 0,5 s.
;         (N=  5, M=100 y K=249).



Saludos,
Facundo.

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Recuerdo que a mi me dio un problema, pero este solo fuen en la libreria del LCD que no servía, para corregirlo hice lo siguiente

El código
Código: ASM
  1. btfss   LCD_PinRS            ; Debe garantizar una correcta escritura manteniendo
  2.    call   Retardo_2ms            ; 2 ms en modo comando y 50 µs en modo cáracter.
  3.    call   Retardo_50micros

Lo quité de la parte inferior de la rutina lcd_envia y lo puse en la rutina LCD_escribe
Código: ASM
  1. LCD_EscribeLCD
  2.    andlw   b'11110000'            ; Se queda con el nibble alto del dato que es el
  3.    movwf   LCD_Dato            ; que hay que enviar y lo guarda.
  4.    movf   LCD_BusDatos,W         ; Lee la información actual de la parte baja
  5.    andlw   b'00001111'            ; del Puerto B, que no se debe alterar.
  6.    iorwf   LCD_Dato,F            ; Enviará la parte alta del dato de entrada
  7.                            ; y en la parte baja lo que había antes.
  8.    bsf      STATUS,RP0            ; Acceso al Banco 1.
  9.    movf   TRISB,W               ; Guarda la configuración que tenía antes TRISB.
  10.    movwf   LCD_GuardaTRISB
  11.    movlw   b'00001111'            ; Las 4 líneas inferiores del Puerto B se dejan
  12.    andwf   PORTB,F               ; como estaban y las 4 superiores como salida.
  13.    bcf      STATUS,RP0            ; Acceso al Banco 0.
  14.  
  15.    btfss   LCD_PinRS            ; Debe garantizar una correcta escritura manteniendo
  16.    call   Retardo_2ms            ; 2 ms en modo comando y 50 µs en modo cáracter.
  17.    call   Retardo_50micros
  18.  
  19.    movf   LCD_Dato,W            ; Recupera el dato a enviar.
  20.    movwf   LCD_BusDatos         ; Envía el dato al módulo LCD.
  21.    bsf      LCD_PinEnable         ; Permite funcionamiento del LCD mediante un pequeño
  22.    bcf      LCD_PinEnable         ; pulso y termina impidiendo el funcionamiento del LCD.
  23.    bsf      STATUS,RP0            ; Acceso al Banco 1. Restaura el antiguo valor en
  24.    movf   LCD_GuardaTRISB,W      ; la configuración del Puerto B.
  25.    movwf   TRISB
  26.    bcf      STATUS,RP0            ; Acceso al Banco 0.
  27.    return

Despues de eso me comenzó a andar todo bien. No sé si el problema es tú codigo o era ese error.
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA