; File: IOLCD_P@.A51 Date: 01/15/93 ; ; /* (c) Copyright BLUE EARTH RESEARCH, MANKATO, MN 1993. */ ; /* All rights reserved. */ ; $ TITLE(LCD PRINT@ DRIVER FOR I/O-24 MODULE) $ PW(93) PL(60) DATE(01-15-93) $ DEBUG ERRORPRINT XREF ; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ; º LCD DRIVER SOFTWARE FOR IMPLEMENTING 2x16 DISPLAY º ; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ Written By: Thomas Bachmann ³ ; ³ Blue Earth Research, Mankato, MN 56001 ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ; NOTES: ; The following program can be used to initialize and write ; messages to most standard LCD Modules using the Micro-440 ; and I/O-24 module. It was tested using a Sharp LM16X21A ; 2 line by 16 character display. ; After this program is initialized from within BASIC by ; executing the "CALL 7F00H" Statement, characters are written ; to the LCD by the "PRINT@" Statement. A Carriage Return ; (0DH) will cause the cursor to be at the "home" position, ; and a Line Feed (0AH) will place the cursor at the beginning ; of the second line. A Form Feed (0CH) will clear the screen ; and return the cursor to the home position. ; The following BASIC program can be used to demonstrate the ; functions of the LCD with this program: ; 10 CALL 7F00H : REM INITIALIZE LCD MODULE ; 20 PRINT@ "BLUE EARTH" : PRINT@ "RESEARCH" ; 30 DO : G=GET : UNTIL G : PRINT@ CHR$(12), ; 40 PRINT@ "LCD" : PRINT@ "DEMO" ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ $ EJECT ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ DEFINITIONS SPECIFIC TO THE SYSTEM WIRING ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; The following software assume that the LCD module is ; wired with all inputs to Port A and Port B as follows: ; SIGNAL I/O-24 SIGNAL ; -------- ----------- -------- ; 13 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; DB7ÄÄÄÄÄÄÄÄÄÄÄ´ PA7 ³ ; 25 ³ ³ ; DB6ÄÄÄÄÄÄÄÄÄÄÄ´ PA6 ³ ; 12 ³ ³ ; DB5ÄÄÄÄÄÄÄÄÄÄÄ´ PA5 ³ ; 24 ³ ³ ; DB4ÄÄÄÄÄÄÄÄÄÄÄ´ PA4 ³ ; 11 ³ ³ ; DB3ÄÄÄÄÄÄÄÄÄÄÄ´ PA3 ³ ; 23 ³ ³ ; DB2ÄÄÄÄÄÄÄÄÄÄÄ´ PA2 ³ ; 10 ³ ³ ; DB1ÄÄÄÄÄÄÄÄÄÄÄ´ PA1 ³ ; 22 ³ ³ ; DB0ÄÄÄÄÄÄÄÄÄÄÄ´ PA0 ³ ; 9 ³ ³ 2 ; EÄÄÄÄÄÄÄÄÄÄÄÄ´ PB7 0-5 ÃÄÄÄÄÄÄÄÄÄÄÄVee ; 21 ³ ³ 14 ; R/WÄÄÄÄÄÄÄÄÄÄÄ´ PB6 +5V ÃÄÄÄÄÄÄÄÄÄÄÄVcc ; 8 ³ ³ 1 ; RSÄÄÄÄÄÄÄÄÄÄÄ´ PB5 GND ÃÄÄÄÄÄÄÄÄÄÄÄVss ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; Troubleshooting hint: ; If your LCD module appears to reset properly but does not ; display characters, make sure that the contrast adjust ; potentiometer on the I/O-24 module is properly positioned. $ EJECT ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ PARAMETER DEFINITIONS ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ; All registers, bits, addresses, and constants are declared ; below. The program can be adapted to system wiring or ; parameter changes by modifying the corresponding definition ; located in the following code block. DSEG AT 18H REG_SEL: DS 1 ; SELECT COMMAND OR DATA REG. TEMP_HOLD: DS 1 ; TEMP LCD BYTE BUFFER CLOCK1: DS 2 ; TIMER REGISTERS FOR WAITING SPACE EQU 20H CR EQU 0DH LF EQU 0AH FF EQU 0CH EXEC_TIME EQU 20 ; INSTRUCTION EXECUTION TIME COMMAND EQU 1110$0000B ; ALL SIGNALS LOW DATA_OUT EQU 1100$0000B ; SELECT DD RAM $ EJECT RESET EQU 0011$0000B ; "RESET" BYTE FUNCTION_SET EQU 0011$1000B ; "FUNCTION SET" BYTE ; NOTE: 001d$nf00B For "Function Set" where ; d=1 for 8-bit interface, 0 for 4-bit interface ; n=1 for 2 line display, 0 for 1 line display ; f=1 for 5x10 dot pattern, 0 for 5x7 dot pattern DISPLAY_OFF EQU 0000$1000B ; "DISPLAY OFF" BYTE DISPLAY_ON EQU 0000$1100B ; "DISPLAY ON" BYTE ; NOTE: 0000$11cbB For "Display On," where ; c=1 for Cursor on, and b=1 for blinking cursor CLEAR_DISPLAY EQU 0000$0001B ; "CLEAR DISPLAY" BYTE MODE_SET EQU 0000$0110B ; "ENTRY MODE" BYTE LINE2 EQU 1100$0000B ; "GOTO LINE 2" BYTE LINE1 EQU 1000$0000B ; "GOTO LINE 1" BYTE SHIFT_RIGHT EQU 0001$1100B ; "SHIFT DISPLAY RIGHT" SHIFT_LEFT EQU 0001$1000B ; "SHIFT DISPLAY LEFT" CURSOR_LEFT EQU 0001$0000B ; "SHIFT CURSOR LEFT" CURSOR_RIGHT EQU 0001$0100B ; "SHIFT CURSOR RIGHT" ; Initialize the 82C55 Control Word as follows: ; PORT A = OUTPUT PORT C(0-3) = OUTPUT ; PORT B = OUTPUT PORT C(4-7) = INPUT ; Note: For more information, see Page 3-107 in Intel Data ; Book #296467-002, "1991 Peripheral Components" CONTROL_WORD EQU 1000$1000B ; SELECT MODE 0 CONTROL EQU 0FB00H ; SET BOTH A0 & A1 PORT_C EQU 0FA00H ; SET A1 ONLY PORT_B EQU 0F900H ; SET A0 ONLY PORT_A EQU 0F800H ; NEITHER A0 NOR A1 RESET_HIGH EQU 0E200H ; RESET SIGNAL HIGH RESET_LOW EQU 0E000H ; RESET SIGNAL LOW $ EJECT ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ BEGINNING OF INITIALIZATION ROUTINE ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; CSEG AT 7F00H MOV DPTR,#RESET_HIGH MOVX @DPTR,A ; HOLD RESET LINE HIGH MOV CLOCK1,#25 ; LOAD 50 uS LOOP COUNT DJNZ CLOCK1,$ MOV DPTR,#RESET_LOW MOVX @DPTR,A ; INITIALIZE 82C55 PORTS A & B AS OUTPUTS MOV DPTR,#CONTROL MOV A,#CONTROL_WORD MOVX @DPTR,A ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ INITIALIZE USER LCD OUTPUT ALGORITHM ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; The following code places the jump vector in memory and ; sets the protection bit that tells BASIC where it should ; direct the PRINT@ output to. MOV DPTR,#403CH ; POINT TO JUMP LOCATION MOV A,#2 ; LOAD LJMP MOVX @DPTR,A INC DPTR MOV A,#HIGH CHAR_OUTPUT MOVX @DPTR,A INC DPTR MOV A,#LOW CHAR_OUTPUT MOVX @DPTR,A SETB 39 ; PROTECTION BIT $ EJECT ; ------------------- INITIALIZE LCD MODULE ------------------- LCDSTART: ; LCD display initialization routine MOV DPTR,#PORT_B MOV REG_SEL,#COMMAND MOV A,REG_SEL ; CLEAR ALL CONTROL LINES MOVX @DPTR,A MOV CLOCK1,#30 ; WAIT FOR A LONG TIME CALL WAIT_LONG MOV A,#RESET ; WRITE BYTE ACALL CLOCK_N_WAIT ACALL LD_DEC ; OUTPUT AND WAIT A WHILE MOV A,#RESET ; WRITE BYTE ACALL CLOCK_N_WAIT MOV A,#RESET ; WRITE BYTE ACALL CLOCK_N_WAIT MOV A,#FUNCTION_SET ; WRITE BYTE ACALL CLOCK_N_WAIT ; CLOCK IT IN ; Output the byte that specifies an 8-bit interface MOV A,#FUNCTION_SET ; GET THE BYTE ACALL CLOCK_N_WAIT ; CLOCK IT IN ; Turn the display off MOV A,#DISPLAY_OFF ; GET THE BYTE ACALL CLOCK_N_WAIT ; CLOCK IT IN ACALL CLEAR ; CLEAR THE DISPLAY ; SET THE DISPLAY ENTRY MODE MOV A,#MODE_SET ; GET THE BYTE ACALL CLOCK_N_WAIT ; CLOCK IT IN ; TURN THE DISPLAY BACK ON MOV A,#DISPLAY_ON ; GET THE BYTE ACALL CLOCK_N_WAIT ; CLOCK IT IN ; MAKE SURE THAT THE CONTRAST ADJUST WILL WORK MOV DPTR,#PORT_C MOV A,#0F0H ; WRITE 1's TO INPUT PORT MOVX @DPTR,A ; Fall through to clear display and return to BASIC ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ DISPLAY WRITING SUBROUTINES ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; Clear the LCD display CLEAR: MOV REG_SEL,#COMMAND MOV TEMP_HOLD,#CLEAR_DISPLAY ; GET THE BYTE ACALL OUT ; CLOCK IT IN LD_DEC: MOV CLOCK1,#10 ; WAIT AT LEAST 4.9 mS WAIT_LONG: MOV CLOCK1+1,#250 DJNZ CLOCK1+1,$ DJNZ CLOCK1,WAIT_LONG RET ; ---------------------- LCD UPDATE --------------------------- ; The following code is executed every time that the BASIC ; program executes a "PRINT@" Statement. After the statement ; is executed from within BASIC, the character to be output is ; in the accumulator. CHAR_OUTPUT: MOV REG_SEL,#DATA_OUT ; POINT TO DATA REGISTER CJNE A,#SPACE,$+3 ; CHECK FOR A PRINTABLE CHAR JNC OUTPUT MOV REG_SEL,#COMMAND ; POINT TO COMMAND REGISTER ; If the character is a Form Feed, the display is cleared and ; the cursor is placed at the beginning of the first line. CJNE A,#FF,CR_Chk ; Form Feed? SJMP Clear ; If the character is a carriage return, the display cursor is ; placed at the beginning of the first line of the display. CR_Chk: CJNE A,#CR,LF_Chk ; Carriage return? MOV A,#LINE1 SJMP OUTPUT ; If the character is a line feed, the display cursor is ; placed at the beginning of the second line of the display. LF_Chk: CJNE A,#LF,NoChar ; Line Feed? MOV A,#LINE2 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ $ EJECT ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ SUBROUTINE FOR SENDING A CHARACTER ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; SEND AN 8-BIT CHARACTER (OR COMMAND) TO THE LCD. OUTPUT: MOV TEMP_HOLD,A ; SAVE IT ; ------------------ OUTPUT THE CHARACTER --------------------- OUT: MOV DPTR,#PORT_B ; SET CONTROL LINES MOV A,REG_SEL ; SELECT COMMAND OR DATA MOVX @DPTR,A MOV A,TEMP_HOLD ; GET CHARACTER AGAIN CLOCK_N_WAIT: MOV DPTR,#PORT_A ; POINT TO DATA LINES MOVX @DPTR,A ; OUTPUT THE BYTE MOV DPTR,#PORT_B ; POINT TO CONTROL LINES MOV A,REG_SEL CLR ACC.7 ; SET 'E' HIGH MOVX @DPTR,A SETB ACC.7 MOVX @DPTR,A ; AND CLEAR 'E' MOV CLOCK1+1,#EXEC_TIME ; WAIT A WHILE DJNZ CLOCK1+1,$ NoChar: RET ; Back to BASIC END ; Following is the HEX file derived from the assembled source ; file. This can be used for directly loading the program via ; MONITOR-51 and almost any terminal program. :107F000090E200F0751A19D51AFD90E000F090FB90 :107F1000007488F090403C7402F0A3747FF0A37466 :107F200072F0D22790F9007518E0E518F0751A1E66 :107F3000127F687430F198F1657430F1987430F103 :107F4000987438F1987438F1987408F198F15D7468 :107F500006F198740CF19890FA0074F0F07518E03E :107F6000751901F190751A0A751BFAD51BFDD51A02 :107F7000F7227518C0B4200050147518E0B40C0234 :107F800080DBB40D0474808005B40A2174C0F51937 :107F900090F900E518F0E51990F800F090F900E587 :0E7FA00018C2E7F0D2E7F0751B14D51BFD22C6 :00000001FF