PIC18F452 interactuando con LCD HD44780 en ensamblaje

0

He intentado que una pantalla LCD Hitachi HD44780 funcione con mi PIC18F452 durante unos días sin suerte. He intentado mover las líneas de datos a diferentes puertos en el microchip, he intentado interactuar con unos cuantos arduinos que tengo y también cambiar la pantalla LCD por otra, pero todo lo que aparece en la pantalla es una sola línea de bloques de caracteres.

Estoy escribiendo el código PIC en el ensamblaje y lo tengo conectado en una placa de pruebas. He revisado por triple las conexiones para asegurarme de que estén en las patas correctas del microchip. PIC tiene un cristal de 10Mhz adjunto, que utiliza PORTE para los pines de control LCD, PORTB para datos LCD y PORTD para salidas LED.

Mi subrutina de inicio para la pantalla LCD es

LCD_init:
    delay_t 15, msec, delay_timer
;;  AN5/E0 = RW, AN6/E1 = R/S, AN7/E2 = E   
    movlw b'00000010'       ;; PORTA shared w/ PORTE, set pins to DIGITAL
    movwf ADCON1

    clrf TRISE          ;; Clear TRISE - PORTE as outputs
    clrf TRISB          ;; Set PORTD to outputs

;;  Function Set - 8-bit, 1 Line, 5x8 map
    movlw b'00110000'       ;; 00l DataLength NumbLine Font x x
    movwf PORTB
    movwf PORTD
    call LCD_send_command
    delay_t 5, msec, delay_timer
    call LCD_send_command
    delay_t 100, usec, delay_timer
    call LCD_send_command

;;  Display On/Off
    movlw b'00001110'       ;; 00001 DisplayOn Cursor Blink
    movwf PORTB
    movwf PORTD
    call LCD_send_command

;;  Entry Mode set    
    movlw b'00000110'       ;; 000001 Inc/Dec Shift
    movwf PORTB
    movwf PORTD
    call LCD_send_command

;;  Clear Screen
    movlw b'00000001'
    movwf PORTB
    movwf PORTD
    call LCD_send_command

;;  Data write test
    movlw b'01001001'
    movwf PORTB
    movwf PORTD
    call LCD_send_char

    return

Mi subrutina LCD_send_command:

LCD_send_command:
    call LCD_busy       ;; Wait for LCD to finish command
    clrf TRISB          ;; Set PORTD to outputs
    bcf LCD_rw          ;; Clear R/W
    bcf LCD_rs          ;; Clear R/S
    bsf LCD_enable      ;; Pulse E High...
    delay_t 1, msec, delay_timer
    bcf LCD_enable      ;; ... then low
    return

Mi subrutina LCD_send_char:

LCD_send_char:
    call LCD_busy
    clrf TRISB          ;; Set PORTB to outputs
    bcf LCD_rw          ;; Clear R/W
    bsf LCD_rs          ;; Set R/S
    bsf LCD_enable      ;; Pulse E High...
    delay_t 1, msec, delay_timer
    bcf LCD_enable      ;; ... then low
    return

Mi subrutina LCD_busy:

LCD_busy:
    setf TRISB          ;; Set PORTD to inputs
    bcf LCD_rs          ;; R/S = 0
    bsf LCD_rw          ;; R/W = 1
    btfss LCD_BUSY      ;; BUSY_FLAG, skip if set
    return
    bra LCD_busy

Por favor, avíseme si hay algo más que necesite de mí, cualquier ayuda me agradecería mucho. Gracias.

    
pregunta Matthew Law

1 respuesta

0

Parece que tiene "problemas" en su código.
Los comentarios se refieren a PORTD, pero su código utiliza PORTB.
La sincronización con los módulos HD44780 más antiguos puede ser complicada.

Puede encontrar útil esta implementación completa y probada:

