1、这学期学8086汇编,所做的四次实验十个题目(前8手写,后2摘录后修改,时间久远未找到原文链接,愿理解),亲测可用,码住,希望能对将来的读者有所帮助。
2、有的需要在debug中根据段地址和偏移地址修改(e命令)或查看(d命令)值以后才能使用,偏移地址大多在3000,根据需要可能在3100也有,需要读源代码加以理解。
按照这篇文章配置。
0.0、0.1为常用的两个功能,不是具体题目,也不是原创。
.model small ;小型存储模式
.stack ;定义堆栈段
.data ;定义数据段
string db 'Hello, world!' ;预存字符串、
db 0dh, 0ah, '$' ;回车换行结束
.code ;定义代码段
start: mov ax, @data ;装数据段(段
mov ds, ax ; 地址送DS)
lea dx, string ;调用21H号
mov ah, 9 ; 中断,显示
int 21h ; 字符串
mov ax, 4c00h ;调用21H号中
int 21h ; 断,返回
end start ; 结束汇编
.model small
.stack
.data
buf db 20
db ?
db 20 dup(0)
crlf db 0dh,0ah,'$'
.code
start: mov ax,@data
mov ds,ax
lea dx,buf;接受字符串
mov ah,0ah
int 21h
mov al,buf+1
add al,2
mov ah,0
mov si,ax
mov buf[si],'$'
lea dx,crlf;另取一行
mov ah,09h
int 21h
lea dx,buf+2;输出数据
mov ah,9
int 21h
mov ax,4c00h
int 21h
end start
.model small
SSTACK SEGMENT STACK
DW 64 DUP(?)
SSTACK ENDS
DATA SEGMENT
SADD DB 33H,39H,32H,34H,30H ;
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA
MOV DS, AX
MOV AX, OFFSET SADD
MOV SI, AX
MOV BX, 000AH
MOV CX, 0004H
MOV AH, 00H
MOV AL, [SI]
SUB AL, 30H
A1: IMUL BX
MOV DX, [SI+01]
AND DX, 00FFH
ADC AX, DX
SBB AX, 30H
INC SI
LOOP A1
A2: JMP A2
CODE ENDS
END START
.model small
.stack
.data
crlf db 0dh,0ah,'$'
.code
start: mov ax,@data
mov ds,ax
mov ax,0
mov cx,5
mov si,34ffh
jmp change
notin: dec cx
mov al,0ffh
mov [si+0ah],al
jcxz ending
change: inc si
mov al,[si]
cmp al,30h
jb notin
cmp al,39h
ja notin
and al,0fh
mov [si+0ah],al
loop change
ending: mov ax,4c00h
int 21h
end start
.model small
.stack
.data
.code
start: mov ax,@data
mov ds,ax
mov ax,2
mov cx,3
mov si,1
cheng: mul cx
cmp ax,200
ja ending
add si,ax
mov ax,cx
inc cx
jmp cheng
ending: mov ax,4c00h
int 21h
end start
.model small
.stack
.data
crlf db 0dh,0ah,'$'
.code
start: mov ax,@data
mov ds,ax
mov dx,0
mov si,3000h
mov cx,[si]
mov ch,0
mov si,1
jmp tongji
temp: inc dx
dec cx
jcxz ending
tongji: mov al,[si+3000h]
inc si
cmp al,127
ja temp
loop tongji
mov [si+3000h],dx
ending: mov ax,4c00h
int 21h
end start
.model small
.stack
.data
buf db 10 dup(0)
crlf db 0dh,0ah,'$'
.code
start: mov ax,@data
mov ds,ax
mov ah,1
mov cx,10
mov si,0
gets: mov al,[si+3000h]
mov buf[si],al
inc si
loop gets
mov bx,9
cmp ah,0
jz ending
wai: mov ah,0
mov cx,bx
mov si,0
cmp_ad:
mov al,buf[si]
mov dl,buf[si+1]
cmp al,dl
jb back
xchg al,dl
mov ah,1
back: mov buf[si],al
mov buf[si+1],dl
inc si
loop cmp_ad
dec bx
jnz wai
ending: mov cx,10
mov si,0
print: mov al,buf[si]
mov [3100h+si],al
inc si
loop print
mov ax,4c00h
int 21h
end start
这个比较懒,拿来排序前后的数据对应一下数值得到名次。
.model small
.stack
.data
buf db 10 dup(0)
buf2 db 10 dup(0)
crlf db 0dh,0ah,'$'
.code
start: mov ax,@data
mov ds,ax
mov cx,10
mov si,0
gets: mov al,[si+3000h]
mov buf[si],al
mov buf2[si],al
inc si
loop gets
mov bx,9
wai: mov cx,bx
mov si,0
cmp_ad: mov al,buf[si]
mov dl,buf[si+1]
cmp al,dl
ja back
xchg al,dl
back: mov buf[si],al
mov buf[si+1],dl
inc si
loop cmp_ad
dec bx
jnz wai
mov cx,10
mov bx,0
mov si,0
cmp2: mov al,buf[bx]
mov dl,buf2[si]
cmp al,dl
jz write
inc bx
loop cmp2
write: inc bx
mov [si+3100h],bx
mov bx,0
inc si
mov cx,10
cmp si,10
jb cmp2
ending: mov ax,4c00h
int 21h
end start
这个也是太懒辽,还是直接拿来冒泡排序后取头尾,大家知道就好,处理大量数据可千万不要这样。
STACK SEGMENT PARA STACK
SPAE dw 20 DUP(?)
TOP EQU SIZE SPAE
STACK ENDS
DATA SEGMENT
COUNT dw 7
DATA ENDS
MAIN SEGMENT
ASSUME CS:MAIN,DS:DATA,SS:STACK
STR: mov ax, DATA
mov DS, ax
mov si, 3000H
mov cx, COUNT
call FAR PTR QIU
hlt
MAIN ENDS
PROCE SEGMENT
ASSUME CS:PROCE,DS:DATA,SS:STACK
QIU PROC FAR
push si
push cx
push bx
push bp
mov bp, sp
pushf
mov bh, [si]
mov bl, bh
A1: inc si
mov al, [si]
cmp al, bh
jle ALBH
mov bh, al
ALBH: cmp al, bl
je ALBL
mov bl, al
ALBL: loop A1
mov ax, bx
popf
pop bp
pop bx
pop cx
pop si
ret 0
QIU ENDP
PROCE ENDS
END STR
STACK SEGMENT PARA STACK
SPAE dw 20 DUP(?)
TOP EQU SIZE SPAE
STACK ENDS
DATA SEGMENT
NUM dw 0
RESULT dw ?
DATA ENDS
MAIN SEGMENT
ASSUME CS:MAIN,DS:DATA,SS:STACK
STR: mov ax, DATA
mov DS, ax
mov sp, size SPAE
mov bx, NUM
call FAR PTR QIU
hlt
MAIN ENDS
PROCE SEGMENT
ASSUME CS:PROCE,DS:DATA,SS:STACK
QIU PROC FAR
and bx, bx
jz A1
push bx
dec bx
call QIU
pop bx
mul bx
mov RESULT, ax
ret
A1: mov ax, 1
ret
QIU ENDP
PROCE ENDS
END STR
data segment
string db "7",0DH,0AH,'$' ;回车+换行
data ends
code segment
main proc far
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax ;初始化数据段
push ds ;通过数据段访问中断向量表
mov ax,0000h
mov ds,ax
mov ax,offset MIR7 ;取中断入口地址
mov si,003ch ;中断矢量地址
mov ds:[si],ax ;存放中断矢量
mov ax,cs ;段地址
mov si,003eh ;中断段地址
mov ds:[si],ax ;存放中断段地址
CLI ;关中断
pop ds ;恢复数据段段地址
init:;初始化8259
mov al,11h;边沿触发
out 20h,al;ICW1
mov al,08h
out 21h,al;ICW2
mov al,04h
out 21h,al;ICW3,IR2连接从片
mov al,01h
out 21h,al;ICW4
mov al,6fh;不屏蔽ir7,ir4
out 21h,al;OCW1
STI;开中断
AWAIT:
nop
jmp AWAIT ;无限循环
MIR7:
STI
call delay
lea dx,string
mov ah,09h
int 21h ;输出7
mov al,20h
out 20h,al ;中断结束
iret ;中断返回
main endp
delay proc near
mov cx,0a00h
waitPress:
nop
loop waitPress
ret
delay endp
code ends
end start
根据老师要求,两个中断程序,分别输出sun,chen,因为有嵌套和delay函数,还可能出现显示字母混杂的情况(也是为了满足要求,感觉这个纯粹是为了捣乱)。
stack segment
dw 100 dup(?)
tos label word
stack ends
data segment
strings db "s$"
stringu db "u$"
stringn db "n",0DH,0AH,"$"
stringc db "c$"
stringh db "h$"
stringe db "e$"
string1 db "n",0DH,0AH,"$"
data ends
code segment
assume cs:code,ds:data,ss:stack
main proc far
start:
mov ax, stack
mov ss,ax
mov sp,offset tos
mov ax,data
mov ds,ax;初始化数据段
push ds;通过数据段访问中断向量表
mov ax,0
mov ds,ax
mov ax,offset MIR7
mov si,003ch;中断矢量地址
mov ds:[si],ax;存放中断矢量
mov ax,cs;段地址
mov si,003eh;中断段地址
mov ds:[si],ax;存放中断段地址
mov ax,offset SIR1
mov si,00c4h
mov ds:[si],ax
mov ax,cs
mov si,00c6h
mov ds:[si],ax
pop ds;恢复数据段段地址
cli;关中
;初始化主片8259
mov al,11h;边沿触发
out 20h,al;ICW1
mov al,08h
out 21h,al;ICW2
mov al,04h
out 21h,al;ICW3,IR2连接从片
mov al,01h
out 21h,al;ICW4
mov al,6bh;主片OCW1,不屏蔽ir7,ir4,ir2
out 21h,al;OCW1
;初始化从片8259
mov al,11h
out 0a0h,al;ICW1
mov al,30h
out 0a1h,al;ICW2
mov al,02h
out 0a1h,al;ICW3
mov al,01h
out 0a1h,al;ICW4
mov al,0fdh
out 0a1h,al;从片OCW1
sti;开中断
Exam:
nop
jmp Exam
MIR7:
sti
call delay
lea dx,strings
mov ah,09h
int 21h
call delay
lea dx,stringu
mov ah,09h
int 21h
call delay
lea dx,stringn
mov ah,09h
int 21h
mov al,20h
out 20h,al;中断结束
iret;中断返回
SIR1:
sti
;call delay;延时防抖
lea dx,stringc
mov ah,09h
int 21h;输出S1
;call delay
lea dx,stringh
mov ah,09h
int 21h;输出S1
;call delay
lea dx,stringe
mov ah,09h
int 21h
;call delay
lea dx,string1
mov ah,09h
int 21h
mov al,20h
out 0a0h,al
out 20h,al;中断结束
iret;中断返回
main endp
delay proc near
mov cx,0ff00h
waitButton:
nop
loop waitButton
ret
delay endp
code ends
end start
MY8255_A EQU 0600H
MY8255_B EQU 0602H
MY8255_C EQU 0604H
MY8255_CON EQU 0606H
SSTACK SEGMENT STACK
DW 16 DUP(?)
SSTACK ENDS
DATA SEGMENT
DTABLE DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H
DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV SI,3000H
MOV AL,00H
MOV [SI],AL ;清显示缓冲
MOV [SI+1],AL
MOV [SI+2],AL
MOV [SI+3],AL
MOV DI,3003H
MOV DX,MY8255_CON ;8255控制字初始化
MOV AL,81H ;1000 0001 A、B口输出 C口输入
OUT DX,AL
BEGIN:
; 调用显示子程序
CALL DIS
;清屏
CALL CLEAR
;扫描 看是否有键按下
CALL CCSCAN
;有键按下 跳INK1
JNZ INK1
JMP BEGIN
INK1:
CALL DIS
CALL DALLY
CALL DALLY
CALL CLEAR
CALL CCSCAN
; 若结果不为0 ZF=0 则说明一定有键按下 则跳转 判断哪个键按下
JNZ INK2
JMP BEGIN
;确定按下键的位置
INK2:
MOV CH,0FEH ; FEH=1111 1110(对应关系:PA7 PA6..PA1 PA0 )
; PA5-PA0=1111 10 (这里对应关系要弄明白)
;PA0对应的按键则是 从左到右第一列(这里不会晕哦)
MOV CL,00H ; 初始对于行的偏移量 为0
;列循环 即扫描列 从第一列开始
COLUM:
MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
L1: TEST AL,01H ;is L1?
JNZ L2
MOV AL,00H ;L1
JMP KCODE
L2: TEST AL,02H ;is L2?
JNZ L3
MOV AL,04H ;L2
JMP KCODE
L3: TEST AL,04H ;is L3?
JNZ L4
MOV AL,08H ;L3
JMP KCODE
L4: TEST AL,08H ;is L4?
JNZ NEXT
MOV AL,0CH ;L4
; 找到按键后 此时AL存的的第一列每一行的初始值 0 4 8 C
; CL 存的是对应行的偏移量
; 假设 AL为08H CL为2 则表示的总偏移量为 8+2=10H
; 说明在table中该数字的偏移量为10H
; 输出该数字 利用偏移量就行 因为数字其实是存在table中的
KCODE: ADD AL,CL
CALL PUTBUF
PUSH AX
KON: CALL DIS
CALL CLEAR
CALL CCSCAN
JNZ KON
POP AX
NEXT: INC CL ; CL相当于 行偏移量
MOV AL,CH
TEST AL,08H ; 08H=0000 1000 当AL为1111 0111 && 0000 1000 结果为0
; ZF=1 说明行偏移量达到最大值 3
JZ KERR ; 4次列循环结束 跳KERR
ROL AL,1
MOV CH,AL
JMP COLUM
KERR: JMP BEGIN
; 键盘扫描子程序
; 原理是 先向全部列输出低电平
; 然后从C口读入 行电平
; 如果没有按键按下 所有行应该均为高电平
; 反之 若有按键按下 则开始仔细判断出到底是哪个按键按下 具体判断方法是:
; 先向第一列输出低电平(从左到右)
; 然后从C口读入行电平 利用 AND
; 判断哪一行是否为低电平即可(后面为了计算方便取反了行电平)
; 若行全为高 为开始向下一列输出低电平 循环4次即可
CCSCAN: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL ; 向所有列输出 低电平
MOV DX,MY8255_C
IN AL,DX ;读所有行电平
;原来没有任何键按下 4行全为1
;这里取反 变成 0000 便于后面的判断
NOT AL
; 假设没有按键按下
; 0000&1111=0
; 结果为0 ZF=1
AND AL,0FH
RET
;清屏子程序
;就是使得所有的灯熄灭 00H表示全不亮 瞬间 很快
CLEAR: MOV DX,MY8255_B
MOV AL,00H
OUT DX,AL
RET
; 显示子程序 (这里稍微有点绕)
DIS: PUSH AX
MOV SI,3000H
; 0DFH=1101 1111 对应PA7 PA6 PA5...PA1 PA0
; 由电路图 得出 X1-PA0 X2-PA1.....
; 6个显示器 从左到右依次是 X1 X2 X3... X5 X6
; 所以 对应的PA: PA0 PA1 PA2...PA4 PA5
; 这里初始是0DFH 代表 1 1 1 1 1 0
; 意思是 第六个显示 开始显示数字
; 哈哈 这里其实是从X6到X1依次显示的
; 每个数字显示间隔很快 我们会认为是6个数字一起显示 其实是逐个显示
MOV DL,0DFH
MOV AL,DL
AGAIN: PUSH DX
; 把AL送给A口 觉得开放哪个灯 (这里要看电路图 A口也控制灯的开放)
MOV DX,MY8255_A
OUT DX,AL
MOV AL,[SI] ; 把3000H--3005H中存的偏移量(相对)取出
MOV BX,OFFSET DTABLE ; 获取DTABLE的首地址
AND AX,00FFH ;因为后面会有加法运算 先把ah清0 这样ax就是
; al的值,防止出错
ADD BX,AX ; 获取需要的值的偏移量(这个是绝对偏移量)
MOV AL,[BX] ; 获取显示数字需要的值 例 显示0需要3FH
MOV DX,MY8255_B ; 送往B口 显示数字
OUT DX,AL
CALL DALLY ;延时
INC SI ;移动SI 读取下一个偏移量
POP DX
MOV AL,DL ; DL: 控制哪个灯的开放 开始是0DF 1101 1111
; 取后6位(看电路图 只连了6根线)即01 1111
; 赋值给AL
TEST AL,04H ; 测试AL 看是否为11 1110
; 6个灯 一次显示需要循环6次
; 这里第六次结束是 AL=11 1110
; 对于灯 就是x1灯显示完(灯:X6->X1)
JZ OUT1 ; 6次循环完成后 跳出
ROR AL,1 ; 循环右移
; 例 第一个灯亮 AL=01 1111
; 则 第二个灯亮 为 10 1111
; 所以需要循环右移
; 反映在灯上 则是左移(不要绕进去了哦)
MOV DL,AL
JMP AGAIN ; 跳回 继续显示 需循环6次
OUT1: POP AX
RET
; 子程序 延时作用 RET为子程序结束标记
DALLY: PUSH CX
MOV CX,0006H
T1: MOV AX,009FH
T2: DEC AX
JNZ T2
LOOP T1
POP CX
RET
; 将获得的偏移量存入3000H--30005H中
; 便于后面的显示
; 显示其实就是从3000H--3005H中读取偏移量
; 然后在table中找到真正的值即可
PUTBUF: MOV SI,DI ;存键盘值到相应位的缓冲中
MOV [SI],AL ;先存入地址3005H 再递减 也就是下一个存入偏移量的是3004H
DEC DI
CMP DI,2FFFH
JNZ GOBACK
MOV DI,3003H
GOBACK: RET
CODE ENDS
END START
建议实验可以用这些代码,考试用的话还是找一些比较简短的代码,确实这个8255和8259真的难记。
我们考试还常常带上数模转换器一起考,提示注意,不同学校未必有用。