;**************************** ; >-< G Soft Creations >-< ; LCD Routines-GSC (C) 2007 ;============================ ; ::: Internal RAM ::: ; 0x00 to 0x0F = registers r ; 0x10 to 0x29 = prog vars .equ LcdStat, 0x17 ; Controls BackLight & Cmd/Dat of LCD. At addrs 0x17 for example,can change ; 0x2A to 0x37 = stack .equ STK, 0x2A ;------------------ ; Defines ;------------------ ;XXXXXXXXXXXXXXXXXXXXXXXX LCD XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .equ LCD, P2 ; LCD conected to P2 .equ LCD_RS, 0x10 ; Val of pin P2.4 (Cmd / Data) .equ LCD_RW, 0x20 ; Val of pin P2.5 (Read / Write) .equ LCD_BL, 0x80 ; Val of pin P2.7 (Back Light) .flag LCD_PEN, P2.6 ; Enable Pin .flag LCD_PBL, P2.7 ; BackLight Pin .flag LCD_BUSY, P2.3 ; Busy Pin ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;******************************************************** .org 0x2B ;----------------------- ; LCD Routines: ;----------------------- ;******************************************************************** ; Sends Commands or Chars on ACC to the LCD nibble per nibble ; To send char do an AND on LcdStat with LCD_RS ; Destroys: r6 & r7 ;******************************************************************** LcdWrite: mov r6, #2 ; Sending 2 nibbles mov r7, a ; backup a swap a ; high nibble first _LcdWLoop: anl a, #0x0F ; discard high nibble orl a, LcdStat ; get the RW, RS & BL status mov LCD, a setb LCD_PEN ; Clock the Enable pin clr LCD_PEN ; / acall LcdBusy ; wait the busy bit to clear mov a, r7 ; restore to send low nibble djnz r6, _LcdWLoop ret ;******************************************************************** ; LcdRead: Reads a byte from LCD in the Acc ;******************************************************************** LcdRead: mov LCD, #0x2F ; Pull high the data pins _LcdB: ; & RW pin (RS & EN low) setb LCD_PEN ; Reads the first 4 bits mov a, LCD clr LCD_PEN anl a, #0x0F ; Use just low nibble swap a ; first is the high nibble push acc setb LCD_PEN ; Reads the last 4 bits mov a, LCD clr LCD_PEN anl a, #0x0F ; Use just low nibble mov r5, a pop acc orl a, r5 ; combine whole byte ret ;******************************************************************** ; LcdBusy: Wait until busy is clear ;******************************************************************** LcdBusy: acall LcdRead jb acc.7, LcdBusy ret ;******************************************************************** ; Initializes the LCD in 4 bit mode, 2 lines x 16 cols ;******************************************************************** _LcdISeq: .db 0x33, 0x32, 0x28, 0x06, 0x01, 0x0F, 0x0C LcdInit: mov r0, #7 ; send 7 bytes mov dptr, #_LcdISeq _LcdILoop: clr a movc a, @a+dptr ; get the init seq bytes inc dptr mov r4, #2 ; sending 2 nibbles mov r5, a ; backup byte on r5 swap a ; get first nibble _LcdLoop2: anl a, #0x0F mov LCD, a setb LCD_PEN clr LCD_PEN mov r7, #10 ; Do some delay because the _LcdILoop3: ; busy bit cant be read yet djnz r6, _LcdILoop3 djnz r7, _LcdILoop3 mov a, r5 ; get the original byte djnz r4, _LcdLoop2 ; send second nibble djnz r0, _LcdILoop ; Loop for 7 bytes ret ;******************************************************************** ; Prints a formated string ended by #0xF0 on the LCD ; Format: if encounter one of thiz do that: ; 0x80 to 0xCF -> position cursor ; 0xD0 -> same as printf %d (prints 1 byte on the stack ; as decimal a number.) ; 0xE0 -> Clear LCD ; 0xF0 -> End of String ;******************************************************************** LcdPrintf: pop 0x01 ; get the dptr pushed by acall on r1 & r2 pop 0x02 ; to get the right params for printf __LcdPrintf: clr a movc a, @a+dptr ; get next byte inc dptr ; point to next byte cjne a, #0xF0, _KeepPrint ; check for end push 0x02 ; restore the dptr ptr push 0x01 ret _KeepPrint: mov r0, a ; backup subb a, #0x80 ; check if ch is less jc _NormalChars ; then 0x80 (normal ch) mov a, r0 subb a, #0xD0 ; check if ch is > 0x80 & < 0xCF jnc _NoPos mov a, r0 acall LcdWrite ; (positioning) sjmp __LcdPrintf _NoPos: cjne r0, #0xD0, _NoDecimal ; check for a = 0xD0 (above subb) orl LcdStat, #LCD_RS ; this will send chars pop acc ; get the ch to print as decimal acall DispNum ; from the stcak xrl LcdStat, #LCD_RS ; back to commands sjmp __LcdPrintf _NoDecimal: cjne r0, #0xE0, __LcdPrintf ; check for a = 0xE0 mov a, #0x01 ; clear command acall LcdWrite sjmp __LcdPrintf _NormalChars: orl LcdStat, #LCD_RS ; this will send chars mov a, r0 ; get the ch to print acall LcdWrite ; send the char xrl LcdStat, #LCD_RS ; back to commands sjmp __LcdPrintf ;******************************************************************************************** ; DispNum: Show the acc on the LCD as a decimal number ; LcdStat must be already orld with LCD_RS ;******************************************************************************************** DispNum: mov b, #100 div ab jz DispNoCent add a, #48 ; to ASCII acall LcdWrite DispNoCent: mov a, b mov b, #10 div ab add a, #48 ; to ASCII acall LcdWrite mov a, b add a, #48 ; to ASCII acall LcdWrite ret ; Example code: ;************************************************************************* ;==========================-------------------------- ; Main Routine: Test LCD ;==========================-------------------------- ;************************************************************************* msgStrt: .db 0xE0, "G Soft Creations", 0xC0, "Show 33: ", 0xD0, 0xF0 ; this string prints "G Soft Creations" on the 1st line and "Show 33: 33" on the second Start: mov LcdStat, #0x00 acall LcdInit mov dptr, #msgStrt push #33 ; Push numbers you want to show acall LcdPrintf .org 0x00 ;locate routine at 00H ljmp Start ;jump to START