;
;   Filename:       main.asm
;   Author:         dan1138
;   Target:         PIC18F452
;   Assembler:      MPASMWIN v5.22
;   Assembler mode: Absolute
;
;   Files required: p18f452.inc
;
;   Description:
;
;   Initialize an HD44780 based LCD module with a PIC18F452 using an external 10MHz crystal
;
;   Notes:
;   Tested using the DM163022-1 PICDEM2 Plus demo board.
;   I know it's obsolete and impossible to find but I got one so I used it.
;
    list P=18F452, r=dec, n=0, c=255
#include "p18f452.inc"

    config OSC = HS         ; Oscillator Selection bits (HS oscillator)
    config OSCS = OFF       ; Oscillator System Clock Switch Enable bit (Oscillator system clock switch option is disabled (main oscillator is source))
    config PWRT = OFF       ; Power-up Timer Enable bit (PWRT disabled)
    config BOR = OFF        ; Brown-out Reset Enable bit (Brown-out Reset disabled)
    config BORV = 27        ; Brown-out Reset Voltage bits (VBOR set to 2.7V)
    config WDT = OFF        ; Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
    config WDTPS = 128      ; Watchdog Timer Postscale Select bits (1:128)
    config CCP2MUX = ON     ; CCP2 Mux bit (CCP2 input/output is multiplexed with RC1)
    config STVR = ON        ; Stack Full/Underflow Reset Enable bit (Stack Full/Underflow will cause RESET)
    config LVP = OFF        ; Low Voltage ICSP Enable bit (Low Voltage ICSP disabled)
    config CP0 = OFF        ; Code Protection bit (Block 0 (000200-001FFFh) not code protected)
    config CP1 = OFF        ; Code Protection bit (Block 1 (002000-003FFFh) not code protected)
    config CP2 = OFF        ; Code Protection bit (Block 2 (004000-005FFFh) not code protected)
    config CP3 = OFF        ; Code Protection bit (Block 3 (006000-007FFFh) not code protected)
    config CPB = OFF        ; Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code protected)
    config CPD = OFF        ; Data EEPROM Code Protection bit (Data EEPROM not code protected)
    config WRT0 = OFF       ; Write Protection bit (Block 0 (000200-001FFFh) not write protected)
    config WRT1 = OFF       ; Write Protection bit (Block 1 (002000-003FFFh) not write protected)
    config WRT2 = OFF       ; Write Protection bit (Block 2 (004000-005FFFh) not write protected)
    config WRT3 = OFF       ; Write Protection bit (Block 3 (006000-007FFFh) not write protected)
    config WRTC = OFF       ; Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write protected)
    config WRTB = OFF       ; Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write protected)
    config WRTD = OFF       ; Data EEPROM Write Protection bit (Data EEPROM not write protected)
    config EBTR0 = OFF      ; Table Read Protection bit (Block 0 (000200-001FFFh) not protected from Table Reads executed in other blocks)
    config EBTR1 = OFF      ; Table Read Protection bit (Block 1 (002000-003FFFh) not protected from Table Reads executed in other blocks)
    config EBTR2 = OFF      ; Table Read Protection bit (Block 2 (004000-005FFFh) not protected from Table Reads executed in other blocks)
    config EBTR3 = OFF      ; Table Read Protection bit (Block 3 (006000-007FFFh) not protected from Table Reads executed in other blocks)
    config EBTRB = OFF      ; Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from Table Reads executed in other blocks)
;
;   /* Specify the System clock frequency in Hz */
#define FOSC 10000000

;   /* Specify the Peripheral clock frequency in Hz */
#define FCYC (FOSC/4)
;
; Define the LCD port pins
#define E_PIN_OUT     LATD,6
#define RW_PIN_OUT    LATD,5
#define RS_PIN_OUT    LATD,4
#define E_PIN_DIR     TRISD,6
#define RW_PIN_DIR    TRISD,5
#define RS_PIN_DIR    TRISD,4
#define LCD_DATA_BITS 0x0F
#define LCD_PORT_IN   PORTD
#define LCD_PORT_OUT  LATD
#define LCD_PORT_DIR  TRISD
#define LCD_FORMAT    (FOUR_BIT&LINES_5X7)

