When interfacing an F84 with an Hitachi LCD module using the below code - Available from David Taites archive as cramer.zip I can only print 9 characters onto the display - then it stops - no matter what these characters are. For instance, compiling the code 'as-is' my LCD display reads "Microchip". However the second line does not appear -getting it to display "Hello World" I am left with "Hello Wor" on my display - it matters not what the text is - 9 characters and thats it... This also means that 4 characters, a "LINE2" command and another 4 characters shuould work. Does anyone have any idea why this is happeining and what I can do to stop it? ;*************************************************************************** ************************** ; ; Program: lcd.asm ; ; This program interfaces to an industry standard 2 line by 20 character display ; module. The program assembles for 4-bit data interface. LCD_DATA is the port which ; supplies the data tothe LCD, while LCD_CNTL is the port that has the control lines ; ( E, RS, R_W ). The data is transfer on the high nibble of the port PORT<7:4> ). ; ; Target: PIC16C84 - But should work on any PIC16CXX running at 4Mhz ; ; Note: To change the clock speed, the delays at the end of the source file need to be changed. ; ; References: ; Addapted from the Microchip AN587 code. ; OPTREX data sheet. ; Also referenced the following web pages: ; http://www.iaehv.nl/users/pouweha/lcd.htm ; http://www.paranoia.com/~filipg/HTML/LINK/F_LCD_tech.html ; http://hobbes.king.ac.uk/matt/pic ; Andrew Warren's QBasic program for calculating delays. ; ; ; History ; Author Date Comments ; Microchip 05-10-94 Original Code (File name was LM032L.ASM) ; ; Norm Cramer 04-22-96 Modified to only use 4 bit interface and to not destroy the ; contents of the lower portion of the output register and the ; output register TRIS. Changed the examples to include a table ; definition using the "dt" compiler directive. Added delay ; subroutines for testing. Changed Check_Busy to Wait_Busy and ; added a Check_Busy that returns 0 if not busy, ff if busy. ; Modified to meet my programming standards for easy maint. ; ; ERRORLEVEL -302 Processor 16C84 Radix HEX EXPAND include include ; ; LCD_DATA EQU PORTB LCD_DATA_TRIS EQU TRISB ; ; LCD_CNTL EQU PORTA LCD_CNTL_TRIS EQU TRISA ; ; ; ; LCD Display Commands and Control Signal names. ; E EQU 3 ; LCD Enable control line R_W EQU 1 ; LCD Read/Write control line RS EQU 2 ; LCD Register Select control line ; ; cblock 0x00c Temp1, Temp, Char, r1, r2, r3, r4 endc ; org _ResetVector ; RESET vector location RESET: goto Start ; ; This is the Periperal Interrupt routine. Should NOT get here ; page ; org _IntVector ; Interrupt vector location ERROR1: bcf STATUS, RP0 ; Bank 0 goto ERROR1 ; ; ; Start: ; POWER_ON Reset (Beginning of program) clrf STATUS ; Do initialization (Bank 0) clrf INTCON bsf STATUS, RP0 ; Bank 1 clrf TRISA ; RA5 - 0 outputs movlw 0xF0 ; movwf TRISB ; RB7 - 4 inputs, RB3 - 0 outputs bsf OPTION_REG, NOT_RBPU ; Disable PORTB pull-ups bcf STATUS, RP0 ; Bank 0 clrf PORTA ; ALL PORT output should output Low. clrf PORTB ; page ; call LCD_Init ; Set up the LCD Module ;Send a message the hard way movlw 'M' call Send_Char movlw 'i' call Send_Char movlw 'c' call Send_Char movlw 'r' call Send_Char movlw 'o' call Send_Char movlw 'c' call Send_Char movlw 'h' call Send_Char movlw 'i' call Send_Char movlw 'p' call Send_Char movlw LINE2 ; Address DDRam first character, second line call Send_Cmd ;Demonstration of the use of a table to output a message movlw 0 ; Table address of start of message dispmsg: movwf Temp1 ; Temp1 holds start of message address call Table andlw 0FFh btfsc STATUS,Z ; Check if at end of message (zero returned at end) goto out call Send_Char ; Display character movf Temp1,w ; Point to next character addlw 1 goto dispmsg out: loop: goto loop ; Stay here forever ; page ; Table: addwf PCL,f ; Jump to character dt "This is a test line!" ; 20 Character string terminated with a 0 Table_End: retlw 0 ; ; Check to ensure table doesn't cross a page boundary. if ( (Table & 0x0FF) >= (Table_End & 0x0FF) ) MESSG "Warning - User Definded: Table crosses page boundry in computed jump" endif ; ;******************************************************************* ;* The LCD Module Subroutines * ;******************************************************************* ; ;******************************************************************* ;*SendChar - Sends character to LCD * ;*This routine splits the character into the upper and lower * ;*nibbles and sends them to the LCD, upper nibble first. * ;******************************************************************* ; Send_Char movwf Char ; Character to be sent is in W call Wait_Busy ; Wait for LCD to be ready movlw 0x0f andwf LCD_DATA,F ; Clear the upper nibble movf Char,w andlw 0xF0 ; Get upper nibble iorwf LCD_DATA,F ; Send data to LCD bcf LCD_CNTL, R_W ; Set LCD to write bsf LCD_CNTL, RS ; Set LCD to data mode bsf LCD_CNTL, E ; toggle E for LCD bcf LCD_CNTL, E movlw 0x0f andwf LCD_DATA,F ; Clear the upper nibble swapf Char,W andlw 0xF0 ; Get lower nibble iorwf LCD_DATA,F ; Send data to LCD bsf LCD_CNTL, E ; toggle E for LCD bcf LCD_CNTL, E return ; page ; ;******************************************************************* ;* Send_Cmd - Sends command to LCD * ;* This routine splits the command into the upper and lower * ;* nibbles and sends them to the LCD, upper nibble first. * ;******************************************************************* Send_Cmd movwf Char ; Character to be sent is in W call Wait_Busy ; Wait for LCD to be ready movlw 0x0f andwf LCD_DATA,F ; Clear the upper nibble movf Char,w andlw 0xF0 ; Get upper nibble iorwf LCD_DATA,F ; Send data to LCD bcf LCD_CNTL,R_W ; Set LCD to write bcf LCD_CNTL,RS ; Set LCD to command mode bsf LCD_CNTL,E ; toggle E for LCD bcf LCD_CNTL,E movlw 0x0f andwf LCD_DATA,F ; Clear the upper nibble swapf Char,W andlw 0xF0 ; Get lower nibble iorwf LCD_DATA,F ; Send data to LCD bsf LCD_CNTL,E ; toggle E for LCD bcf LCD_CNTL,E return ; page ; ;******************************************************************* ;* This routine checks the busy flag, returns when not busy * ;* Affects: * ;* Temp - Returned with busy/address * ;******************************************************************* ; Wait_Busy bsf STATUS, RP0 ; Select Register page 1 movlw 0xf0 ; Set port to input iorwf LCD_DATA_TRIS,W ; Only set upper half of port movwf LCD_DATA_TRIS bcf STATUS, RP0 ; Select Register page 0 bcf LCD_CNTL, RS ; Set LCD for Command mode bsf LCD_CNTL, R_W ; Setup to read busy flag bsf LCD_CNTL, E ; Set E high bcf LCD_CNTL, E ; Set E low movf LCD_DATA, W ; Read upper nibble busy flag, DDRam address andlw 0xF0 ; Mask out lower nibble movwf Temp bsf LCD_CNTL, E ; Toggle E to get lower nibble bcf LCD_CNTL, E swapf LCD_DATA, w ; Read lower nibble busy flag, DDRam address andlw 0x0F ; Mask out upper nibble iorwf Temp,W ; Combine nibbles btfsc Temp, 7 ; Check busy flag, high = busy goto Wait_Busy ; If busy, check again bcf LCD_CNTL, R_W bsf STATUS, RP0 ; Select Register page 1 movlw 0x0F andwf LCD_DATA_TRIS,W movwf LCD_DATA_TRIS ; Set Port for output bcf STATUS, RP0 ; Select Register page 0 return ; page ; ;******************************************************************* ;* This routine checks the busy flag, returns ff if busy 00 if not * ;* busy. Temp will contain the current address. * ;* * ;* Affects: * ;* Temp - Returned with busy/address * ;******************************************************************* ; Check_Busy bsf STATUS, RP0 ; Select Register page 1 movlw 0xf0 ; Set port to input iorwf LCD_DATA_TRIS,W ; Only set upper half of port movwf LCD_DATA_TRIS bcf STATUS, RP0 ; Select Register page 0 bcf LCD_CNTL, RS ; Set LCD for Command mode bsf LCD_CNTL, R_W ; Setup to read busy flag bsf LCD_CNTL, E ; Set E high bcf LCD_CNTL, E ; Set E low movf LCD_DATA, W ; Read upper nibble busy flag, DDRam address andlw 0xF0 ; Mask out lower nibble movwf Temp bsf LCD_CNTL, E ; Toggle E to get lower nibble bcf LCD_CNTL, E swapf LCD_DATA, w ; Read lower nibble busy flag, DDRam address andlw 0x0F ; Mask out upper nibble iorwf Temp,W ; Combine nibbles btfsc Temp, 7 ; Check busy flag, high = busy goto Busy_Exit ; If busy exit with busy flag set bcf LCD_CNTL, R_W bsf STATUS, RP0 ; Select Register page 1 movlw 0x0F andwf LCD_DATA_TRIS,W movwf LCD_DATA_TRIS ; Set Port for output bcf STATUS, RP0 ; Select Register page 0 retlw 0x00 Busy_Exit: bcf LCD_CNTL, R_W bsf STATUS, RP0 ; Select Register page 1 movlw 0x0F andwf LCD_DATA_TRIS,W movwf LCD_DATA_TRIS ; Set Port for output bcf STATUS, RP0 ; Select Register page 0 retlw 0xff ; page ; ; Initilize the LCD Display Module ; LCD_Init: bcf LCD_CNTL, E ; Clear all controll lines bcf LCD_CNTL, RS bcf LCD_CNTL, R_W call Delay15000 ; Wait for 15ms for LCD to get powered up movlw 0x0f andwf LCD_DATA,F ; Clear the upper nibble movlw 0x030 ; Command for 4-bit interface high nibble iorwf LCD_DATA,F ; Send data to LCD bsf STATUS, RP0 ; Select Register page 1 movlw 0x0F andwf LCD_DATA_TRIS,W movwf LCD_DATA_TRIS ; Set Port for output BCF STATUS, RP0 ; Select Register page 0 bsf LCD_CNTL, E ; Clock the initalize command to LCD module bcf LCD_CNTL, E call Delay4100 ; Delay for at least 4.1ms before continuing bsf LCD_CNTL, E ; Clock the initalize command to LCD module bcf LCD_CNTL, E call Delay100 ; delay for at least 100usec before continuing bsf LCD_CNTL, E ; Clock the initalize command to LCD module bcf LCD_CNTL, E call Wait_Busy ; From here on, the Busy Bit will be valid. movlw 0x0f andwf LCD_DATA,F ; Clear the upper nibble movlw 0x020 ; Command for 4-bit interface high nibble (Really an 8bit command but ; lower 4 bits are don't care at this point) iorwf LCD_DATA,F ; Send data to LCD bsf LCD_CNTL, E ; Clock the initalize command to LCD module bcf LCD_CNTL, E movlw FUNCTION_SET ; Send the function set command 4-bit I/F, Font, Number of lines call Send_Cmd ; Can now use the Send_Cmd routine since Busy Bit Valid and in 4bit mode. movlw DISP_OFF call Send_Cmd movlw DISP_ON call Send_Cmd movlw ENTRY_INC call Send_Cmd ; LCD Module is now initalized return ; ; Delay routines. These routines need to be modified to work with the particular PIC configuration ; used. For test purposes, they are instruction count delays based on 4Mhz PIC. The delays are a ; little longer than advertised but close enough for testing. ; Delay4100: movlw d'252' movwf r1 movlw 4 movwf r2 movlw 1 movwf r3 movlw 1 movwf r4 delay_loop: nop decfsz r1,f goto delay_loop decfsz r2,f goto delay_loop decfsz r3,f goto delay_loop decfsz r4,f goto delay_loop return Delay100: movlw d'22' movwf r1 movlw 1 movwf r2 movlw 1 movwf r3 movlw 1 movwf r4 goto delay_loop Delay15000: movlw d'156' movwf r1 movlw 15 movwf r2 movlw 1 movwf r3 movlw 1 movwf r4 goto delay_loop end ICQ: 10061444 E-Mail: sampowel@globalnet.co.uk