; File: IOLCDKP@.A51 Date: 05/20/93 ; ; /* (c) Copyright BLUE EARTH RESEARCH, MANKATO, MN 1993. */ ; /* All rights reserved. */ ; $ TITLE(LCD/KEYPAD PRINT@ DRIVER FOR I/O-24) $ PW(93) PL(60) DATE(05-20-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 4100H" 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 4100H : REM INITIALIZE LCD MODULE ; 20 PRINT@ "BLUE EARTH" : PRINT@ "RESEARCH" ; 30 GOSUB 80 : PRINT@ CHR$(12), ; 40 PRINT@ "LCD" : PRINT@ "DEMO" ; 50 GOSUB 80 : PRINT@ CHR$(D), : GOTO 50 ; 80 DO : D=DBY(1DH) : WHILE D ; 90 DO : D=DBY(1DH) : UNTIL D : RETURN ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ $ 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 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ 7 ; DB7ÄÄÄÄÄÄÄÄÄÄÄ´ PA7 PB3 ÃÄÄÄÄÄÄÄÄÄÄCOL4 ; 25 ³ ³ 19 ; DB6ÄÄÄÄÄÄÄÄÄÄÄ´ PA6 PB2 ÃÄÄÄÄÄÄÄÄÄÄCOL3 ; 12 ³ ³ 6 ; DB5ÄÄÄÄÄÄÄÄÄÄÄ´ PA5 PB1 ÃÄÄÄÄÄÄÄÄÄÄCOL2 ; 24 ³ ³ 18 ; DB4ÄÄÄÄÄÄÄÄÄÄÄ´ PA4 PB0 ÃÄÄÄÄÄÄÄÄÄÄCOL1 ; 11 ³ ³ 5 ; DB3ÄÄÄÄÄÄÄÄÄÄÄ´ PA3 PC7 ÃÄÄÄÄÄÄÄÄÄÄROW4 ; 23 ³ ³ 17 ; DB2ÄÄÄÄÄÄÄÄÄÄÄ´ PA2 PC6 ÃÄÄÄÄÄÄÄÄÄÄROW3 ; 10 ³ ³ 4 ; DB1ÄÄÄÄÄÄÄÄÄÄÄ´ PA1 PC5 ÃÄÄÄÄÄÄÄÄÄÄROW2 ; 22 ³ ³ 16 ; DB0ÄÄÄÄÄÄÄÄÄÄÄ´ PA0 PC4 ÃÄÄÄÄÄÄÄÄÄÄROW1 ; 9 ³ ³ 2 ; EÄÄÄÄÄÄÄÄÄÄÄÄ´ PB7 0-5 ÃÄÄÄÄÄÄÄÄÄÄÄVee ; 21 ³ ³ 14 ; R/WÄÄÄÄÄÄÄÄÄÄÄ´ PB6 +5V ÃÄÄÄÄÄÄÄÄÄÄÄVcc ; 8 ³ ³ 1 ; RSÄÄÄÄÄÄÄÄÄÄÄ´ PB5 GND ÃÄÄÄÄÄÄÄÄÄÄÄVss ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; Keypad Layout: ; ÉÍÍÍÍÍÑÍÍÍÍÍÑÍÍÍÍÍÑÍÍÍÍÍ» ; º 1 ³ 2 ³ 3 ³ A º ; ÇÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄĶ ; º 4 ³ 5 ³ 6 ³ B º ; ÇÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄĶ ; º 7 ³ 8 ³ 9 ³ C º ; ÇÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄĶ ; º * ³ 0 ³ # ³ D º ; ÈÍÍÍÍÍÏÍÍÍÍÍÏÍÍÍÍÍÏÍÍÍÍͼ ; 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 TEMP_KEY: DS 1 ; TEMP BYTE FOR DEBOUNCING SWITCH_BYTE: DS 1 ; LAST KEY PRESSED BSEG AT 0 NR1: DBIT 1 ; SET WHEN NEW VALUE DETECTED NR2: DBIT 1 NR3: DBIT 1 NR4: DBIT 1 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 KEYS EQU 4800H ; STORE KEY READINGS DEBOUNCED EQU KEYS+100H ; STORE DEBOUNCED KEYS ENT EQU 0DH ; ENTER - "ENT" DEL EQU 7FH ; DELETE - "DEL" RST EQU 2 ; RESET - "RST" ROW4 EQU 1100$0001B ; MASK OFF EACH ROW ROW3 EQU 1100$0010B ROW2 EQU 1100$0100B ROW1 EQU 1100$1000B ;ROW4 EQU 1000$0001B ; MASK OFF EACH ROW ;ROW3 EQU 1000$0010B ;ROW2 EQU 1000$0100B ;ROW1 EQU 1000$1000B $ 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 4100H 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 $ EJECT ; -------------- SET UP TIMER0 INTERRUPT VECTOR --------------- MOV DPTR,#400BH ; Stuff "LJMP XXXXH" into MOV A,#2 ; mirrored Timer 0 overflow MOVX @DPTR,A ; vector at address 400BH. INC DPTR MOV A,#HIGH Timer0Int ; Location of Timer 0 MOVX @DPTR,A ; interrupt routine. INC DPTR MOV A,#LOW Timer0Int MOVX @DPTR,A ; ------------- SET UP TIMER0 FOR 5 mS INTERRUPT -------------- CLR TR0 ; STOP TIMER0 FOR NOW MOV A,TL0 ; Reload Timer 0 for 5 mS ADD A,#LOW -4998 ; (Less 2uS to compensate MOV TL0,A ; for ADD & MOV latency.) MOV TH0,#HIGH -4998 ; Timer 0 is a 16 bit timer used to generate a 5 mS interrupt. ; The input to both Timers is the internal system clock ; The frequency is OSC/12 = 1 MHz. (1uS) ; TMOD: ; Timer 1 Timer 0 ; ÃÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÅÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ´ ; ³ GAT ³ C/T ³ M1 ³ M0 ³ GAT ³ C/T ³ M1 ³ M0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 0 0 0 1 0 0 0 1 MOV TMOD,#11H ; TIMER/CNTR MODE CTRL REGISTER ; TCON: ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; ³ TF1 ³ TR1 ³ TF0 ³ TR0 ³ IE1 ³ IT1 ³ IE0 ³ IT0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 0 0 0 1 0 0 0 0 SETB TR0 ; Start Timer ; IE: ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; ³ EA ³ EC ³ ET2 ³ ES ³ ET1 ³ EX1 ³ ET0 ³ EX0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 1 0 0 0 0 0 1 0 SETB ET0 ; Timer 0 interrupt enable SETB EA ; Global interrupt enable ; 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 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ 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 ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ CLEAR TIMER0 INTERRUPT ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; STOP: CLR TR0 ; Stop Timer CLR ET0 ; Timer 0 interrupt enable CLR EA ; Global interrupt enable RET $ EJECT ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ TIMER0 INTERRUPT SERVICING ROUTINE ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; Timer0Int: PUSH ACC ; 5 mS interrupt PUSH PSW PUSH DPH PUSH DPL MOV A,TL0 ; Reload Timer 0 for 5 mS ADD A,#LOW -4998 ; (Less 2uS to compensate MOV TL0,A ; for ADD & MOV latency.) MOV TH0,#HIGH -4998 ; -------------------- SCAN THE KEYPAD ------------------------ MOV DPTR,#PORT_B ; POINT TO KEYPAD COLUMNS MOV A,#ROW1 ; GET THE FIRST ROW ORL A,REG_SEL MOVX @DPTR,A MOV DPTR,#PORT_C ; POINT TO KEYPAD ROWS MOVX A,@DPTR ; READ THEM ORL A,#0FH ; MASK OFF UNUSED BITS CPL A MOV TEMP_KEY,A ; SAVE THE BYTE MOV DPTR,#KEYS MOVX A,@DPTR ; GET PREVIOUS READING CJNE A,TEMP_KEY,NEW1 INC DPH ; POINT TO DEBOUNCED LOCATION MOVX @DPTR,A CLR NR1 $ EJECT READ2: MOV DPTR,#PORT_B ; POINT TO KEYPAD COLUMNS MOV A,#ROW2 ; GET THE SECOND ROW ORL A,REG_SEL MOVX @DPTR,A MOV DPTR,#PORT_C ; POINT TO KEYPAD ROWS MOVX A,@DPTR ; READ THEM ORL A,#0FH ; MASK OFF UNUSED BITS CPL A MOV TEMP_KEY,A ; SAVE THE BYTE MOV DPTR,#KEYS+1 MOVX A,@DPTR ; GET PREVIOUS READING CJNE A,TEMP_KEY,NEW2 INC DPH ; POINT TO DEBOUNCED LOCATION MOVX @DPTR,A CLR NR2 READ3: MOV DPTR,#PORT_B ; POINT TO KEYPAD COLUMNS MOV A,#ROW3 ; GET THE THIRD ROW ORL A,REG_SEL MOVX @DPTR,A MOV DPTR,#PORT_C ; POINT TO KEYPAD ROWS MOVX A,@DPTR ; READ THEM ORL A,#0FH ; MASK OFF UNUSED BITS CPL A MOV TEMP_KEY,A ; SAVE THE BYTE MOV DPTR,#KEYS+2 MOVX A,@DPTR ; GET PREVIOUS READING CJNE A,TEMP_KEY,NEW3 INC DPH ; POINT TO DEBOUNCED LOCATION MOVX @DPTR,A CLR NR3 READ4: MOV DPTR,#PORT_B ; POINT TO KEYPAD COLUMNS MOV A,#ROW4 ; GET THE FOURTH ROW ORL A,REG_SEL MOVX @DPTR,A MOV DPTR,#PORT_C ; POINT TO KEYPAD ROWS MOVX A,@DPTR ; READ THEM ORL A,#0FH ; MASK OFF UNUSED BITS CPL A MOV TEMP_KEY,A ; SAVE THE BYTE MOV DPTR,#KEYS+3 MOVX A,@DPTR ; GET PREVIOUS READING CJNE A,TEMP_KEY,NEW4 INC DPH ; POINT TO DEBOUNCED LOCATION MOVX @DPTR,A CLR NR4 SJMP LoadKey $ EJECT NEW1: SETB NR1 ; NEW VALUE FOR ROW1 MOV A,TEMP_KEY MOVX @DPTR,A ; SAVE THE NEW VALUE INC DPH ; POINT TO DEBOUNCED LOCATION CLR A MOVX @DPTR,A SJMP READ2 NEW2: SETB NR2 ; NEW VALUE FOR ROW2 MOV A,TEMP_KEY MOVX @DPTR,A ; SAVE THE NEW VALUE INC DPH ; POINT TO DEBOUNCED LOCATION CLR A MOVX @DPTR,A SJMP READ3 NEW3: SETB NR3 ; NEW VALUE FOR ROW3 MOV A,TEMP_KEY MOVX @DPTR,A ; SAVE THE NEW VALUE INC DPH ; POINT TO DEBOUNCED LOCATION CLR A MOVX @DPTR,A SJMP READ4 NEW4: SETB NR4 ; NEW VALUE FOR ROW4 MOV A,TEMP_KEY MOVX @DPTR,A ; SAVE THE NEW VALUE INC DPH ; POINT TO DEBOUNCED LOCATION CLR A MOVX @DPTR,A $ EJECT LoadKey: ; UPDATE KEY READING REGISTER MOV SWITCH_BYTE,#0 JB NR1,Load2 ; STILL DEBOUNCING? MOV DPTR,#DEBOUNCED MOVX A,@DPTR ; GET KEY READING JZ Load2 ; NONE PRESSED MOV DPTR,#RC1-1 ; POINT TO CHAR STRINGS SJMP GET_C Load2: JB NR2,Load3 MOV DPTR,#DEBOUNCED+1 MOVX A,@DPTR ; GET KEY READING JZ Load3 ; NONE PRESSED MOV DPTR,#RC2-1 ; POINT TO CHAR STRINGS SJMP GET_C Load3: JB NR3,Load4 MOV DPTR,#DEBOUNCED+2 MOVX A,@DPTR ; GET KEY READING JZ Load4 ; NONE PRESSED MOV DPTR,#RC3-1 ; POINT TO CHAR STRINGS SJMP GET_C Load4: JB NR4,TIME1 MOV DPTR,#DEBOUNCED+3 MOVX A,@DPTR ; GET KEY READING JZ TIME1 ; NONE PRESSED MOV DPTR,#RC4-1 ; POINT TO CHAR STRINGS GET_C: SWAP A CJNE A,#10H,$+3 ; CHECK FOR OUT OF RANGE JNC TIME1 MOVC A,@A+DPTR ; GET BYTE MOV SWITCH_BYTE,A TIME1: ;* Any other function that needs to be executed every *; ;* 5 mS should be programmed here. *; AllDone: POP DPL ; Tail end of 5 mS interrupt POP DPH POP PSW POP ACC RETI $ EJECT ; ----------------- KEYPAD DEFINITIONS ------------------------ RC1: DB 'A33222211111111' RC2: DB 'B66555544444444' RC3: DB 'C99888877777777' RC4: DB 'D##0000********' 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. :1041000090E200F0751A19D51AFD90E000F090FBCE :10411000007488F090403C7402F0A37441F0A374E2 :1041200094F0D22790F9007518E0E518F0751A1E82 :1041300012418A743031BA3187743031BA743031F7 :10414000BA743831BA743831BA740831BA317F74FC :104150000631BA740C31BA90FA0074F0F090400B4A :104160007402F0A37441F0A374D7F0C28CE58A24E2 :104170007AF58A758CEC758911D28CD2A9D2AF757B :1041800018E075190131B2751A0A751BFAD51BFDB5 :10419000D51AF7227518C0B4200050147518E0B471 :1041A0000C0280DBB40D0474808005B40A2174C055 :1041B000F51990F900E518F0E51990F800F090F97C :1041C00000E518C2E7F0D2E7F0751B14D51BFD22FD :1041D000C28CC2A9C2AF22C0E0C0D0C083C082E5F9 :1041E0008A247AF58A758CEC90F90074C84518F029 :1041F00090FA00E0440FF4F51C904800E0B51C5E16 :104200000583F0C20090F90074C44518F090FA00DC :10421000E0440FF4F51C904801E0B51C4C0583F018 :10422000C20190F90074C24518F090FA00E0440F02 :10423000F4F51C904802E0B51C3A0583F0C20290E8 :10424000F90074C14518F090FA00E0440FF4F51C31 :10425000904803E0B51C280583F0C203802AD200F1 :10426000E51CF00583E4F0809CD201E51CF0058399 :10427000E4F080AED202E51CF00583E4F080C0D209 :1042800003E51CF00583E4F0751D0020000B904948 :1042900000E060059042D2802820010B904901E0A7 :1042A00060059042E1801A20020B904902E060050F :1042B0009042F0800C200312904903E0600C904281 :1042C000FFC4B41000500393F51DD082D083D0D02A :1042D000D0E0324133333232323231313131313167 :1042E000313142363635353535343434343434347E :1042F000344339393838383837373737373737373D :0F430000442323303030302A2A2A2A2A2A2A2A14 :00000001FF