#define USE_FAST_CLOCK
; Start address of each line
#define LINE_ONE    0x00
#define LINE_TWO    0x40
#define LINE_THREE  0x14
#define LINE_FOUR   0x54
;
; Power On Reset entry point
    org 0
    goto    start
;
; Interrupt Service Routine entry point
    org 0x08
ISR_vevtor:
    retfie  1
;
; Main application start
start:
    movlw   0x07
    movwf   ADCON1              ; Make all pins digital I/O
    bcf     TRISD,7
    bsf     LATD,7              ; Turn on power to the DM163022-1 PICDEM2 Plus LCD module
    call    LCD_Init            ; Initial the HD44780 module
    movlw   HIGH(SignOn)
    movwf   LCD_pszRomStr+1
    movlw   LOW(SignOn)         ; Point to sign on message in ROM memory
    movlw   LINE_ONE
    call    LCD_SetDDRamAddr    ; Position to first line
    movwf   LCD_pszRomStr       ; Display sign on message
    call    LCD_Putrs
;
; Main application loop
main:
    goto    main
SignOn:
    DT      "PIC18F452",0

;
;
;/* Display ON/OFF Control defines */
#define DON         b'00001111'  ;/* Display on      */
#define DOFF        b'00001011'  ;/* Display off     */
#define CURSOR_ON   b'00001111'  ;/* Cursor on       */
#define CURSOR_OFF  b'00001101'  ;/* Cursor off      */
#define BLINK_ON    b'00001111'  ;/* Cursor Blink    */
#define BLINK_OFF   b'00001110'  ;/* Cursor No Blink */

;/* Cursor or Display Shift defines */
#define SHIFT_CUR_LEFT    b'00010011'  ;/* Cursor shifts to the left   */
#define SHIFT_CUR_RIGHT   b'00010111'  ;/* Cursor shifts to the right  */
#define SHIFT_DISP_LEFT   b'00011011'  ;/* Display shifts to the left  */
#define SHIFT_DISP_RIGHT  b'00011111'  ;/* Display shifts to the right */

;/* Function Set defines */
#define FOUR_BIT   b'00101111'  ;/* 4-bit Interface               */
#define EIGHT_BIT  b'00111111'  ;/* 8-bit Interface               */
#define LINE_5X7   b'00110011'  ;/* 5x7 characters, single line   */
#define LINE_5X10  b'00110111'  ;/* 5x10 characters               */
#define LINES_5X7  b'00111011'  ;/* 5x7 characters, multiple line */

;
; This code assumes an oscillator of 40MHz
;
; The the fastest oscillator a PIC18F452 can use is 40MHz.
;
; When USE_FAST_CLOCK is defined the delays are adjusted
; for a 40MHz oscillator.
;
#ifdef USE_FAST_CLOCK
#define DELAY_FOR_FAST_CLOCK  call Delay2us
#else
#define DELAY_FOR_FAST_CLOCK
#endif
;
; This RAM is used by the LCD interface routines.
;
; Warning:
;   This must be RAM in the access RAM memory space
;
  cblock 0x70
    LCD_byte:1          ; byte sent to or read from LCD
    LCD_BusyBit:1       ; Mask of where the BUSY bit is located
    LCD_pszRomStr:2     ; pointer to ASCIIZ string in ROM
  endc

; Delay2us() provide at least 2 microseconds of delay at 40MHz
Delay2us:
    bra    _n2


; LCD_Delay() provide at least 5 milliseconds of delay
LCD_Delay:
;
; If we are using a fast clock make
; the delays work for a 40MHz clock.
;
#ifdef USE_FAST_CLOCK
    call    LCD_D7
LCD_D7:
    call    LCD_D8
    call    LCD_D8
    call    LCD_D8
    call    LCD_D8
#endif

LCD_D8:
    bra     _n0
