简体   繁体   中英

What is wrong with my assembly code for displaying data onto LCD using 'check busy' flag

This is my first time working with LCDs and I am trying to get my code (see below) written for a PIC18f458 to display the ASCII characters 'N' and 'O' on a LCD; using a "check busy" flag instead of a delay, to work.

When I debug the code within the MPLAB X IDE, it seems to perform as expected. But, when I test it out using Proteus, it only displays the 'O' character (see image 1).

REGA    EQU 0x07            ; set aside registers for delay
REGB    EQU 0x08            ; subroutines
REGC    EQU 0x09
LCD_DATA EQU    PORTD           ; LCD data pins RD0-RD7
LCD_CTRL EQU    PORTC           ; LCD control pins
RS      EQU     RC0             ; RS pin of LCD
RW      EQU     RC1             ; R/W pin of LCD
EN      EQU     RC2             ; Enable pin of LCD 

        ORG     0000H           ; burn into ROM starting at 0
    
        CLRF    TRISD           ; make PORT D an output
        CLRF    TRISC           ; make PORTC an output
        BCF     LCD_CTRL,EN     ; enable idle low
        CALL    LDELAY          ; wait for initialisation
        MOVLW   0x38            ; init LCD 2 lines, 5x7 char    
        CALL    COMMAND         ; issue command
        CALL    LDELAY          ; initialisation hold
        MOVLW   0x0E            ; LCD on, cursor on
        CALL    COMMAND         ; issue command
        CALL    READY           ; is LCD ready?
        MOVLW   0x01            ; clear LCD command
        CALL    COMMAND         ; issue command
        CALL    READY           ; is LCD ready?
        MOVLW   0x06            ; shift cursor right
        CALL    COMMAND         ; issue command
        CALL    READY           ; is LCD ready?
        MOVLW   0x86            ; cursor: line 1, pos. 6
        CALL    COMMAND         ; issue command
        CALL    READY           ; is LCD ready?
        MOVLW   A'N'            ; display letter 'N'
        CALL    DATA_DISPLAY
        CALL    READY           ; is LCD ready?
        MOVLW   A'O'            ; display letter 'O'
        CALL    DATA_DISPLAY
        CALL    READY           ; is LCD ready?
HERE    BRA     HERE        
;------------------------------------------------------ 
COMMAND MOVWF   LCD_DATA        ; issue command code
        BCF     LCD_CTRL,RS     ; RS = 0 for command
        BCF     LCD_CTRL,RW     ; R/W = 0 for write
        BSF     LCD_CTRL,EN     ; E = 1 for high pulse
        CALL    SDELAY          ; make a wide En pulse
        BCF     LCD_CTRL,EN     ; E = 0 for H-to-L pulse
        RETURN
;-----------------------------------------------------  
DATA_DISPLAY 
        MOVWF   LCD_DATA        ; copy WREG to LCD DATA pin
        BSF     LCD_CTRL,RS     ; RS = 1 for data
        BCF     LCD_CTRL,RW     ; R/W = 0 for write
        BSF     LCD_CTRL,EN     ; E = 1 for high pulse
        CALL    SDELAY          ; make a wide En pulse
        BCF     LCD_CTRL,EN     ; E = 0 for H-to-L pulse    
        RETURN
;-----------------------------------------------------
; check busy flag   
READY   SETF    TRISD           ; make PORTD input port for LCD data
        BCF     LCD_CTRL,RS     ; RS = 0 access command reg
        BSF     LCD_CTRL,RW     ; R/W = 1 read command flag
; read command reg and check busy flag  
BACK    BSF     LCD_CTRL,EN     ; E = 0 for L-to-H pulse
        CALL    SDELAY          ; make a wide En pulse
        BCF     LCD_CTRL,EN     ; E = 1 for L-to-H pulse
        BTFSC   LCD_DATA,7      ; stay until busy flag = 0
        BRA     BACK
        CLRF    TRISD           ; make PORTD output port for LCD data
        RETURN
; 1/4 SECOND DELAY
LDELAY  
        MOVLW   D'200'          ; load WREG with literal value 200
        MOVWF   REGA            ; copy to delay regA
