;安装1602液晶, 烧写程序后,把电脑的键盘 ;插入键盘接口。按键液晶则有显示.
PS2_CLK BIT P3.3 PS2_DATA BIT P3.4
LCD_RS BIT P2.0 ;LCD控制端口 LCD_RW BIT P2.1 LCD_EN BIT P2.2 LCD_X EQU 27H ;LCD 地址变量
KEY_DATA EQU 30H EXT1_NUM EQU 31H
BEEP BIT P3.3
RESET BIT 20H.0 H_SCAN BIT 20H.1 ;行扫描标志 SHIFT BIT 20H.3 ;SHIFT标志 BREAK_C BIT 20H.4 ;断码标志
;--------------------------------------------------- ORG 0000H JMP MAIN ORG 0013H JMP EXT1 ORG 0043H ;--------------------------------------------------- MAIN: MOV SP,#60H MOV P0,#0FFH MOV P2,#0FFH MOV P3,#0FFH
ACALL INIT_LCD ACALL SET_LCD1 ACALL SET_LCD2
MOV R5,#100 ;延时5S ACALL DELAY
MOV A,#01H ACALL WCOM ;清屏
MOV 20H,#00H MOV LCD_X,#00H MOV R1,#00H MOV R2,#00H MOV KEY_DATA,#00H
CLR IT1 ;外部中断1为低电平触发 SETB EA ;开总中断 SETB EX1 ;开外部中断1 DISP: JB RESET,MAIN ;程序热复位 JMP DISP ;---------------------------------------------------------- ;根据PS2的键值来查找其代码,并取得顺序码。 ;然后再根据顺序码来查找ASCII码。 ;入口: ;A PS2的键值 ;出口: ;A 键值的ASCII码 ;R3存放顺序码 ;---------------------------------------------------------- PS2KEY_D: MOV B,A MOV DPTR,#TABLE_D MOV R3,#0FFH KEY_IN1: INC R3 MOV A,R3 MOVC A,@A+DPTR CJNE A,B,KEY_IN2 MOV A,R3 ;找到,取顺序码 MOV DPTR,#TABLE_D_ASC ;根据顺序码来查找ASCII码 MOVC A,@A+DPTR RET KEY_IN2: CJNE A,#0FFH,KEY_IN1 ;末完,继续查 RET ;0FFH为结束码 ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PS2KEY_U: MOV B,A MOV DPTR,#TABLE_D MOV R3,#0FFH KEY_IN3: INC R3 MOV A,R3 MOVC A,@A+DPTR CJNE A,B,KEY_IN4 MOV A,R3 ;找到,取顺序码 MOV DPTR,#TABLE_U_ASC ;根据顺序码来查找ASCII码 MOVC A,@A+DPTR RET KEY_IN4: CJNE A,#0FFH,KEY_IN3 ;末完,继续查 RET ;0FFH为结束码 ;------------------------------------------------------ ;外部中断子程序 ;R1 中断次数计数 ;------------------------------------------------------ EXT1: CJNE R1,#00H,IN_LOOP ;跳过第一位启动位 JMP IN_LOOP3 IN_LOOP: CJNE R1,#09H,IN_LOOP1 ;2-9位为数据 IN_LOOP1: JNC IN_LOOP3 ;大于或等于9,转。 RR A ; JB PS2_DATA,IN_LOOP2 ;判数据是“1”,还是“0” ANL A,#7FH ;是“0”最高置位为0 JMP IN_LOOP3 IN_LOOP2: ORL A,#80H ;是“1”最高置位为1 IN_LOOP3: INC R1 ;中断计数 JNB PS2_CLK,$ ;等待PS2_CLK变高 IN_LOOP4: CJNE R1,#0BH,IN_LOOP5 ;一桢数据是否读完? IN_LOOP5: JNC IN_LOOP6 ;大于或等于11,转。 JMP EXT1_END IN_LOOP6: CJNE A,#0F0H,IN_LOOP6E ;断码是否开始 SETB BREAK_C ;置断码标志 MOV R1,#00H JMP EXT1_END IN_LOOP6E: CJNE A,#66H,IN_LOOP6A ;Back Space键功能 JB BREAK_C,IN_LOOP6F MOV R1,#00H MOV R4,LCD_X CJNE R4,#00H,IN_LOOP6G ;判是否到显示起始位 JMP EXT1_END IN_LOOP6G: DEC LCD_X ;删除前一位数 MOV A,#20H ACALL CONV1 ;有INC LCD_X指令 DEC LCD_X ;所以要再减一次 MOV A,#10H ;光标左移一格 ACALL WCOM JMP EXT1_END IN_LOOP6F: CLR BREAK_C MOV R1,#00H JMP EXT1_END
IN_LOOP6A: CJNE A,#12H,IN_LOOP6C ;左SHIFT JB BREAK_C,IN_LOOP6B MOV R1,#00H SETB SHIFT ;置SHIFT标志 JMP EXT1_END IN_LOOP6B: CLR SHIFT CLR BREAK_C MOV R1,#00H JMP EXT1_END IN_LOOP6C: CJNE A,#59H,IN_LOOP7 ;右SHIFT JB BREAK_C,IN_LOOP6D MOV R1,#00H SETB SHIFT JMP EXT1_END IN_LOOP6D: CLR SHIFT CLR BREAK_C MOV R1,#00H JMP EXT1_END IN_LOOP7: CJNE A,#71H,IN_LOOP8 ;DEL键功能,清屏。 JB BREAK_C,IN_LOOP7A MOV R1,#00H MOV A,#01H ACALL WCOM MOV 20H,#00H ;清所有的标志 MOV LCD_X,#00H ; JMP EXT1_END IN_LOOP7A: CLR BREAK_C MOV R1,#00H JMP EXT1_END IN_LOOP8: CJNE A,#5AH,IN_LOOP9 ;ENTER键功能,换行。 JB BREAK_C,IN_LOOP8C MOV R1,#00H CPL H_SCAN ;换行取反 JNB H_SCAN,IN_LOOP8A MOV A,#0C0H ;设置 LCD 的第二行地址 ACALL WCOM ACALL CLR_LINE ;清第二行的内容 MOV A,#0C0H ;设置 LCD 的第二行地址 ACALL WCOM MOV LCD_X,#00H JMP IN_LOOP8B IN_LOOP8A: MOV A,#80H ;设置 LCD 的第一行地址 ACALL WCOM ACALL CLR_LINE ;清第一行的内容 MOV A,#80H ;设置 LCD 的第一行地址 ACALL WCOM MOV LCD_X,#00H IN_LOOP8B: JMP EXT1_END IN_LOOP8C: CLR BREAK_C MOV R1,#00H JMP EXT1_END IN_LOOP9: CJNE A,#05H,IN_LOOPA ;F1 帮助键功能 JB BREAK_C,IN_LOOP9A MOV R1,#00H ACALL SET_LCD3 ACALL SET_LCD4 JMP EXT1_END IN_LOOP9A: CLR BREAK_C MOV R1,#00H JMP EXT1_END IN_LOOPA: CJNE A,#76H,IN_LOOPB ;ESC键功能 SETB RESET ;置复位标志 JMP EXT1_END IN_LOOPB: CLR EX1 ;关中断,准备显示 MOV R1,#00H JB SHIFT,IN_LOOPBA ACALL PS2KEY_D CJNE A,#0FFH,IN_LOOPC ;没有定义的键不显示 JMP IN_LOOPD IN_LOOPBA: ACALL PS2KEY_U CJNE A,#0FFH,IN_LOOPC ;没有定义的键不显示 JMP IN_LOOPD IN_LOOPC: ACALL CONV1 ACALL BEEP_BL IN_LOOPD: SETB EX1 ;显示完毕,开中断 EXT1_END: RETI ;---------------------------------------------------------- ;PS2键值表(下行键) ;---------------------------------------------------------- TABLE_D: DB 1CH,32H,21H,23H,24H,2BH,34H,33H,43H,3BH,42H DB 4BH,3AH,31H,44H,4DH,15H,2DH,1BH,2CH,3CH,2AH DB 1DH,22H,35H,1AH ;A-Z
DB 45H,16H,1EH,26H,25H,2EH DB 36H,3DH,3EH,46H ;0-9
DB 0EH,4EH,55H,5DH,29H,54H DB 5BH,4CH,52H,41H,49H,4AH ;,71H
DB 70H,69H,72H,7AH,6BH ;右边数字键 DB 73H,74H,6CH,75H,7DH ;0-9
DB 0FFH ;---------------------------------------------------------- ;键值的ASCII码 (下行键) ;---------------------------------------------------------- TABLE_D_ASC: DB 61H,62H,63H,64H,65H,66H,67H,68H,69H,6AH,6BH DB 6CH,6DH,6EH,6FH,70H,71H,72H,73H,74H,75H,76H DB 77H,78H,79H,7AH ;A-Z
DB 30H,31H,32H,33H,34H,35H DB 36H,37H,38H,39H ;0-9
DB 60H,2DH,3DH,0A4H,20H,5BH DB 5DH,3BH,27H,2CH,2EH,2FH ;,2EH
DB 30H,31H,32H,33H,34H,35H ;右边数字键 DB 36H,37H,38H,39H ;0-9
DB 0FFH ;********************************************************** ;上行键ASCII码表 ;********************************************************** TABLE_U_ASC: DB 41H,42H,43H,44H,45H,46H,47H,48H,49H,4AH,4BH DB 4CH,4DH,4EH,4FH,50H,51H,52H,53H,54H,55H,56H DB 57H,58H,59H,5AH ;A-Z
DB 29H,21H,40H,23H,24H,25H,5EH,26H,2AH,28H ;0-9上行键
DB 5CH,5FH,2BH,7CH,20H,7BH,7DH,3AH,22H,3CH,3EH,3FH ;,2EH
DB 30H,31H,32H,33H,34H,35H ;右边数字键 DB 36H,37H,38H,39H ;0-9 ;-------------------------------------------------------- ;LCD初始化显示子程序 ;-------------------------------------------------------- SET_LCD1: MOV DPTR,#LMESS1 ;指针指到显示信息1 MOV A,#1 ;显示在第一行 CALL LCD_PRINT RET SET_LCD2: MOV DPTR,#LMESS2 ;指针指到显示信息2 MOV A,#2 ;显示在第二行 CALL LCD_PRINT RET LMESS1: DB " PS2 KEYBOARD ",0 ;LCD 第一行显示 LMESS2: DB " DEMO PROGRAM ",0 ;LCD 第二行显示
SET_LCD3: MOV DPTR,#LMESS3 ;指针指到显示信息1 MOV A,#1 ;显示在第一行 CALL LCD_PRINT RET SET_LCD4: MOV DPTR,#LMESS4 ;指针指到显示信息2 MOV A,#2 ;显示在第二行 CALL LCD_PRINT RET LMESS3: DB " WELCOME TO ",0 ;LCD 第一行显示 LMESS4: DB " WWW.WILLAR.COM ",0 ;LCD 第二行显示 ;-------------------------------------------------------- ;LCD 初始化子程序
;8位数据传送方式,双行显示,字形5*7点阵。 ;开显示,显示光标并闪动。 ;-------------------------------------------------------- INIT_LCD: CALL DELAY5MS ;延时15MS CALL DELAY5MS CALL DELAY5MS ;等待LCD电源稳定 MOV A,#38H ;双行显示,字形5*7点阵,8位数据。 CALL WCOM_NC ;不检测忙信号 CALL DELAY5MS MOV A,#38H ;双行显示,字形5*7点阵 CALL WCOM_NC ;不检测忙信号 CALL DELAY5MS MOV A,#38H ;双行显示,字形5*7点阵 CALL WCOM_NC ;不检测忙信号 CALL DELAY5MS
MOV A,#38H ;双行显示,字形5*7点阵 CALL WCOM ;检测忙信号 CALL DELAY5MS MOV A,#0FH ;开显示,显示光标,光标闪烁。 CALL WCOM CALL DELAY5MS MOV A,#01H ;清除 LCD 显示屏 CALL WCOM CALL DELAY5MS RET ; --------------------------------------------------------- ;LCD 显示子程序 ; ;H_SCAN 行扫描标志 ;---------------------------------------------------------- CONV1: JB H_SCAN,CONV3 ; CONV2: MOV B,LCD_X ACALL LCDP1 INC LCD_X MOV R0,LCD_X CJNE R0,#10H,CONV_END ;一行显示完否? SETB H_SCAN MOV LCD_X,#00H ;设置显示起始位置 JMP CONV_END CONV3: MOV B,LCD_X ACALL LCDP2 INC LCD_X MOV R0,LCD_X CJNE R0,#11H,CONV_END ;一行显示完否 CLR H_SCAN MOV A,#01H ;清屏 ACALL WCOM MOV LCD_X,#00H ;设置显示起始位置 CONV_END: RET ;-------------------------------------------------------- ;清屏子程序 ;-------------------------------------------------------- ;CLR_DISP: MOV A,#80H ;设置 LCD 的第一行地址 CALL WCOM ;写入命令 CALL CLR_LINE ;清除该行字符数据 MOV A,#0C0H ;设置 LCD 的第二行地址 CALL WCOM ;写入命令 CALL CLR_LINE ;清除该行字符数据 RET ;-------------------------------------------------------- ;在LCD的第一行显示字符 ;-------------------------------------------------------- LCDP1: PUSH ACC ;入栈保护 MOV A,B ;设置显示地址 ADD A,#80H ;设置LCD的第二行地址 CALL WCOM ;写入命令 POP ACC ;由堆栈取出A CALL WDATA ;写入数据 RET
;-------------------------------------------------------- ;在LCD的第二行显示字符 ;-------------------------------------------------------- LCDP2: PUSH ACC ;入栈保护 MOV A,B ;设置显示地址 ADD A,#0C0H ;设置LCD的第二行地址 CALL WCOM ;写入命令 POP ACC ;由堆栈取出A CALL WDATA ;写入数据 RET ;-------------------------------------------------------- ;在LCD的第一行或第二行显示字符 ;-------------------------------------------------------- LCD_PRINT: CJNE A,#1,LINE2 ;判断是否为第一行 LINE1: MOV A,#80H ;设置 LCD 的第一行地址 CALL WCOM ;写入命令 CALL CLR_LINE ;清除该行字符数据 MOV A,#80H ;设置 LCD 的第一行地址 CALL WCOM ;写入命令 JMP FILL LINE2: MOV A,#0C0H ;设置 LCD 的第二行地址 CALL WCOM ;写入命令 CALL CLR_LINE ;清除该行字符数据 MOV A,#0C0H ;设置 LCD 的第二行地址 CALL WCOM FILL: CLR A ;填入字符 MOVC A,@A+DPTR ;由信息区取出字符 CJNE A,#00H,LC1 ;判断是否为结束码 RET LC1: CALL WDATA ;写入数据 INC DPTR ;指针加1 JMP FILL ;继续填入字符 RET ;-------------------------------------------------------- ;清除 LCD 指定行的字符 ;“空白”的ASCII代码为20H。 ;-------------------------------------------------------- CLR_LINE: MOV R0,#24 CL1: MOV A,#20H ;' ' CALL WDATA DJNZ R0,CL1 RET ;-------------------------------------------------------- ;写控制指令子程序
;写控制指令到LCD ;传入参数: ACC(要写入的指令) ;RS=L,RW=L,E=高脉冲,D0-D7=指令码 。 ;-------------------------------------------------------- WCOM: ACALL CHECKBUSY WCOM_NC: MOV P0,A ;写入指令 CLR LCD_EN NOP NOP CLR LCD_RS CLR LCD_RW SETB LCD_EN ACALL DEL_250 CLR LCD_EN RET ;-------------------------------------------------------- ;写数据子程序
;写显示数据到LCD ;传入参数: ACC(要写入的数据) ;RS=H,RW=L,E=高脉冲,D0-D7=数据码 。 ;-------------------------------------------------------- WDATA: ACALL CHECKBUSY MOV P0,A ;写入数据 CLR LCD_EN NOP NOP SETB LCD_RS CLR LCD_RW SETB LCD_EN CALL DEL_250 CLR LCD_EN RET
DEL_250: MOV R7,#125 ;延时250微秒 DJNZ R7,$ RET ;-------------------------------------------------------- ;检测LCD控制器忙碌状态
;正常读写操作之前必须检测LCD控制器状态 ;BUSY FLAG(P0.7)=1时,忙,不能接收MCU送来的指令和数据。 ;BUSY FLAG(P0.7)=0时,闲,能够接收MCU送来的指令和数据。 ;读数据时 ;RS=L,RW=H,E=H,输出:D0-D7=数据 ;-------------------------------------------------------- CHECKBUSY: PUSH ACC MOV P0,#0FFH ;置P0口为输入状态 CLR LCD_EN NOP NOP SETB LCD_RW CLR LCD_RS SETB LCD_EN BUSYLOOP: NOP JB P0.7,BUSYLOOP CLR LCD_EN POP ACC RET ;--------------------------------------------------------- ;延时50MS子程序 ;--------------------------------------------------------- DELAY50MS: MOV R6,#100 DEL2: MOV R7,#250 DJNZ R7,$ DJNZ R6,DEL2 RET ;-------------------------------------------------------- ;延时5MS子程序 ;-------------------------------------------------------- DELAY5MS: MOV R6,#25 DEL3: MOV R7,#100 DJNZ R7,$ DJNZ R6,DEL3 RET ;=================================================== ; ;蜂鸣器响一声子程序 ; ;=================================================== BEEP_BL: MOV R6,#100 BL1: CALL DEX1 CPL BEEP ;P3.7取反 DJNZ R6,BL1 MOV R5,#8 ;修改此参数可以调整键盘响应速度 CALL DELAY RET DEX1: MOV R7,#180 DEX2: NOP DJNZ R7,DEX2 RET DELAY: ;延时R5*20MS MOV R6,#50 D1: MOV R7,#200 DJNZ R7,$ DJNZ R6,D1 DJNZ R5,DELAY RET ;---------------------------------------------------------- END
|