.486
DATA SEGMENT USE16
ARY DB 1BH,?,?
DATA ENDS
CODE SEGMENT USE16
ASSUME DS:DATA, CS:CODE
START:
;装载数据段
MOV AX,DATA
MOV DS,AX
;将SI指向数组头
LEA SI,ARY
;取高4位即逻辑右移4位,高位补零
MOV AL,[SI]
SHR AL,4
MOV [SI+1],AL
;取第四位即高位与0相与
MOV AL,[SI]
AND AL,0FH
MOV [SI+2],AL
;返回DOS
MOV AH,4CH
INT 21H
CODE ENDS
END START
.486
DATA SEGMENT USE16
A DB 03H
B DB 03H
C DB 03H
K DB ?
DATA ENDS
CODE SEGMENT USE16
ASSUME DS:DATA, CS:CODE
START:
;装载数据段
MOV AX,DATA
MOV DS,AX
;CMP指令不能两个操作数都是存储器,将B放入BL,C放入BH
MOV BL,B
MOV BH,C
;若A=B则跳转到 AeqB
CMP A,BL
JE AeqB
;若B=C则跳转到 K1
CMP BL,C
JE K1
;若C=A则跳转到 K1,否则跳转到K0
CMP A,BH
JE K1
JMP K0
;若B=C则跳转到K2,否则跳转到K1
AeqB: CMP BL,BH
JE K2
JMP K1
K0:
MOV K,0
JMP DONE
K1:
MOV K,1
JMP DONE
K2:
MOV K,2
;返回DOS
DONE:
MOV AH,4CH
INT 21H
CODE ENDS
END START
.486
DATA SEGMENT USE16
A DB 10H
B DB 11H
C DB 12H
N DB ?
DATA ENDS
CODE SEGMENT USE16
ASSUME DS:DATA, CS:CODE
START:
;装载数据段
MOV AX,DATA
MOV DS,AX
;由于CMP两个操作数不能都为立即数,故将B存到BL
MOV BL,B
;比较A与B的大小
CMP A,BL
;若A<=B则跳转到BbiggerA
JNA BbiggerA
;不跳转则完成A-B+C,结果保存到变量N
MOV AL,A
SUB AL,B
ADD AL,C
MOV N,AL
JMP DONE
BbiggerA:
;完成A+B,结果保存到变量N
MOV AL,A
ADD AL,B
MOV N,AL
;返回DOS
DONE:
MOV AH,4CH
INT 21H
CODE ENDS
END START
循环
.486
DATA SEGMENT USE16
STRN DB '1234$'
LEN EQU $-STRN
N DB ?
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE
START:
;装载数据段
MOV AX,DATA
MOV DS,AX
;使用AL来计次,将SI指向字符串头,将数组长度LEN即循环次数存入CX
MOV AL,0
LEA SI,STRN
MOV CX,LEN
TRY:
;取出当前SI所指向的字符,与自身相与,值不变,根据PF的改变判断1个数的奇偶
MOV BL,[SI]
AND BL,BL
;若PF=1,即偶数个1,则无需改变,跳转到 NEXT
JP NEXT
;若PF=0,即奇数个1,则令最高位为1,即与80H相或
OR BL,80H
;将加上偶校验位的值覆盖原值,并将计数+1
MOV [SI],BL
INC AL
NEXT:
;SI自增1,即指向字符串的下一个字符
INC SI
;循环重复之前的步骤
LOOP TRY
;最终结果保存在变量N中
MOV N,AL
MOV AH, 4CH
INT 21H
CODE ENDS
END START
.486
DATA SEGMENT USE16
N DB ?
FIRST DB 01H, 03H, 20 DUP(2), 00H, 05H, 00H, 74 DUP(4), 0AAH
LEN EQU $-FIRST
ZERO DB 00H
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE, DS:DATA
START:
MOV AX,DATA
MOV DS,AX
LEA SI,FIRST
MOV CX,LEN
MOV AL,0
DO:
MOV BL,[SI]
CMP BL, ZERO
JZ DONE
INC AL
INC SI
LOOP DO
DONE:
MOV N, AL
MOV AH,4CH
INT 21H
CODE ENDS
END START
子程序
.486
DATA SEGMENT USE16
BUF DB 5 DUP(3AH), 2 DUP(0F2H), 3 DUP(79H)
LEN EQU $-BUF
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE
START:
;装载数据段
MOV AX, DATA
MOV DS, AX
;将SI指向字符串头,字符串长度存入CX
LEA SI, BUF
MOV CX, LEN
TRY:
;先转换高4位并显示
MOV AL, [SI]
SHR AL, 4
CALL HEXASC
MOV AH, 02H
INT 21H
;再转换低四位并显示
MOV AL, [SI]
AND AL, 0FH
CALL HEXASC
MOV AH, 02H
INT 21H
;每显示一个字节的两个字符后就显示一个空格
MOV DL, 20H
MOV AH, 02H
INT 21H
;循环重复上面步骤
INC SI
LOOP TRY
DONE:
MOV AH, 4CH
INT 21H
HEXASC PROC NEAR
;加上30H后如果大于'9'的ASCII码39H,则表示要显示的字符是字母
PUSH AX
ADD AL, 30H
CMP AL, 39H
JA NotNum
MOV DL, AL
JMP RE
;则再加上07H得到字母的ASCII码
NotNum:
ADD AL, 07H
MOV DL, AL
RE:
POP AX
RET
HEXASC ENDP
CODE ENDS
END START
.486
DATA SEGMENT USE16
X DB 'x'
BUF DB 20
N DB 0
TB DB 20 DUP(0)
DATA ENDS
MAIN SEGMENT USE16
ASSUME DS:DATA, CS:MAIN
START:
;装载数据段
MOV AX, DATA
MOV DS, AX
;输入字符串
LEA DX, BUF
MOV AH, 0AH
INT 21H
;换行
MOV DL, 0AH
MOV AH, 02H
INT 21H
;显示X
MOV DL, X
MOV AH, 02H
INT 21H
;显示空格
MOV DL, 20H
MOV AH, 02H
INT 21H
;通过堆栈传递参数
LEA BX, TB
PUSH BX
LEA BX, N
PUSH BX
LEA BX, X
PUSH BX
;调用子程序
CALL FAR PTR CountX
;加上30H或37H转换为ASCII码,显示结果
ADD DL, 30H
CMP DL, 39H
JA NotNum
JMP SOUT
;如果大于39H,则再加上07H得到字母的ASCII码
NotNum:
ADD DL, 07H
SOUT:
MOV AH, 02H
INT 21H
;结束程序
MOV AH, 4CH
INT 21H
MAIN ENDS
SPRO SEGMENT USE16
ASSUME DS:DATA, CS:SPRO
CountX PROC FAR
;保护现场
PUSH SI
PUSH BP
PUSH CX
PUSH AX
;将堆栈中的传递的参数赋值给寄存器,BP指向栈顶,CX为字符串长度N,AL保存'x'的ASCII码,AH保存当前指向的字符,DL用来计次
MOV BP, SP
MOV DL, 0
;MOV CX, [BP+14]这只能拿到N在DS中的偏移量
MOV SI, [BP+14]
MOV CL, [SI]
MOV SI, [BP+12]
MOV AL, [SI]
MOV SI, [BP+16]
MOV AH, [SI]
AGAIN:
CMP AH, AL
JNE LP
INC DL
LP:
INC SI
MOV AH, [SI]
LOOP AGAIN
;还原现场
POP AX
POP CX
POP BP
POP SI
;还原传递参数占用的堆栈
RET 6
CountX ENDP
SPRO ENDS
END START
DOS
.486
DATA SEGMENT USE16
STRN DB 3
LEN DB 0
BUF DB 3 DUP(0)
WRN DB 0AH, 'ERROR', 0AH, '$'
SUCC DB 0AH, 'RIGHT', 0AH, '$'
FLAG DB ?
DATA ENDS
CODE SEGMENT USE16
ASSUME DS:DATA, CS:CODE
START:
;load
MOV AX, DATA
MOV DS, AX
INP:
;检查到错误则将FLAG=0
MOV FLAG, 1
;input
LEA DX, STRN
MOV AH, 0AH
INT 21H
;将输入的两个字符分别存入BL,BH
LEA SI, BUF
MOV BL, [SI]
MOV BH, [SI+1]
;调用子程序判断BL中是否是数字,不是则FLAG=0
CALL ISNUM
;根据FLAG=0来判断输入是否正确。不正确,则跳转到 ER
MOV AL, FLAG
CMP AL, 0
JE ER
;调用子程序判断BH中是否是字母,不是则FLAG=0
CALL ISLET
;根据FLAG=0来判断输入是否正确。不正确,则跳转到 ER
MOV AL, FLAG
CMP AL, 0
JE ER
;没有发生错误则跳到RIG
JMP RIG
ER:
;输出'ERROR'并换行,跳转回输入语句实现循环输入
LEA DX, WRN
MOV AH, 09H
INT 21H
JMP INP
RIG:
;输出 'right'
LEA DX, SUCC
MOV AH, 09H
INT 21H
DONE:
MOV AH, 4CH
INT 21H
;无法在子程序中跳转到主程序的标号,标号仅在子程序内部有效!
ISNUM PROC NEAR
;判断BL是否属于'0'~'9'
CMP BL, 30H
JB OT1
CMP BL, 39H
JA OT1
JMP RE1
OT1:
MOV FLAG, 0
RE1:
RET
ISNUM ENDP
ISLET PROC NEAR
;判断BH是否为字母
;A-Z
CMP BH, 41H
JB OT2
CMP BH, 5AH
JA LOWER
JMP RE2
;a-z
LOWER:
CMP BH, 61H
JB OT2
CMP BH, 7AH
JA OT2
JMP RE2
OT2:
MOV FLAG, 0
RE2:
RET
ISLET ENDP
CODE ENDS
END START
.486
DATA SEGMENT USE16
DIGIT DB 0, 0AH,'$'
LETTER DB 0, 0AH,'$'
OTHER DB 0, 0AH,'$'
STRN DB 50
LEN DB 0
BUF DB 50 DUP(0)
AC_TAB DB '0123456789ABCDEF'
OUT1 DB 0AH,'digit:','$'
OUT2 DB 'letter:','$'
OUT3 DB 'other:','$'
DATA ENDS
CODE SEGMENT USE16
ASSUME DS:DATA, CS:CODE
START:
;装载数据段
MOV AX, DATA
MOV DS, AX
;输入字符串
LEA DX, STRN
MOV AH, 0AH
INT 21H
LEA SI, BUF
MOV CL, LEN
MOV CH, 0
;遍历字符串
LP:
MOV BL, [SI]
;对每个字符调用子程序
CALL COUNT
INC SI
LOOP LP
RESULT:
;使用XLAT查询结果数字的ASCII码,将结果覆盖原来的数字
LEA BX, AC_TAB
MOV AL, DIGIT
XLAT
MOV DIGIT, AL
;先显示说明语句
LEA DX, OUT1
MOV AH, 09H
INT 21H
;再显示结果数字
LEA DX, DIGIT
MOV AH, 09H
INT 21H
;同上
MOV AL, LETTER
XLAT
MOV LETTER, AL
LEA DX, OUT2
MOV AH, 09H
INT 21H
LEA DX, LETTER
MOV AH, 09H
INT 21H
MOV AL, OTHER
XLAT
MOV OTHER, AL
LEA DX, OUT3
MOV AH, 09H
INT 21H
LEA DX, OTHER
MOV AH, 09H
INT 21H
DONE:
MOV AH, 4CH
INT 21H
COUNT PROC NEAR
NUM:
CMP BL, 30H
JB OTH
CMP BL, 39H
JA UPPER
INC DIGIT
JMP RE
UPPER:
CMP BL, 41H
JB OTH
CMP BL,5AH
JA LOWER
INC LETTER
JMP RE
LOWER:
CMP BL, 61H
JB OTH
CMP BL, 7AH
JA OTH
INC LETTER
JMP RE
OTH:
INC OTHER
RE:
RET
COUNT ENDP
CODE ENDS
END START
8254
.486
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
;在此定义数据变量
;
START:
;写控制字
MOV DX, 30CH
MOV AL, 00010110B ;通道0 只读写低字节 方式3 二进制方式
OUT DX, AL
;写计数初值
MOV DX, 300H
MOV AL, 47D ;1KHZ闪烁
;MOV AL, 470D ;100HZ
OUT DX, AL
WT:
JMP WT
CODE ENDS
END BEG
.486
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
START:
;写控制字
MOV DX, 30CH
MOV AL, 01010110B ;通道1 只读写低字节 方式3 二进制方式
OUT DX, AL
;写通道1的计数初值
MOV DX, 304H
MOV AX, 1860D ;20ms * 93KHZ
OUT DX, AL
MOV AL, AH
OUT DX, AL
;写控制字
MOV DX, 30CH
MOV AL, 00010110B ;通道0 只读写低字节 方式3 二进制方式
OUT DX, AL
;写通道0的计数初值
MOV DX, 300H
MOV AL, 50D ;50次
OUT DX, AL
WT:
JMP WT
CODE ENDS
END BEG
.486
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
START:
MOV DX, 30CH
MOV AL, 10110010B
OUT DX, AL
MOV DX, 308H
MOV AX,60000D
OUT DX, AL
MOV AL, AH
OUT DX, AL
WT:
JMP WT
CODE ENDS
END BEG
8255
.486
PORTA EQU 300H
PORTB EQU 304H
PORTC EQU 308H
CTRL_8255 EQU 30CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
START:
MOV DX, CTRL_8255
MOV AL, 10000000B ;C口高低位输出
OUT DX, AL
MOV AL, 10101010B
LP:
MOV DX, PORTC
OUT DX, AL
ROL AL, 1 ;循环左移实现亮灭交替
CALL DLY_L
JMP LP
WT: JMP WT
DLY_L PROC
PUSH ECX
MOV ECX, 2FFFFH
DLYS_AGN:
NOP
NOP
LOOP DLYS_AGN
POP ECX
RET
DLY_L ENDP
CODE ENDS
END START
.486
PORTA EQU 300H
PORTB EQU 304H
PORTC EQU 308H
CTRL_8255 EQU 30CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
START:
MOV DX, CTRL_8255
MOV AL, 10000010B ;C口方式0输出 B口方式0输入
OUT DX, AL
LP:
MOV DX, PORTB
IN AL, DX ;读取开关状态
MOV BL, AL
MOV BH, 0 ;BH记录BL中1的个数
TEST BL, 00001000B
JNZ WT ;K4为1时,程序结束
CNT:
AND BL, BL
JZ PNT ;全为0则表示全部移位完成,跳到输出
SHL BL,1
JC YS ;移出来的是1则计数+1,否则直接进行下一次位移
JMP CNT
YS:
INC BH
JMP CNT
PNT:
MOV AL, BH
NOT AL
MOV DX, PORTC
OUT DX, AL
JMP LP
WT: JMP WT
CODE ENDS
END START
.486
PORTA EQU 300H
PORTB EQU 304H
PORTC EQU 308H
CTRL EQU 30CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
FLAG DB ?
START:
;写控制字
MOV DX, CTRL
MOV AL, 10000010B ;C口输出 B口方式0输入
OUT DX, AL
CASE:
;开关状态存在BL中,根据读取到的开关状态跳转到不同的分支
MOV DX, PORTB
IN AL, DX
MOV BL, AL
CMP BL, 00000001B
JE MD_ONE
CMP BL, 00000011B
JE MD_TWO
CMP BL, 00000111B
JE MD_THREE
CMP BL, 00001111B
JE MD_FOUR
CMP BL, 00011111B
JE MD_FIVE
CMP BL, 00111111B
JE MD_SIX
CMP BL, 01111111B
JE MD_SEVEN
CMP BL, 11111111B
JE DN
JMP CASE
MD_ONE:
;灯亮情况和开关情况电平相反
MOV AL, BL
NOT AL
AGN_ONE:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 1
CALL CHANGED ;如果灯亮循环过程中开关状态变化,则重新判断对应的分支
CMP FLAG, 1
JE CASE
JMP AGN_ONE
MD_TWO:
MOV AL, BL
NOT AL
AGN_TWO:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 2
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP AGN_TWO
MD_THREE:
MOV AL, BL
NOT AL
AGN_THREE:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 3
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP AGN_THREE
MD_FOUR:
MOV AL, BL
NOT AL
AGN_FOUR:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 4
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP AGN_FOUR
MD_FIVE:
MOV AL, BL
NOT AL
AGN_FIVE:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 5
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP AGN_FIVE
MD_SIX:
MOV AL, BL
NOT AL
AGN_SIX:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 6
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP AGN_SIX
MD_SEVEN:
MOV AL, BL
NOT AL
AGN_SEVEN:
MOV DX, PORTC
CALL DLY_L
CALL DLY_L
OUT DX, AL
ROL AL, 7
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP AGN_SEVEN
DN:
MOV DX, PORTC
MOV AL, 0FFH
OUT DX, AL
WT:
JMP WT
CHANGED PROC
PUSH AX
MOV FLAG, 0
MOV DX, PORTB
IN AL, DX
CMP BL, AL
JE DONE
MOV FLAG, 1
DONE:
POP AX
RET
CHANGED ENDP
DLY_L PROC
PUSH ECX
MOV CX, 0FFFFH
DLYS_AGN:
NOP
NOP
LOOP DLYS_AGN
POP ECX
RET
DLY_L ENDP
CODE ENDS
END BEG
LED
.486
PORTA EQU 320H
PORTB EQU 324H
PORTC EQU 328H
CTRL EQU 32CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
;
START:
MOV DX, CTRL
MOV AL, 10000000B; A接段选,B接位选
OUT DX, AL
;送段选
MOV AL, 7FH
MOV DX, PORTA
OUT DX ,AL
SET:
;送位选
MOV AH, 00100000B
LP:
MOV AL, AH
MOV DX, PORTB
OUT DX, AL
;长延时
CALL DLY_L
;位选右移
SHR AH, 1
;若1被移出则从头开始
JC SET
JMP LP
WT: JMP WT
DLY_L PROC
PUSH CX
MOV CX, 0FFH
DLYS_AGN:
NOP
NOP
LOOP DLYS_AGN
POP CX
RET
DLY_L ENDP
CODE ENDS
END BEG
.486
PORTA EQU 320H
PORTB EQU 324H
PORTC EQU 328H
CTRL EQU 32CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
MESS DB 06H, 5BH, 4FH, 0E6H, 6DH, 7DH;字形码
START:
LEA SI, MESS
;位选预置数
MOV AH, 00100000B
;控制字
MOV AL, 10000000B; A接段选,B接位选
MOV DX, CTRL
OUT DX, AL
LP:
;先送段选
MOV AL, [SI]
MOV DX, PORTA
OUT DX, AL
;再送位选
MOV AL, AH
MOV DX, PORTB
OUT DX ,AL
;延时
CALL DLY_L
;位选右移
SHR AH, 1
JC START
INC SI
JMP LP
WT:
JMP WT
DLY_L PROC
PUSH CX
MOV CX, 0FFH
DLYS_AGN:
NOP
NOP
LOOP DLYS_AGN
POP CX
RET
DLY_L ENDP
CODE ENDS
END BEG
.486
PORTA EQU 320H
PORTB EQU 324H
PORTC EQU 328H
CTRL EQU 32CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
MESS DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH;字形码
DISP DB 2,0,1,9,3,8,1,8
START:
;控制字
MOV AL, 10000000B; A接段选,B接位选
MOV DX, CTRL
OUT DX, AL
DIS:
LEA SI, DISP
LEA BX, MESS
;位选预置数
MOV AH, 10000000B
LP:
;送段选
MOV AL, [SI]
XLAT
MOV DX, PORTA
OUT DX, AL
;送位选
MOV AL, AH
MOV DX, PORTB
OUT DX, AL
SHR AH, 1
JC DIS
INC SI
JMP LP
WT: JMP WT
DLY_L PROC
PUSH CX
MOV CX, 0FFH
DLYS_AGN:
NOP
NOP
LOOP DLYS_AGN
POP CX
RET
DLY_L ENDP
CODE ENDS
END BEG
.486
PORTA EQU 320H
PORTB EQU 324H
PORTC EQU 328H
CTRL EQU 32CH
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
BEG:
JMP START
MESS DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH;字形码
DISP DB 2,0,1,9,3,8,1,8
FLAG DB ?
START:
;控制字
MOV AL, 10001001B; A接段选,B接位选,C读开关
MOV DX, CTRL
OUT DX, AL
CASE:
;读开关
MOV DX, PORTC
IN AL, DX
MOV BL, AL
MOV CH, AL;CH存开关状态
TEST BL, 10000000B
JNZ C3
CMP BL, 00000001B
JE C1
CMP BL, 00000010B
JE C2
JMP C4
C1:
;送段选 '8'
MOV AL, 7FH
MOV DX, PORTA
OUT DX, AL
;送位选
MOV AH, 10000000B
LP1:
MOV AL, AH
MOV DX, PORTB
OUT DX, AL
CALL DLY_L
;循环右移1位
SHR AH, 1
JC C1
;判断开关状态是否改变,改变则重新判断分支,没改变则继续循环
CALL CHANGED
CMP FLAG, 1
JE CASE
JMP LP1
C2:
LEA SI, DISP
LEA BX, MESS
MOV AH, 10000000B
LP2:
;取字形码
MOV AL, [SI]
XLAT
;送段选
MOV DX, PORTA
OUT DX, AL
;送位选
MOV AL, AH
MOV DX, PORTB
OUT DX, AL
SHR AH, 1
JC C2
;判断开关状态是否改变,改变则重新判断分支,没改变则继续循环
CALL CHANGED
CMP FLAG, 1
JE CASE
INC SI
JMP LP2
C3:
;灯全灭,结束
MOV AL, 00H
MOV DX, PORTB
OUT DX, AL
JMP WT
C4:
;送段选
MOV AL, MESS
MOV DX, PORTA
OUT DX, AL
;送位选
MOV AL, 0FFH
MOV DX, PORTB
OUT DX, AL
JMP CASE
WT:
JMP WT
DLY_L PROC
PUSH ECX
MOV ECX, 2FFFFH
DLYS_AGN:
NOP
NOP
LOOPD DLYS_AGN
POP ECX
RET
DLY_L ENDP
CHANGED PROC ;按键没变则FLAG=0
PUSH CX
MOV FLAG, 0
MOV DX, PORTC
IN AL, DX
CMP CH, AL
JE DONE
MOV FLAG, 1
DONE:
POP CX
RET
CHANGED ENDP
CODE ENDS
END BEG
键盘
.486
PORTA EQU 300H
PORTB EQU 304H
PORTC EQU 308H
CTRL_8255 EQU 30CH
CHANEL0 EQU 320H
CHANEL1 EQU 324H
CHANEL2 EQU 328H
CTRL_8254 EQU 32CH
KA EQU 0BBH
KB EQU 0B7H
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 1000H
START:
;初始化8255
MOV DX, CTRL_8255
MOV AL, 10000010B ;A口输出控制8254,B口输入读键盘行,C口输出送键盘列信号
OUT DX, AL
;初始化8254
MOV DX, CTRL_8254
MOV AL, 00110110B ;通道0,高低字节,方式三,二进制
OUT DX, AL
MOV AX, 47000; 1s*47000Hz
MOV DX, CHANEL0
OUT DX, AL
MOV AL, AL
OUT DX, AL
;
KSCAN:
MOV BL, 0BH ;A,B的列特征值
MOV AL, BL
MOV DX, PORTC;送列读行
OUT DX, AL
MOV DX, PORTB
IN AL, DX
AND AL, 0FH
CMP AL, 0FH
JNZ FNDKEY ;有键按下则跳转
JMP KSCAN ;无键按下则重新读取
FNDKEY:
SHL BL, 4
OR BL, AL;列信号和行信号组成键特征值
CALL DLY_L
KEYUP: ;判断按键是否释放
MOV AL, 0
MOV DX, PORTC
OUT DX, AL
MOV DX, PORTB
IN AL, DX
AND AL, 0FH
CMP AL, 0FH
JNZ KEYUP ;未释放则继续等待
CMP BL, KA;如果按下的是'A'
JE CA
CMP BL, KB;'B'
JE CB
JMP KSCAN
CA:
;输出高电平到8254的GATE
MOV AL, 0FFH
MOV DX, PORTA
OUT DX, AL
JMP KSCAN
CB:
;输出低电平到8254的GATE
MOV AL, 00H
MOV DX, PORTA
OUT DX, AL
JMP WT
WT:
JMP WT
DLY_L PROC
PUSH ECX
MOV ECX, 2FFFFH
DLYS_AGN:
NOP
NOP
LOOP DLYS_AGN
POP ECX
RET
DLY_L ENDP
CODE ENDS
END START