L1      MOVLW   D'250'          ; load WREG with literal value 250
        MOVWF   REGB            ; copy to delay regB
L2      NOP                     ; waste soem time
        NOP
        DECF    REGB, F         ; decrement value in regB
        BNZ     L2              ; repeat until it equals to zero
        DECF    REGA, F         ; decrement value in regA
        BNZ     L1              ; repeat until it equals to zero
        RETURN
; Short DELAY
SDELAY  
        MOVLW   D'2'            ; load WREG with literal value 2
        MOVWF   REGC            ; copy to delay regE
S1      NOP
        DECF    REGC, F         ; decrement value in regE
        BNZ     S1              ; repeat until it equals to zero
        RETURN
        END

图片 1

When I change the infinite loop at the end of the code to instead loop around loading and displaying the characters, I can see that both characters are being displayed in the loop (see image 2).

图 2 So, my question is, what is wrong with my code (below) that is causing it to only display a single character, ie, the last character?

Please note that when I use a delay (in the assembly code) intead of a busy flag, the code works as intended. Likewise, the C version (see below) using a "check busy" flag also works as intended. So, I am left scratching my head as to what could possibly be the issue. Therefore, any insight that anyone can provide will be very much appreciated.

#define ldata PORTD                     // PORTD = LCD data pins
#define rs PORTCbits.RC0                // rs = PORTC.0
#define rw PORTCbits.RC1                // rw = PORTC.1
#define en PORTCbits.RC2                // en = PORTC.2
#define busy PORTDbits.RD7              // busy = PORTD.7

void lcdcmd(unsigned char value);
void lcddata(unsigned char value);
void lcdready(void);
void MSDelay(unsigned int itime);
 
void main()
  {
    TRISD = 0;                          // both ports B and D as output
    TRISB = 0;
    en = 0;                             // enable idle low      
    MSDelay(250);                       // long delay
    lcdcmd(0x38);                       // init. LCD 2  lines, 5x7 matrix
    MSDelay(250);                       // long delay
    lcdcmd(0x0E);                       // display on, cursor on
    lcdready();                         // check the LCD busy flag
    lcdcmd(0x01);                       // clear LCD
    lcdready();                         // check the LCD busy flag          
    lcdcmd(0x06);                       // shift cursor right
    lcdready();                         // check the LCD busy flag          
    lcdcmd(0x86);                       // line 1, position 6
    lcdready();                         // check the LCD busy flag          
    lcddata('N');                       // display letter 'N'
    lcdready();                         // check the LCD busy flag
    lcddata('O');                       // display letter 'O'  
  }
void lcdcmd(unsigned char value)
  {
    ldata = value;                      // put the value on the pins
    rs = 0;
    rw = 0;
    en = 1;                             // strobe the enable pin
    MSDelay(1);
    en = 0;
  }
void lcddata(unsigned char value)
  {
    ldata = value;                      // put the value on the pins
    rs = 1;
    rw = 0;
    en = 1;                             // strobe the enable pin
    MSDelay(1);
    en = 0;
  }

void lcdready()
  {
    TRISD = 0xFF;                       // make PORTD an input
    rs = 0;                  
    rw = 1;                   
    do                                  // wait here for busy flag
     {
        en = 1;                          // strobe the enable pin
       MSDelay(1);
       en = 0;
     }while(busy==1);
    TRISD = 0; 
   }
void MSDelay(unsigned int itime)
  {
    unsigned int i, j;
    for(i=0;i<itime;i++)
       for(j=0;j<135;j++);                
  }

The busy flag for the HD44780 8-bit parallel interface is valid only while the ENABLE is at a HIGH level.

In practice when using a real LCD character module the state of the LCD outputs will remain at their last driven state for a microsecond or so after the ENABLE is set to a LOW level. This does not happen in simulation so will be invalid at the time the ENABLE is set to a LOW level.

You need to read and comprehend the information in the LCD module data sheet. Pay attention to the timing diagrams for the LCD read cycles.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM