8086汇编实验(十题可用)

一、前言

1、这学期学8086汇编,所做的四次实验十个题目(前8手写,后2摘录后修改,时间久远未找到原文链接,愿理解),亲测可用,码住,希望能对将来的读者有所帮助。
2、有的需要在debug中根据段地址和偏移地址修改(e命令)或查看(d命令)值以后才能使用,偏移地址大多在3000,根据需要可能在3100也有,需要读源代码加以理解。

二、环境(DOSBox)

按照这篇文章配置。

三、题目及源代码

0.0、0.1为常用的两个功能,不是具体题目,也不是原创。

0.0 第一个helloworld!

		.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		; 结束汇编

0.1 输入输出

	.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

1、十进制转二进制

	.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

2、asc转bcd

	.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

3、循环程序设计

	.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

4、统计符号为负个数

	.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

5、冒泡排序

	.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

6、排名

这个比较懒,拿来排序前后的数据对应一下数值得到名次。

	.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

7、求最大最小值

这个也是太懒辽,还是直接拿来冒泡排序后取头尾,大家知道就好,处理大量数据可千万不要这样。

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

8、求阶乘

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

9.1、8259_1,编写中断程序,每次脉冲输出7

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

9.2、8259_2

根据老师要求,两个中断程序,分别输出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

10、8255键盘扫描

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真的难记。
我们考试还常常带上数模转换器一起考,提示注意,不同学校未必有用。

  • 5
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值