_n0:bra     _n1
_n1:movlw   d'249'
LCD_D9:
    call    _n2
    addlw   -1
    bnz     LCD_D9
_n2:bra     _n3
_n3:bra     _n4
_n4:bra     _n5
_n5:bra     _n6
_n6:bra     _n7
_n7:bra     _n8
_n8:bra     _n9
_n9:return

; LCD_DelayPOR() provides at least 15ms delay
LCD_DelayPOR:
    call    LCD_Delay
    call    LCD_Delay
    bra     LCD_Delay
;
;**********************************************************************
; Function: LCD_Busy
; Description:
;   This routine reads the busy status of the
;   Hitachi HD44780 LCD controller.
;
; Inputs:   none
;
; Outputs:  none
;
; Returns:  WREG = Not zero when status of LCD controller is busy
;
; Notes:
;  The busy bit is not reported in the same nibble
;  on all HD44780 "compatible" controllers.
;  If you have a Novatek 7605 type controller some
;  versions report these nibbles in reverse order.
;
;  This code has been tested with a Novatek 7605
;  and the real Hitachi HD44780.
;
LCD_Busy:
    movf    LCD_BusyBit,F   ; Check if busy bit avaliable.
    bz      LCD_DelayPOR    ; Use a 15ms delay when busy not available.

    bcf     RS_PIN_OUT
    bsf     RW_PIN_OUT

    bcf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK

    btfsc   LCD_BusyBit,7
    movf    LCD_PORT_IN,W      ; The standard LCD returns the BUSY flag first

    bcf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK

    btfsc   LCD_BusyBit,3
    movf    LCD_PORT_IN,W      ; A Non standard LCD returns the BUSY flag second

    bcf     E_PIN_OUT
    andlw   (LCD_DATA_BITS&(~LCD_DATA_BITS>>1))
    bnz     LCD_Busy
    return
;
; Send a byte to LCD using 4-bit mode
LCD_PutByte:
    movlw   ~LCD_DATA_BITS
    andwf   LCD_PORT_DIR,F      ; Make LCD port bits outputs
    andwf   LCD_PORT_OUT,F      ; Make LCD port bits zero

    bcf     RW_PIN_OUT
;
; send first 4-bits
    swapf   LCD_byte,W
    andlw   LCD_DATA_BITS
    iorwf   LCD_PORT_OUT,F
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bcf     E_PIN_OUT
;
; send second 4-bits
    xorwf   LCD_byte,W
    andlw   LCD_DATA_BITS
    xorwf   LCD_PORT_OUT,F
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bcf     E_PIN_OUT

; set data bits for input
    movlw   LCD_DATA_BITS
    iorwf   LCD_PORT_DIR,F
    movf    LCD_byte,W
    return
;
; Read a byte to LCD using 4-bit mode
LCD_GetByte:
    bsf     RW_PIN_OUT
;
; read first 4-bits
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    movf    LCD_PORT_IN,W
    bcf     E_PIN_OUT
    andlw   LCD_DATA_BITS
    movwf   LCD_byte
;
; read second 4-bits
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    movf    LCD_PORT_IN,W
    bcf     E_PIN_OUT
    andlw   LCD_DATA_BITS
    swapf   LCD_byte,F
    iorwf   LCD_byte,F
    movf    LCD_byte,W
    return
;
;**********************************************************************
; Function Name:  LCD_SetCGRamAddr
; Description:
;   This routine sets the character generator
;   address of the Hitachi HD44780 LCD
;   controller.
;
; Inputs:   W = character generator ram address
;
; Outputs:  none
;
; Returns:  nothing
;
LCD_SetCGRamAddr:
    iorlw   0x40            ; Write cmd and address to port
    movwf   LCD_byte        ; save byte going to LCD

    call    LCD_Busy

    bcf     RS_PIN_OUT
    bra     LCD_PutByte

