Monday, January 30, 2006

8051: Example 15

Writing message on LCD display

This example uses the most frequently used type of LCD which displays text in two lines with 16 characters each. In order to save I/O ports, only 4 pins are used for communication here. In this way each byte is transmitted in two steps: first higher then lower nible.
LCD needs to be initialized at the beginning of the program. Besides, parts of the program which repeat in the program create special subroutines. All this may seem extremely complicated, but the whole program basically performs several simple operations and displays ”Mikroelektronika Razvojni sistemi”.
Write message on LCD display
*************************************************************************
;* PROGRAM NAME : Lcd.ASM
;* DESCRIPRTION : Program for testing LCD display. 4-bit communication
;* is used. Program does not check BUSY flag but uses program delay 
;* between 2 commands. PORT1 is used for connection
;* to the microcontroller.
;************************************************************************

;BASIC DIRECTIVES

$MOD53
$TITLE(LCD.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING

;Stack
          DSEG     AT     0E0h
Stack_Start:       DS     020h

Start_address      EQU    0000h

                                             ;Reset vectors
          CSEG     AT     0
          ORG      Start_address
          JMP      Inic

          ORG      Start_address+100h

          MOV      IE,#00                    ; All interrupts are disabled
          MOV      SP,#Stack_Start

Inic:     CALL     LCD_inic                  ; Initialize LCD

;*************************************************
;* MAIN PROGRAM
;*************************************************

START:    MOV      A,#80h                    ; Next character will appear on the first
          CALL     LCD_status                ; location in the first line of LCD display.
          MOV      A,#'M'                    ; Display character ‘M’.
          CALL     LCD_putc                  ; Call subroutine for character transmission.
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#'k'                    ; Display character ‘k’.
          CALL     LCD_putc
          MOV      A,#'r'                    ; Display character ‘r’.
          CALL     LCD_putc
          MOV      A,#'o'                    ; Display character ‘o’.
          CALL     LCD_putc
          MOV      A,#'e'                    ; Display character ‘e’.
          CALL     LCD_putc
          MOV      A,#'l'                    ; Display character ‘l’.
          CALL     LCD_putc
          MOV      A,#'e'                    ; Display character ‘e’.
          CALL     LCD_putc
          MOV      A,#'k'                    ; Display character ‘k’.
          CALL     LCD_putc
          MOV      A,#'t'                    ; Display character ‘t’.
          CALL     LCD_putc
          MOV      A,#'r'                    ; Display character ‘r’.
          CALL     LCD_putc
          MOV      A,#'o'                    ; Display character ‘o’.
          CALL     LCD_putc
          MOV      A,#'n'                    ; Display character ‘n’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#'k'                    ; Display character ‘k’.
          CALL     LCD_putc
          MOV      A,#'a'                    ; Display character ‘a’.
          CALL     LCD_putc

          MOV      A,#0c0h                   ; Next character will appear on the first
          CALL     LCD_status                ; location in the second line of LCD display.
          MOV      A,#'R'                    ; Display character ‘R’.
          CALL     LCD_putc                  ; Call subroutine for character transmission.
          MOV      A,#'a'                    ; Display character ‘a’.
          CALL     LCD_putc
          MOV      A,#'z'                    ; Display character ‘z’.
          CALL     LCD_putc
          MOV      A,#'v'                    ; Display character ‘v’.
          CALL     LCD_putc
          MOV      A,#'o'                    ; Display character ‘o’.
          CALL     LCD_putc
          MOV      A,#'j'                    ; Display character ‘j’.
          CALL     LCD_putc
          MOV      A,#'n'                    ; Display character ‘n’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#' '                    ; Display character ‘ ’.
          CALL     LCD_putc
          MOV      A,#'s'                    ; Display character ‘s’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#'s'                    ; Display character ‘s’.
          CALL     LCD_putc
          MOV      A,#'t'                    ; Display character ‘t’.
          CALL     LCD_putc
          MOV      A,#'e'                    ; Display character ‘e’.
          CALL     LCD_putc
          MOV      A,#'m'                    ; Display character ‘m’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc

          MOV      R0,#20d                   ; Wait time (20x10ms)
          CALL     Delay_10ms                ;
          MOV      DPTR,#LCD_DB              ; Clear display
          MOV      A,#6d                     ;
          CALL     LCD_inic_status           ;
          MOV      R0,#10d                   ; Wait time(10x10ms)
          CALL     Delay_10ms
          JMP      START

;*********************************************
;* Subroutine for wait time (T= r0 x 10ms)
;*********************************************

Delay_10ms:  MOV   R5,00h                    ; 1+(1+(1+2*r7+2)*r6+2)*r5 approximately
             MOV   R6,#100d                  ; (if r7>10)
             MOV   R7,#100d                  ; 2*r5*r6*r7
             DJNZ  R7,$                      ; $ indicates current instruction.
             DJNZ  R6,$-4
             DJNZ  R5,$-6
             RET

;**************************************************************************************
;* SUBROUTINE: LCD_inic
;* DESCRIPTION: Subroutine for LCD initialization.
;*
;* (is used with 4-bit interface, under condition that pins DB4-7 on LCD
;* are connected to pins PX.4-7 on microcontroller’s ports, i.e. four higher
;* bits on the port are used).
;*
;* NOTE: It is necessary to define port pins for controlling LCD operation:
;* LCD_enable, LCD_read_write, LCD_reg_select,similar to port for connection to LCD.
;* It is also necessary to define addresses for the first character in each
;* line.
;**************************************************************************************

LCD_enable     BIT    P1.3                   ; Bit for activating pin E on LCD.
LCD_read_write BIT    P1.1                   ; Bit for activating pin RW on LCD.
LCD_reg_select BIT    P1.2                   ; Bit for activating pin RS on LCD.
LCD_port       SET    P1                     ; Port for connection to LCD.
Busy           BIT    P1.7                   ; Port pin on which Busy flag appears.

LCD_Start_I_red  EQU   00h                   ; Address of the first message character
                                             ; in the first line of LCD display.
LCD_Start_II_red EQU   40h                   ; Address of the first message character
                                             ; in the second line of LCD display.

LCD_DB:        DB     00111100b              ; 0 -8b, 2/1 lines, 5x10/5x7 format
               DB     00101100b              ; 1 -4b, 2/1 lines, 5x10/5x7 format
               DB     00011000b              ; 2 -Display/cursor shift, right/left
               DB     00001100b              ; 3 -Display ON, cursor OFF, cursor blink off
               DB     00000110b              ; 4 -Increment mode, display shift off
               DB     00000010b              ; 5 -Display/cursor home
               DB     00000001b              ; 6 -Clear display
               DB     00001000b              ; 7 -Display OFF, cursor OFF, cursor blink off

LCD_inic:                                    ;*****************************************

               MOV    DPTR,#LCD_DB

               MOV    A,#00d                 ; Triple initialization in 8-bit
               CALL  LCD_inic_status_8       ; mode is performed at the beginning
               MOV   A,#00d                  ; (in case of slow increment of
               CALL  LCD_inic_status_8       ; power supply when the power supply is on
               MOV   A,#00d
               lcall LCD_inic_status_8

               MOV   A,#1d                   ; Change from 8-bit into
               CALL  LCD_inic_status_8       ; 4-bit mode
               MOV   A,#1d
               CALL  LCD_inic_status

               MOV   A,#3d                   ; As from this point the program executes in
                                             ;4-bit mode
               CALL  LCD_inic_status
               MOV   A,#6d
               CALL  LCD_inic_status
               MOV   A,#4d
               CALL  LCD_inic_status

               RET

LCD_inic_status_8:
                                             ;******************************************
               PUSH  B

               MOVC  A,@A+DPTR
               CLR   LCD_reg_select          ; RS=0 - Write command
               CLR   LCD_read_write          ; R/W=0 - Write data on LCD

               MOV   B,LCD_port              ; Lower 4 bits from LCD port are memorized
               ORL   B,#11110000b
               ORL   A,#00001111b
               ANL   A,B

               MOV   LCD_port,A              ; Data is moved from A to LCD port
               SETB  LCD_enable              ; high-to-low transition signal
                                             ; is generated on the LCD's EN pin
               CLR   LCD_enable               

               MOV   B,#255d                 ; Time delay in case of improper reset
               DJNZ  B,$                     ; during initialization
               DJNZ B,$
               DJNZ B,$

               POP B
               RET

LCD_inic_status:
;****************************************************************************
               MOVC  A,@A+DPTR
               CALL  LCD_status
               RET

;****************************************************************************
;* SUBROUTINE: LCD_status
;* DESCRIPTION: Subroutine for defining LCD status.
;****************************************************************************

LCD_status:    PUSH  B
               MOV   B,#255d
               DJNZ  B,$
               DJNZ  B,$
               DJNZ  B,$
               CLR   LCD_reg_select          ; RS=O: Command is sent to LCD
               CALL  LCD_port_out

               SWAP  A                       ; Nibles are swapped in accumulator

               DJNZ  B,$
               DJNZ  B,$
               DJNZ  B,$
               CLR   LCD_reg_select          ; RS=0: Command is sent to LCD
               CALL  LCD_port_out

               POP   B
               RET

;****************************************************************************
;* SUBROUTINE: LCD_putc
;* DESCRIPTION: Sending character to be displayed on LCD.
;****************************************************************************

LCD_putc:      PUSH  B
               MOV   B,#255d
               DJNZ  B,$
               SETB  LCD_reg_select          ; RS=1: Character is sent to LCD
               CALL  LCD_port_out

               SWAP  A                       ; Nibles are swapped in accumulator

               DJNZ  B,$
               SETB  LCD_reg_select          ; RS=1: Character is sent to LCD

               CALL  LCD_port_out
               POP   B
               RET

;****************************************************************************
;* SUBROUTINE: LCD_port_out
;* DESCRIPTION: Sending commands or characters on LCD display
;****************************************************************************

LCD_port_out:  PUSH  ACC
               PUSH  B
               MOV   B,LCD_port              ; Lower 4 bits of LCD port are memorized
               ORL   B,#11110000b
               ORL   A,#00001111b
               ANL   A,B

               MOV   LCD_port,A              ; Data is copied from A to LCD port

               SETB  LCD_enable              ; high-to-low transition signal
                                             ; is generated on the LCD's EN pin
               CLR   LCD_enable               

               POP   B
               POP   ACC
               RET

               END                           ; End of program

Binary to decimal number conversion

When using LED and LCD displays, it is often necessary to convert numbers from binary to decimal. For example, if some register contains a number in binary format that should be displayed on a three digit LED display it is first necessary to convert it to decimal format. In other words, it is necessary to define what should be displayed on the most right display (units), middle display (tens) and most left display (hundreds).
The subroutine below performs conversion of one byte. Binary number is stored in the accumulator, while digits of that number in decimal format are stored in registers R3, R2 and accumulator (units, tens and hundreds, respectively).
;************************************************************************
;* SUBROUTINE NAME : BinDec.ASM
;* DESCRIPTION : Content of accumulator is converted into three decimal digits
;************************************************************************

BINDEC:            MOV     B,#10d         ; Store decimal number 10 in B
                   DIV     AB             ; A:B. Remainder remains in B
                   MOV     R3,B           ; Move units to register R3
                   MOV     B,#10d         ; Store decimal number 10 in B
                   DIV     AB             ; A:B. Remainder remains in B
                   MOV     R2,B           ; Move tens to register R2
                   MOV     B,#10d         ; Store decimal number 10 in B
                   DIV     AB             ; A:B. Remainder remains in B
                   MOV     A,B            ; Move hundreds to accumulator
                   RET                    ; Return to the main program