; File: LCDKP1.A51 Date: 12/18/95 ; File: IOLCDKP4.A51 Date: 11/27/95 ; Original File: IOLCDKP@.A51 Date: 05/20/93 ; ; /* (c) Copyright BLUE EARTH RESEARCH, MANKATO, MN 1993, 1995 */ ; /* All rights reserved. */ ; ; Changed to use Timer1 instead of Timer0 for interrupt ***1*** $ TITLE(LCD/KEYPAD PRINT@ DRIVER FOR I/O-24) $ PW(99) PL(60) DATE(05-20-93) $ DEBUG ERRORPRINT XREF ; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ; º LCD DRIVER SOFTWARE FOR IMPLEMENTING 4x20 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 designed to use a 4 line 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. ; NOTE: Print a HT character "CHR$(9)," to go to line 3 ; Print a VT character "CHR$(11)," to go to line 4 ; 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 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Note that the sample program uses a single internal memory ; location for reading characters from the keypad. Since it is ; possible for more than one key to be pressed at a time, the ; keypad scan is stored in external memory locations 4900H-4903H ; for row1-row4, respectively. These memory locations will be ; zero if no key in the corresponding row is being pressed. ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; Troubleshooting hint: ; If your LCD module appears to reset properly but does not ; display characters, make sure that your LCD's contrast adjust ; is near maximum when it is at zero volts (ground). ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ $ EJECT ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ DEFINITIONS SPECIFIC TO THE SYSTEM WIRING ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; The following software assume that the LCD and Keypad are ; wired with all conections to Port A and C as follows: ; SIGNAL I/O-24 SIGNAL ; -------- ---------- -------- ; 13 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ 13 ; (14) DB7ÄÄÄÄÄÄÄÄÄÄÄ´ PA7 PA7 ÃÄÄÄÄÄÄÄÄÄÄCOL4 ; 25 ³ ³ 25 ; (13) DB6ÄÄÄÄÄÄÄÄÄÄÄ´ PA6 PA6 ÃÄÄÄÄÄÄÄÄÄÄCOL3 ; 12 ³ ³ 12 ; (12) DB5ÄÄÄÄÄÄÄÄÄÄÄ´ PA5 PA5 ÃÄÄÄÄÄÄÄÄÄÄCOL2 ; 24 ³ ³ 24 ; (11) DB4ÄÄÄÄÄÄÄÄÄÄÄ´ PA4 PA4 ÃÄÄÄÄÄÄÄÄÄÄCOL1 ; 10 ³ ³ 5 ; (6) EÄÄÄÄÄÄÄÄÄÄÄÄ´ PA1 PC7 ÃÄÄÄÄÄÄÄÄÄÄROW4 ; 22 ³ ³ 17 ; (4) RSÄÄÄÄÄÄÄÄÄÄÄ´ PA0 PC6 ÃÄÄÄÄÄÄÄÄÄÄROW3 ; 1 ³ ³ 4 ; (5) R/WÄÄÄÄÄÄÄÄÄÄÄ´ GND PC5 ÃÄÄÄÄÄÄÄÄÄÄROW2 ; 2 ³ ³ 16 ; (3) VeeÄÄÄÄÄÄÄÄÄÄÄ´ Vee PC4 ÃÄÄÄÄÄÄÄÄÄÄROW1 ; 1 ³ ³ ; (1) VssÄÄÄÄÄÄÄÄÄÄÄ´ GND ³ NOTE: Pull-up resistors ; 14 ³ ³ are needed on keypad ; (2) VccÄÄÄÄÄÄÄÄÄÄÄ´ +5V ³ Row inputs (PC4-PC7) ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; 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 1DH SWITCH_BYTE: DS 1 ; LAST KEY PRESSED TEMP_KEY: DS 1 ; TEMP BYTE FOR DEBOUNCING REG_SEL: DS 1 ; SELECT COMMAND OR DATA REG. BSEG AT 0 NR1: DBIT 1 ; SET WHEN NEW VALUE DETECTED NR2: DBIT 1 NR3: DBIT 1 NR4: DBIT 1 Eclk EQU ACC.1 SPACE EQU 20H CR EQU 0DH LF EQU 0AH FF EQU 0CH HT EQU 09H ; Horizontal tab VT EQU 0BH ; Vertical tab SO EQU 0EH SI EQU 0FH DC1 EQU 11H DC2 EQU 12H DLE EQU 10H EXEC_TIME EQU 20 ; INSTRUCTION EXECUTION TIME 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 1110$1100B ; MASK OFF EACH ROW ROW3 EQU 1101$1100B ROW2 EQU 1011$1100B ROW1 EQU 0111$1100B RESET EQU 0011$0000B ; "RESET" BYTE FUNCTION_SET EQU 0010$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" BYSTE CURSOR_OFF EQU 0000$1100B CURSOR_ON EQU 0000$1111B ; 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 LINE4 EQU 1101$0100B ; "GOTO LINE 4" *** NEW *** LINE3 EQU 1001$0100B ; "GOTO LINE 3" *** NEW *** 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" BLOCK EQU 1111$1111B ; Initialize the 82C55 Control Word as follows: ; PORT A = OUTPUT PORT C(0-3) = INPUT ; 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$1001B ; 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 A,#25 ; LOAD 50 uS LOOP COUNT DJNZ ACC,$ 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 REG_SEL,#0 ; OUTPUT TO COMMAND REGISTER MOV A,#30H ; Function Set (default 8-bit interface) ACALL Clock_N_Wait ; Clock and wait >120uS ACALL WAIT5mS ; Need to wait >5 mS the 1st time MOV A,#30H ; Function Set Again (default 8-bit interface) ACALL Clock_N_Wait ; (Actually 03H) MOV A,#30H ; Function Set Again (default 8-bit interface) ACALL Clock_N_Wait MOV A,#20H ; Function Set: Set 4-bit interface ACALL Clock_N_Wait MOV A,#28H ; Function Set: Still 4-bit, now 2 lines ACALL COMMAND MOV A,#08H ; Display Control: Display off, ACALL COMMAND ; Cursor off, Blink off ACALL CLEAR ; Clear Display (Code is #01H) MOV A,#06H ACALL COMMAND ; Entry mode: Increment (+1) MOV A,#0CH ACALL COMMAND ; Display Control: Display on ; ------------- SET UP TIMER1 INTERRUPT VECTOR ------------- ***1*** MOV DPTR,#401BH ; Stuff "LJMP XXXXH" into ***1*** MOV A,#2 ; mirrored Timer 1 overflow MOVX @DPTR,A ; vector at address 401BH. INC DPTR MOV A,#HIGH Timer1Int ; Location of Timer 1 ***1*** MOVX @DPTR,A ; interrupt routine. INC DPTR MOV A,#LOW Timer1Int ; ***1*** MOVX @DPTR,A ; ------------- SET UP TIMER1 FOR 5 mS INTERRUPT -------------- CLR TR1 ; STOP TIMER1 FOR NOW ***1*** MOV A,TL1 ; Reload Timer 1 for 5 mS ***1*** ADD A,#LOW -4998 ; (Less 2uS to compensate ***1*** MOV TL1,A ; for ADD & MOV latency.) ***1*** MOV TH1,#HIGH -4998 ; Timer 1 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 1 0 0 0 0 0 0 SETB TR1 ; Start Timer ***1*** ; IE: ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; ³ EA ³ EC ³ ET2 ³ ES ³ ET1 ³ EX1 ³ ET0 ³ EX0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 1 0 0 0 1 0 0 0 SETB ET1 ; Timer 1 interrupt enable ***1*** SETB EA ; Global interrupt enable ; Fall through to clear display and return to BASIC ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ DISPLAY WRITING SUBROUTINES ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; Clear the LCD display CLEAR: MOV A,#1 ; Clear display ACALL COMMAND WAIT5mS:MOV A,#10 ; Wait >5mS HERE: MOV B,#0FFH ; (5.5mS at 11.0592 Mhz) DJNZ B,$ DJNZ ACC,HERE 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. ; -------------- CHECK FOR NON-PRINTABLE CHARACTERS ------------- CHAR_OUTPUT: JB ACC.7,COMMAND ; Above 128 are LCD instructions MOV REG_SEL,#1 ; POINT TO DATA REGISTER CJNE A,#SPACE,$+3 ; CHECK FOR A JNC OUTPUT ; PRINTABLE CHAR MOV REG_SEL,#0 ; POINT TO CMD REGISTER ; Clear display if Form Feed. CJNE A,#FF,CR_Chk ; Form Feed? SJMP Clear ; Move the Cursor to the Home position if CR_Chk: CJNE A,#CR,LF_Chk ; Carriage return? MOV A,#LINE1 SJMP OUTPUT ; Move the Cursor to Line 2 if Line Feed LF_Chk: CJNE A,#LF,HT_Chk ; Line Feed? MOV A,#LINE2 SJMP OUTPUT ; Move the Cursor to Line 3 if Horizontal tab HT_Chk: CJNE A,#HT,CON_Chk ; Horizontal tab MOV A,#LINE3 SJMP COMMAND CON_Chk: CJNE A,#SO,COF_Chk ; Horizontal tab MOV A,#CURSOR_ON SJMP COMMAND COF_Chk: CJNE A,#SI,CLT_Chk ; Horizontal tab MOV A,#CURSOR_OFF SJMP COMMAND CLT_Chk: CJNE A,#DC1,CRT_Chk ; Horizontal tab MOV A,#CURSOR_LEFT SJMP COMMAND CRT_Chk: CJNE A,#DC2,DLE_Chk ; Horizontal tab MOV A,#CURSOR_RIGHT SJMP COMMAND DLE_Chk: CJNE A,#DLE,VT_Chk MOV A,#BLOCK SJMP DODATA ; Move the Cursor to Line 4 if Vertical tab VT_Chk: CJNE A,#VT,NoChar ; Vertical tab MOV A,#LINE4 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ DISPLAY WRITING SUBROUTINES ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ; ------ SUBROUTINE FOR SENDING A CHARACTER ------ ; SEND AN 8-BIT CHARACTER (OR COMMAND) TO THE LCD. COMMAND:MOV REG_SEL,#0 ; Set LCD to receive instruction SJMP OUTPUT DODATA: MOV REG_SEL,#1 ; Set LCD to receive data ; SEND AN 8-BIT CHARACTER (OR COMMAND) TO THE LCD. OUTPUT: MOV B,A ; SAVE IT ; ------------------ OUTPUT CHARACTER HALF -------------------- ANL A,#0F0H ; GET RID OF LOWER HALF ORL A,REG_SEL ; SELECT COMMAND OR DATA ACALL TOGGLE MOV A,B ; GET OUTPUT BYTE AGAIN ; ------------------- OUTPUT SECOND HALF ---------------------- SWAP A ; NOW DO LOWER HALF ANL A,#0F0H ORL A,REG_SEL ; SELECT COMMAND OR DATA CLOCK_N_WAIT: ACALL TOGGLE WAIT: MOV B,#60 ; Wait at least 120 uS DJNZ B,$ ; (130uS at 11.0592 Mhz) NoChar: RET ; Go Back ; ---------- SUBROUTINE FOR TOGGLING THE E SIGNAL ------------- TOGGLE: MOV DPTR,#PORT_A ; POINT TO DATA LINES PUSH IE CLR EA ; No Interrupts now MOVX @DPTR,A ; OUTPUT COMMAND OR DATA SETB Eclk MOVX @DPTR,A ; CLOCK IT IN CLR Eclk MOVX @DPTR,A POP IE ; Interrupts OK now RET ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ CLEAR TIMER1 INTERRUPT ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; STOP: CLR TR1 ; Stop Timer ***1*** CLR ET1 ; Timer 1 interrupt enable ***1*** CLR EA ; Global interrupt enable RET $ EJECT ; ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ; ³ TIMER1 INTERRUPT SERVICING ROUTINE ³ ; ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; Timer1Int: PUSH ACC ; 5 mS interrupt PUSH PSW PUSH DPH PUSH DPL MOV A,TL1 ; Reload Timer 1 for 5 mS ***1*** ADD A,#LOW -4998 ; (Less 2uS to compensate MOV TL1,A ; for ADD & MOV latency.) ***1*** MOV TH1,#HIGH -4998 ; ***1*** ; -------------------- SCAN THE KEYPAD ------------------------ MOV DPTR,#PORT_A ; 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 READ2: MOV DPTR,#PORT_A ; 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_A ; 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_A ; 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 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 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 ;*********************************************************************** ; ; THIS CODE ADDED TO ACCOMODATE A SONALERT BEEP WHEN A KEY IS PRESSED ; ;*********************************************************************** MOV DPTR,#OLD_KEY ; GET OLD KEY MOVX A,@DPTR CJNE A,SWITCH_BYTE,BEEP ; COMPARE NEW KEY WITH OLD KEY SJMP TIME1 BEEP: MOV A, SWITCH_BYTE ; STORE NEW KEY AS OLD KEY MOVX @DPTR,A MOV DPTR,#PORT_B ; POINT TO PORT B MOVX A, @DPTR ; GET THE VALUE OF PORTB PUSH ACC ; SAVE THE VALUE OF PORTB ORL A, #8 ; TURN ON THE SONALERT MOVX @DPTR,A MOV A,#15 ; TIME SONALERT ON LOOP: MOV B,#0FFH DJNZ B,$ DJNZ ACC,LOOP MOV DPTR,#PORT_B ; POINT TO PORTB POP ACC ; GET THE SAVED PORTB VALUE MOVX @DPTR,A ; TURN OFF THE SONALERT SJMP AllDone TIME1: MOV DPTR,#OLD_KEY ; A KEY IS NOT PRESSED MOV A, SWITCH_BYTE ; SO SAVE THE VALUE IN OLD_KEY MOVX @DPTR,A ;*********************************************************************** ;* 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 ; ----------------- KEYPAD DEFINITIONS ------------------------ RC1: DB 'ABBCCCCDDDDDDDD' RC2: DB '3669999########' RC3: DB '255888800000000' RC4: DB '1447777********' OLD_KEY: DS 1 ; HOLD THE LAST KEY PRESSED END