;
;**********************************************************************
; Function:  LCD_SetDDRamAddr
; Description:
;   This routine sets the display data address
;   of the Hitachi HD44780 LCD controller.
;
; Inputs:   W = display data address
;
; Outputs:  none
;
; Returns:  nothing
;
LCD_SetDDRamAddr:
    iorlw   0x80            ; Write cmd and address to port
    movwf   LCD_byte        ; save byte going to LCD

    call    LCD_Busy

    bcf     RS_PIN_OUT
    bra     LCD_PutByte
;
;**********************************************************************
; Function Name:  LCD_WriteCmd
; Description:
;   This routine writes a command to the Hitachi
;   HD44780 LCD controller.
;
; Inputs:   W = command to send to LCD
;
; Outputs:  none
;
; Returns:  nothing
;
LCD_WriteCmd:
    movwf   LCD_byte        ; save byte going to LCD

    call    LCD_Busy

    bcf     RS_PIN_OUT
    bra     LCD_PutByte
;
;**********************************************************************
; Function: LCD_WriteData
; Description:
;   This routine writes a data byte to the
;   Hitachi HD44780 LCD controller. The data
;   is written to the character generator RAM or
;   the display data RAM depending on what the
;   previous SetxxRamAddr routine was called.
;
; Inputs:   W = data to send to LCD
;
; Outputs:  none
;
; Returns:  nothing
;
LCD_WriteData:
    movwf   LCD_byte        ; save byte going to LCD

    call    LCD_Busy

    bsf     RS_PIN_OUT
    call    LCD_PutByte
    bcf     RS_PIN_OUT
    return
;
;**********************************************************************
; Function: LCD_Init
; Description:
;   This routine configures the LCD. Based on
;   the Hitachi HD44780 LCD controller. The
;   routine will configure the I/O pins of the
;   microcontroller, setup the LCD for 4-bit
;   mode and clear the display.
;
; Inputs:   none
;
; Outputs:  none
;
; Returns:  nothing
;
LCD_Init:
    clrf    LCD_BusyBit
    movlw   ~LCD_DATA_BITS
    andwf   LCD_PORT_DIR,F  ; Make LCD data bus an output
    bcf     E_PIN_DIR       ; Make LCD data enable strobe an output
    bcf     RW_PIN_DIR      ; Make LCD Read/Write select an output
    bcf     RS_PIN_DIR      ; Make LCD Register select an output

    andwf   LCD_PORT_OUT,F  ; Drive all LCD pins low
    bcf     E_PIN_OUT
    bcf     RW_PIN_OUT
    bcf     RS_PIN_OUT

    call    LCD_DelayPOR    ; Wait for LCD to complete power on reset

    movlw   b'00110011'     ; force LCD into 8-bit mode
    iorwf   LCD_PORT_OUT,F
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bcf     E_PIN_OUT
    call    LCD_Delay       ; Required 5ms delay

    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bcf     E_PIN_OUT
    call    LCD_Delay       ; minimum 100us delay but use 5ms

    movlw   b'00100010'     ; set LCD into 4-bit mode
    xorwf   LCD_PORT_OUT,W
    andlw   LCD_DATA_BITS
    xorwf   LCD_PORT_OUT,F
    bsf     E_PIN_OUT
    DELAY_FOR_FAST_CLOCK
    bcf     E_PIN_OUT
    call    LCD_Delay

    movlw   LCD_DATA_BITS   ; Make LCD data pins inputs
    iorwf   LCD_PORT_DIR,F

    movlw   LCD_FORMAT
    andlw   0x0F            ; Allow only 4-bit mode for
    iorlw   0x20            ; HD44780 LCD controller.
    call    LCD_WriteCmd
;
; Find position of busy bit
; Required when using 4-bit mode.
;
    movlw   LINE_ONE+1
    call    LCD_SetDDRamAddr

    call    LCD_Busy

    call    LCD_GetByte
    xorlw   0x01
    btfsc   STATUS,Z        ; skpnz
    bsf     LCD_BusyBit,7
    xorlw   0x11
    btfsc   STATUS,Z        ; skpnz
    bsf     LCD_BusyBit,3
;
; Turn display off
;
    movlw   (DOFF & CURSOR_OFF & BLINK_OFF)
    call    LCD_WriteCmd
;
; Turn display on
;
    movlw   (DON & CURSOR_OFF & BLINK_OFF)
    call    LCD_WriteCmd
;
; Clear display
;
    movlw   (0x01)          ; Clear display
    call    LCD_WriteCmd
;
; Set cursor shift direction
;
    movlw   (SHIFT_CUR_LEFT)
    call    LCD_WriteCmd
;
; Initialize CGRAM
;
    movlw   0
    call    LCD_SetCGRamAddr
    movlw   LOW(CGRAM_Table)
    movwf   LCD_pszRomStr
    movlw   HIGH(CGRAM_Table)
    movwf   LCD_pszRomStr+1
    call    LCD_Putrs
;
; Put cursor on line one, left most position
;
    movlw   LINE_ONE
    call    LCD_SetDDRamAddr

    return
;
;**********************************************************************
; Function: LCD_Putrs
; Description:
;   This routine writes a string of bytes to the
;   Hitachi HD44780 LCD controller. The data
;   is written to the character generator RAM or
;   the display data RAM depending on what the
;   previous SetxxRamAddr routine was called.
;
; Inputs:   LCD_pszRomStr: pointer to string
;
; Outputs:  none
;
; Returns:  nothing
;
LCD_Putrs:
    call    TableLookUp
    iorlw   0
    btfsc   STATUS,Z        ; skpnz
    return
    call    LCD_WriteData
    movlw   Next_instruction-$
Next_instruction:
    addwf   LCD_pszRomStr,F
    btfsc   STATUS,C        ; skpnc
    incf    LCD_pszRomStr+1,F
    bra     LCD_Putrs

TableLookUp:
    clrf    PCLATU
    movf    LCD_pszRomStr+1,W
    movwf   PCLATH
    movf    LCD_pszRomStr,W
    movwf   PCL
;
; This table is used to write
; default characters to the
; Character Generator RAM of
; the LCD module.
;

CGRAM_Table:
    dt      B'10001000' ; CGRAM character 1
    dt      B'10000100'
    dt      B'10001110'
    dt      B'10000100'
    dt      B'10001000'
    dt      B'10000000'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10001110' ; CGRAM character 2
    dt      B'10010001'
    dt      B'10010000'
    dt      B'10010000'
    dt      B'10010001'
    dt      B'10001110'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10001110' ; CGRAM character 3
    dt      B'10010001'
    dt      B'10010000'
    dt      B'10010011'
    dt      B'10010001'
    dt      B'10001110'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10000000' ; CGRAM character 4
    dt      B'10001110'
    dt      B'10001010'
    dt      B'10001010'
    dt      B'10001110'
    dt      B'10000000'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10011110' ; CGRAM character 5
    dt      B'10010001'
    dt      B'10010001'
    dt      B'10011110'
    dt      B'10010010'
    dt      B'10010001'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10001110' ; CGRAM character 6
    dt      B'10010001'
    dt      B'10010001'
    dt      B'10011111'
    dt      B'10010001'
    dt      B'10010001'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10010001' ; CGRAM character 7
    dt      B'10011011'
    dt      B'10010101'
    dt      B'10010101'
    dt      B'10010001'
    dt      B'10010001'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'10000100' ; CGRAM character 8
    dt      B'10001000'
    dt      B'10011100'
    dt      B'10001000'
    dt      B'10000100'
    dt      B'10000000'
    dt      B'10000000'
    dt      B'10011111'

    dt      B'00000000' ; End of table marker

    end

Esto utiliza los datos de 4 bits y la interfaz de control de 3 bits para el módulo LCD.
Este código no utiliza los datos de 8 bits, por lo que tendrá que modificar la máscara para LCD_DATA_BITS para la posición correcta de los bits nybble.

    
respondido por el Dan1138

Lea otras preguntas en las etiquetas