实验一 设计数码管电子表实验要求:
使用8253的两个计数器串连,作为微机系统的外扩定时源,以数码管电路作为外扩输出设备,采用中断方式编程,实现数码管电子表“具体要求如下:
1.六位数码管分别显示时,分,秒。
2.初始时间由主机键盘输入。
3.主机按任意键停止计时返回DOS。
二:实验电路
+5V
与计算机数据线相连
208H-20FH 接B4端子
A(+5V)
A1 Q2 B(8MHZ)
A0
IOR
IOW
8253
CS 200H-207H
(*注意:A1,A0用来选择8253内部三个计数器中的一个,它们分别与计算机地址线的低两位相连。RD,WR 用来控制8253的读写,它们分别与计算机的IOR,IOW相连)
电路分析:
从Q2出来的时钟频率为1MHZ,为实现一秒钟调用一次中断,必须要每1000000次时钟调用一次中断。我们同时将计数器0和计数器1的初值都设为1000,并将计数器0的输出OUT0作为计数器1的时钟,并将计数器1的输出OUT1连到B4端子上,这样就实现了每1000×1000=1000000次时钟调用一次中断。
三.8253控制字格式
D7 D6 D5 D4 D3 D2 D1 D0
SC1
SC2
RL1
RL0
M2
M1
M0
BCD
四.程序清单:
TITLE DISPTIME
DSEG SEGMENT
INPUT_TIM DB 'Please input the current t ime.',13,10,'$'
SHOW_TIM DB 'Time is as the follow.Press Ctr-C to exit.',13,10,'$'
BAD_DATA DB 'Digits mush be between 0 and 9',13,10,'$'
BAD_HRS DB 'Hour must be between 0 and 23',13,10,'$'
BAD_MINS DB 'Minutes mush be between 0 and 59',13,10,'$'
BAD_SECS DB 'Seconds mush be between 0 and 59',13,10,'$'
CRLF DB 13,10,'$'
ASK_HRS DB 'Hour(0-23):$'
ASK_MINS DB 'Minute(0-59):$'
ASK_SECS DB 'Second(0-59):$'
USER DB 3,3 DUP(?)
TIME DB 3 DUP(?)
COUNT DW 1
OLD0A DD?
TABLE DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,79H,71H
DSEG ENDS
SSEG SEGMENT STACK 'STACK'
DB 256 DUP(?)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,SS:SSEG,DS:DSEG,ES:DSEG
START PROC FAR
MOV AX,DSEG
MOV DS,AX
CALL GET_TIME
CLI
CALL I8253 (初始化8253)
CALL I8259 (初始化8259)
CALL RD0A
(读入原0A中断向量)
CALL WR0A(写入新中断向量)
ROTATE,CALL DISPLAY(只要不按键,就不断调用DISPLAY显示TIME变量中的时间)
MOV AH,1
INT 16H
JZ ROTATE
(按键输入后退出。)
CALL RESET
MOV AH,4CH
INT 21H
RET
START ENDP;************************************
(SERVICE为新的中断程序)
SERVICE PROC NEAR
PUSH AX
PUSH DS
MOV AX,DSEG
MOV DS,AX
CALL CHANGE_TIME
(函数CHANGE_TIME用以将时间增加一秒)
MOV AL,20H
OUT 20H,AL(送应答信号)
POP DS
POP AX
IRET
SERVICE ENDP;************************************
(此函数将保存在TIME变量中的时间显示在数码管上。)
DISPLAY PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
MOV SI,OFFSET TIME
MOV BX,OFFSET TABLE
MOV CL,4
MOV AL,[SI]
MOV AH,AL
SAR AL,CL
AND AH,00001111B
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,01H
OUT DX,AL
MOV AL,0
OUT DX,AL
MOV AL,AH
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,02H
OUT DX,AL
MOV AL,0
OUT DX,AL
MOV AL,[SI+1]
MOV AH,AL
SAR AL,CL
AND AH,00001111B
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,04H
OUT DX,AL
MOV AL,0
OUT DX,AL
MOV AL,AH
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,08H
OUT DX,AL
MOV AL,0
OUT DX,AL
MOV AL,[SI+2]
MOV AH,AL
SAR AL,CL
AND AH,00001111B
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,10H
OUT DX,AL
MOV AL,0
OUT DX,AL
MOV AL,AH
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,20H
OUT DX,AL
MOV AL,0
OUT DX,AL
POP SI
POP DX
POP CX
POP BX
POP AX
RET
DISPLAY ENDP;************************************
I8253 PROC NEAR
MOV AL,00110100B
MOV DX,20BH
OUT DX,AL
(设定8253的计算器0,写入时先低字节后高字节,方式2,二进制计数)
MOV AX,1000
MOV DX,208H
OUT DX,AL
MOV AL,AH
OUT DX,AL
(计数器0的初值设为1000。)
MOV AL,01110100B
MOV DX,20BH
OUT DX,AL
(设定8253的计算器1,入时先低字节后高字节,方式2,二进制计数)
MOV AX,1000
MOV DX,209H
OUT DX,AL
MOV AL,AH
OUT DX,AL
(计数器1初值设为1000。)
RET
I8253 ENDP;**********************************
I8259 PROC NEAR
IN AL,21H
AND AL,11111011B
OUT 21H,AL
IN AL,0A1H
AND AL,11111101B
OUT 0A1H,AL
RET
I8259 ENDP;********************************
RD0A PROC NEAR
MOV AX,350AH
INT 21H
MOV WORD PTR OLD0A,BX
MOV WORD PTR OLD0A+2,ES
RET
RD0A ENDP
WR0A PROC NEAR
PUSH DS
MOV AX,CSEG
MOV DS,AX
MOV DX,OFFSET SERVICE
MOV AX,250AH
INT 21H
POP DS
RET
WR0A ENDP;********************************
RESET PROC NEAR
MOV DX,WORD PTR OLD0A
MOV DS,WORD PTR OLD0A+2
MOV AX,250AH
INT 21H (恢复原来的中断向量)
IN AL,0A1H
OR AL,00000010B
OUT 0A1H,AL (屏蔽用户中断)
RET
RESET ENDP;***********************************
(函数GET_TIME的作用是接受用户输入的时间,并把它保存在6字节变量TIME中。
为了保证程序的严谨,如果输入的时间非法,则显示出错信息并要求重输。)
GET_TIME PROC NEAR
LEA DX,INPUT_TIM
MOV AH,9
INT 21H (提示输入时间)
HOUR,LEA DX,ASK_HRS
MOV AH,9
INT 21H (提示输入小时)
CALL INPUT_TIME
(函数INPUT_TIME的功能是把用户输入的字符转化为时间值并存放在BL中如果输入的不是数字,那么让标志寄存器CF=1)
JC HOUR (输入不是数字,重输)
CMP BL,23H
JNA HRS2
(如果输入的数字比24小,那么跳到HRS2去执行下面的内容;如果输入的数字大于等于24,那么要求重输。对于分,秒的输入也按照此法处理。)
LEA DX,BAD_HRS
MOV AH,9
INT 21H
JMP HOUR
HRS2,PUSH BX
MIN,LEA DX,ASK_MINS
MOV AH,9
INT 21H
CALL INPUT_TIME
JC MIN
CMP BL,59H
JNA MIN2
LEA DX,BAD_MINS
MOV AH,9
INT 21H
JMP MIN
MIN2,PUSH BX
SEC,LEA DX,ASK_SECS
MOV AH,9
INT 21H
CALL INPUT_TIME
JC SEC
CMP BL,59H
JNA SEC2
LEA DX,BAD_SECS
MOV AH,9
INT 21H
JMP SEC
(以下程序段将输入的的时间保存在TIME变量中)
SEC2,MOV SI,OFFSET TIME
MOV [SI+2],BL
POP BX
MOV [SI+1],BL
POP BX
MOV [SI],BL
RET
GET_TIME ENDP;************************************
(函数INPUT_TIME的功能是把用户输入的字符转化为时间值并存放在BL中;如果输入的不是数字,那么让标志寄存器CF=1)
INPUT_TIME PROC NEAR
LEA DX,USER
MOV AH,0AH
INT 21H
LEA DX,CRLF
MOV AH,9
INT 21H
CMP USER+1,1
JAE CONVERT
MOV BL,0
RET
CONVERT,MOV CL,4
MOV AL,USER+2
CALL CHECK
JC LEAVE
AND AL,0FH
MOV BL,AL
CMP USER+1,2
JB CLR_CF
SHL BL,CL
MOV AL,USER+3
CALL CHECK
JC LEAVE
AND AL,0FH
OR BL,AL
CLR_CF,CLC
LEAVE,RET
INPUT_TIME ENDP;***********************************
CHECK PROC NEAR
CMP AL,'0'
JB ERROR
CMP AL,'9'
JA ERROR
CLC
RET
ERROR,LEA DX,BAD_DATA
MOV AH,9
INT 21H
STC
RET
CHECK ENDP;***********************************
(此函数将保存在TIME变量中的时间增加一秒)
CHANGE_TIME PROC NEAR
PUSH AX
PUSH CX
PUSH DX
PUSH SI
MOV SI,OFFSET TIME
MOV AL,[SI]
MOV CH,AL
MOV AL,[SI+1]
MOV CL,AL
MOV AL,[SI+2]
MOV DH,AL
(CH:CL:DH=时:分:秒)
MOV AL,DH
ADD AL,1
DAA
MOV DH,AL
CMP DH,60H
JNE EXITCHG
MOV DH,0
MOV AL,CL
ADD AL,1
DAA
MOV CL,AL
CMP CL,60H
JNE EXITCHG
MOV CL,0
MOV AL,CH
ADD AL,1
DAA
MOV CH,AL
CMP CH,24H
JNE EXITCHG
MOV CH,0
EXITCHG,MOV SI,OFFSET TIME
MOV [SI],CH
MOV [SI+1],CL
MOV [SI+2],DH
POP SI
POP DX
POP CX
POP AX
RET
CHANGE_TIME ENDP
CSEG ENDS
END START
五.实验总结:
由于与本实验相关的程序上学期编过(在屏幕上显示时间),所以这次实验我的程序中的主要部分是用的以前的,添加了将时间显示在数码管上的程序。上学期编的那个程序中,我用三个字节来存储时分秒,这次仍然沿用这个习惯。但这个习惯使我在编将时间显示在数码管上的子程序(DISPLAY)的时候遇到了困难,因为一个字节代表的是数码管上的两个位置,所以编查表程序时必须把那个字节的信息拆分为两个字节再进行查表,这使程序繁琐,可读性降低。如果用六个字节分别存储时的十位,时的个位,分的十位,分的个位,秒的十位,秒的个位,那么在编显示程序时确实方便了许多,但是在编改变时间的程序时却会更复杂一些。因此这两种方法各有利弊。
在程序的结束RESET函数中一定要屏蔽用户中断,否则下一次调用程序时就不会响应中断,这个问题让我耗费了很多时间。
实验二:小键盘按键识别一.实验要求:
本次实验的要求与前一实验类似,但仅要求识别小键盘0~9数字键,将小键盘键入的任意长的0~9数字串,采用左移位动态显示的方法显示在数码管电路上,当小键盘按下”R”时停止演示.
二.程序框图:
Y 无键闭合
N:AH为闭合键“列值”
Y
三.实验电路图:

四.8255方式选择控制字
1
D6
D5
D4
D3
D2
D1
D0
五.源程序:
TITLE LITTLEKEYBOARD
SSEG SEGMENT PARA STACK 'STACK'
DB 256 DUP (0)
SSEG ENDS
DSEG SEGMENT
A_8255 EQU 210H
B_8255 EQU 211H
CON_8255 EQU 213H
BUFFER DB 6 DUP(0)
HANG DB?
LIE DB?
NEWHANG DB?
NEWLIE DB?
TABLE DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG,SS:SSEG
START PROC NEAR
MOV AX,DSEG
MOV DS,AX
CALL CLOSEALL
(关掉数码管,防止因为最初数码管有显示而使程序执行不正常。)
CMPAGAIN:
CALL DISPLAY
(DISPLAY函数用来将BUFFER中的键值显示在数码管上。)
MOV DX,CON_8255
MOV AL,10000010B
OUT DX,AL
(设定A口方式0输出,B口方式0输入)
AGAIN:
CALL DISPLAY
MOV DX,A_8255
MOV AL,0
OUT DX,AL (0->PA7---PA0)
MOV DX,B_8255
IN AL,DX
AND AL,00000111B (取出PB0-PB2
CMP AL,00000111B
JE AGAIN
MOV LIE,AL(将列值保存)
CALL DELAY1(延时20ms)
MOV DX,CON_8255
MOV AL,10010000B
OUT DX,AL
(预置A口方式0输入,B口方式0输入)
MOV DX,A_8255
IN AL,DX
MOV HANG,AL(将行值保存)
CALL GETINPUT
(GETINPUT函数通过行值和列值查出输入的键值,并将它保存在AL中,如果输入是R,则AL赋值为FFH;如果输入非法字符,则AL赋值为0AH。)
CMP AL,0AH
JE CMPAGAIN
(如果是非法字符则跳回)
CMP AL,0FFH
JNE CONTINUE
(如果是R则退出程序.)
CALL CLOSEALL
MOV AH,4CH
INT 21H
CONTINUE:
CALL CHANGE
(CHANGE函数用来改变BUFFER中保存的键值)
MOV DX,CON_8255
MOV AL,10000010B
OUT DX,AL
(设定A口方式0输出,B口方式0输入)
LLL:
CALL DISPLAY
MOV DX,B_8255
IN AL,DX
AND AL,00000111B
(取出PB0-PB2)
CMP AL,00000111B
JNE LLL
JMP CMPAGAIN
(不断扫描,如果不松开按键,那么就循环等待;直到按键松开就跳回。)
RET
START ENDP;*********************************
(此函数用以延时20MS)
DELAY1 PROC NEAR
PUSH AX
PUSH CX
PUSH DX
MOV AH,86H
MOV CX,0
MOV DX,20000
INT 15H
POP DX
POP CX
POP AX
RET
DELAY1 ENDP;********************************
(GETINPUT函数通过行值和列值查出输入的键值,并将它保存在AL中,如果输入是R,则AL赋值为FFH;如果输入非法字符,则AL赋值为0AH。)
GETINPUT PROC NEAR
CMP LIE,00000110B
JE LIE0
CMP LIE,00000101B
JE LIE1
CMP LIE,00000011B
JE LIE2
MOV AL,0AH
RET
LIE2:CMP HANG,00010000B
JE NEXT
MOV AL,0AH
RET
NEXT:MOV AL,0FFH
RET
LIE0:CMP HANG,01111111B
JE KEY8
CMP HANG,10111111B
JE KEY9
MOV AL,0AH
RET
KEY8:MOV AL,8
RET
KEY9:MOV AL,9
RET
LIE1:CMP HANG,01111111B
JE KEY0
CMP HANG,10111111B
JE KEY1
CMP HANG,11011111B
JE KEY2
CMP HANG,11101111B
JE KEY3
CMP HANG,11110111B
JE KEY4
CMP HANG,11111011B
JE KEY5
CMP HANG,11111101B
JE KEY6
CMP HANG,11111110B
JE KEY7
MOV AL,0AH
RET
KEY0:MOV AL,0
RET
KEY1:MOV AL,1
RET
KEY2:MOV AL,2
RET
KEY3:MOV AL,3
RET
KEY4:MOV AL,4
RET
KEY5:MOV AL,5
RET
KEY6:MOV AL,6
RET
KEY7:MOV AL,7
RET
GETINPUT ENDP;**********************************
(CHANGE函数用来改变BUFFER中保存的键值,将BUFFER中的键值移位,最后一位加入AL中的新键值。)
CHANGE PROC NEAR
PUSH AX
PUSH SI
MOV SI,OFFSET BUFFER
MOV AH,[SI+1]
MOV [SI],AH
MOV AH,[SI+2]
MOV [SI+1],AH
MOV AH,[SI+3]
MOV [SI+2],AH
MOV AH,[SI+4]
MOV [SI+3],AH
MOV AH,[SI+5]
MOV [SI+4],AH
MOV [SI+5],AL
POP SI
POP AX
RET
CHANGE ENDP;**********************************
(DISPLAY函数用来将BUFFER中的键值显示在数码管上。)
DISPLAY PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
MOV BX,OFFSET TABLE
MOV SI,OFFSET BUFFER
MOV CL,1
XUNHUAN,
MOV AL,[SI]
XLAT
MOV DX,201H
OUT DX,AL
MOV DX,200H
MOV AL,CL
OUT DX,AL
MOV DX,200H
MOV AL,0
OUT DX,AL
INC SI
SHL CL,1
CMP CL,40H
JNE XUNHUAN
POP SI
POP DX
POP CX
POP BX
POP AX
RET
DISPLAY ENDP;*********************************
(此函数用在退出程序时将数码管关闭.)
CLOSEALL PROC NEAR
PUSH AX
PUSH CX
PUSH DX
MOV CL,1
XUNHUAN1:
MOV DX,200H
MOV AL,CL
OUT DX,AL
MOV AL,0
OUT DX,AL
SHL CL,1
CMP CL,20H
JNE XUNHUAN1
POP DX
POP CX
POP AX
RET
CLOSEALL ENDP
CSEG ENDS
END START
六.实验总结:
1.实验电路板上8255的端口地址位210H-213H,这与书上给的不一样,开始时在这方面花费了较多时间。
2.通过此次程序设计,我对计算机读取键盘值的过程有了一定的认识。最开始编程序时并没有想到如果始终按同一个键不放,数码管上就会一下子出来很多字符。调试时发现了这个问题,想到的解决方法有两种,一种是每一次按键后检测键是否松开,直到松开后再继续执行下一次判断;另一种是按键后延缓一个固定的时间(大约0.2秒)再判断(计算机的键盘就是采取这样的方法)。 本程序采用的是第一种方法。
3.编程序要养成好的习惯,我最初的程序结束时并没有关掉数码管,以致下次用时数码管显示不正确。好的程序应该各方面想得周到一些,例如我后来在开始和结束时都加了关闭数码管程序(CLOSEALL),这就避免了上述问题。
4.我并没有采用查表得方法来获得键值,我觉得用跳转的方法能使程序的可读性强一些。当然,程序代码会长许多,但此法由于思路清楚,比较容易查错。
【实验三】数/模、模/数转换实验一、实验目的:
了解数/模、模/数转换的基本原理,掌握ADC0809和DAC0832芯片的使用方法。
二、实验任务:
在实验箱上设计并连接 ADC0809 芯片的接线,按中断方式(利用 EOC 发中断申请)对单通道模拟量进行 A/D 转换。A/D 转换结果送入 PC 机后,再由 PC 机送至 DAC0832 进行 D/A 转换,结果送至双踪示波器,与原信号进行对比观察。
模拟信号源:由电位器中心抽头可以得到一个可调节的直流电压。电位器一端接地,另一端接+5V。
三、实验电路:

四:源程序
TITLE ADDA
SSEG SEGMENT STACK 'STACK'
DB 256 DUP(?)
SSEG ENDS
DSEG SEGMENT
OLD0A DD?
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG,SS:SSEG
START PROC NEAR
MOV AX,DSE
MOV DS,AX
CLI
CALL I8259(初始化8259)
CALL RD0A
(保存原0A中断向量)
CALL WR0A
(写入新的中断向量。)
STI
MOV DX,230H
MOV AL,0
OUT DX,AL
(230H为模拟量输入口,进行一次虚拟写操作,启动A/D转换.)
WAIT_IN:
MOV AH,1
INT 16H
JZ WAIT_IN
CALL RESET
MOV AH,4CH
INT 21H
RET
START ENDP;************************************
SERVICE PROC NEAR
PUSH AX
PUSH DS
MOV AX,DSEG
MOV DS,AX
CLI
IN AL,230H
(读入A/D转换后的值到AL中。)
MOV DX,228H
OUT DX,AL(启动D/A转换)
MOV DX,229H
OUT DX,AL(将AL的值写入D/A转换器)
MOV DX,230H
MOV AL,0
OUT DX,AL
(再次启动A/D转换器,为下一次转换做准备。)
STI
POP DS
POP AX
IRET
SERVICE ENDP;**********************************
I8259 PROC NEAR
IN AL,21H
AND AL,11111011B
OUT 21H,AL
IN AL,0A1H
AND AL,11111101B
OUT 0A1H,AL
RET
I8259 ENDP;************************************RD0A PROC NEAR
MOV AX,350AH
INT 21H
MOV WORD PTR OLD0A,BX
MOV WORD PTR OLD0A+2,ES
RET
RD0A ENDP;************************************
WR0A PROC NEAR
PUSH AX
PUSH DS
MOV AX,CSEG
MOV DS,AX
MOV DX,OFFSET SERVICE
MOV AX,250AH
INT 21H
POP DS
POP AX
RET
WR0A ENDP;**********************************
RESET PROC NEAR
MOV DX,WORD PTR OLD0A
MOV DS,WORD PTR OLD0A+2
MOV AX,250AH
INT 21H
IN AL,0A1H
OR AL,00000010B
OUT 0A1H,AL
RET
RESET ENDP
CSEG ENDS
END START
五.实验总结:
编写程序时要注意每次中断服务程序执行完成后都要给AD端口(230H)执行一次虚拟写操作,从而启动AD转换器进行下一个数据的转换。我开始时忽略了这个问题,结果使DA输出恒定不遍,无法跟踪输入的变化。
连线时一定要搞清原理,本实验是AD转换完成后用EOC端子传输中断请求的方式编程,所以要注意I/O口地址译码器的输出端228H-22FH接DAC的片选信号,230H-237H接ADC的片选信号,EOC接总线的B4段,另外,ADC要接500KHZ的时钟信号,利用8MHZ的信号源经16分频从Q3接出。
实验四 DMA传送实验一.实验目的:
掌握DMA方式的工作原理和8237的编程使用方法。
二.实验要求:
1,按照实验指导第61页的实验接线图连接硬件线路
2,对照【例3.6.1】的程序清单键入源程序,经汇编和连接后运行程序三.实验电路

三.电路分析
1.DMA读入数据按下 DMA按键,通过端子向DMA通道1发硬件DMA请求,系统DMA控制器向CPU发总线请求信号,CPU在执行完当前总线周期后向系统DMA控制器发总线响应信号,随即把总线控制权交给DMA控制器,此时DACK1有效。然后DMA控制器将通道1的页面地址寄存器及当前地址寄存器中的内容放到地址总线上去,并发出存储器读命令,读出内存单元中的内容送往数据总线。由于DACK1有效,通过J4短路线选中6116和双向总线驱动器74LS245,IOW有效,通过J3短路线,使6116的WE有效,从而把数据总线上的数据通过74LS245写入到6116的0号单元,完成一次DMA读传送。此时通道1当前地址寄存器自动加1,当前字节寄存器自动减1。另外通过U38和JS引线向分频器输入一个进位脉冲,使分频器计数一次,Q10-Q0输出选择6116的下一个单元。再反复上述读过程直到当前字节寄存器为FFFFH为止,读过程结束。
2.将DMA数据写到存储器上按下 DMA按键,通过端子向DMA通道1发硬件DMA请求,系统DMA控制器向CPU发总线请求信号,CPU在执行完当前总线周期后向系统DMA控制器发总线响应信号,随即把总线控制权交给DMA控制器,此时DACK1有效。然后DMA控制器将通道1的页面地址寄存器及当前地址寄存器中的内容放到地址总线上去,并发出存储器读命令,读出内存单元中的内容送往数据总线。由于DACK1有效,通过J4短路线选中6116和双向总线驱动器74LS245,IOR有效,通过J2短路线,使6116的RD有效,从而读出6116当前单元的内容,通过74LS245写入到系统数据总线,完成一次DMA写传送。此时通道1当前地址寄存器自动加1,当前字节寄存器自动减1。另外通过U38和JS引线向分频器输入一个进位脉冲,使分频器计数一次,Q10-Q0输出选择6116的下一个单元。再反复上述读过程直到当前字节寄存器为FFFFH为止,写过程结束。
LS393在本实验中的作用作为一个分频器,在本实验中起到了选定存储器6116地址的作用。这是通过输入译码后的进位时钟实现的。
四.实验程序:
DISP MACRO VAR
MOV AH,09H
MOV DX,OFFSET VAR
INT 21H
ENDM
(此宏的功能是将以形参VAR为地址的一个字符串打印在屏幕上)
SCANKEY MACRO
LOCAL LLL
LLL,MOV AH,01H
INT 16H
JZ LLL(等待直到有键按下)
MOV AH,0
INT 16H (将键值保存到AL中)
ENDM
DATA SEGMENT
TEXT DB 'THE QUICK BROWN FOX JUMPS OVER LAZY DOG'
DB 0DH,0AH
DB 'THE QUICK BROWN FOX JUMPS OVER LAZY DOG'
DB 0DH,0AH
DB 'THE QUICK BROWN FOX JUMPS OVER LAZY DOG'
DB 0DH,0AH,'$'
COUNT EQU $-TEXT
BUF DB COUNT DUP(?)
MESG DB 'TO MAKE A DMA REQUEST!'
DB 'THEN STRIKE ANY KEY!',0DH,0AH,'$'
DATA ENDS
STACK SEGMENT STACK 'STACK'
DB 256 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
BEG,MOV AX,DATA MOV DS,AX CALL I8237R
(DMA通道1读入初始化)
DISP MESG (显示操作提示)
SCANKEY LAST1,IN AL,08H(读DMA状态寄存器)
AND AL,02H
JZ LAST1(等待直至传送结束)
CALL I8237(DMA通道1写入初始化)
DISP MESG(显示操作提示)
SCANKEY (等待直到有键按下,读出键值)
LAST2,IN AL,08H(读DMA状态寄存器)
AND AL,02H JZ LAST2(等待直至传输结束)
DISP BUF
(显示BUF中DMA读写传送的最后结果)
MOV AH,4CH
INT 21H (结束程序并返回DOS);*******************************
(DMA通道1读入初始化。)
I8237R PROC MOV AL,05H
OUT 0AH,AL(通道1屏蔽触发器置1)
MOV AL,01001001B (通道1方式字,单字节读传送;自动加1变址,不自动预置)
OUT 0BH,AL MOV AL,0
OUT 0CH,AL(先/后触发器置0)
MOV AX,DATA(AX为TEXT的段基址)
MOV BX,OFFSET TEXT (BX为TEXT的有效地址)
CALL ADDRMOV (计算输出TEXT单元的20位物理地址)
RET
I8237R ENDP;***********************************
(DMA通道1写入初始化)
I8237W PROC
MOV AL,05H
OUT 0AH,AL(通道1屏蔽触发器置1)
MOV AL,01000101B
(通道1方式字,单字节写传送,自动加1变址,不自动预置)
OUT 0BH,AL ;
MOV AL,0
OUT 0CH,AL(先/后触发器置0)
MOV AX,DATA (AX为BUF的段基址)
MOV BX,OFFSET BUF (BX为BUF的有效地址)
CALL ADDRMOV ;计算并输出BUF单元的20位物理地址
RET
I8237W ENDP;****************************
(该函数用以计算
ADDRMOV PROC ;计算并输出某地址
MOV CX,0004H ;计算用AX:BX表示的物理地址
LL,SAL AX,1
RCL CH,1(将移位时的溢出计入CH)
DEC CL
JNZ LL
ADD AX,BX (AX<=AX*4+BX)
JNC NEXT11
INC CH(CH中存放了AX:BX物理地址的高四位。)
NEXT11,OUT 02H,AL ;(低8位存入通道1基本地址寄存器)
MOV AL,AH
OUT 02H,AL ;(中8位存入通道1基本地址寄存器)
MOV AL,CH
OUT 83H,AL ;(高4位存入通道1页面寄存器)
MOV AX,COUNT-1 ;(传送的字节数减1传给基本字节寄存器)
OUT 03H,AL
MOV AL,AH
OUT 03H,AL
MOV AL,01
OUT 0AH,AL ;(解除通道1屏蔽)
RET
ADDRMOV ENDP
CODE ENDS
END BEG

实验总结:
我原本对DMA传输过程不熟悉,这个实验可谓是帮了我大忙。要看懂实验的原理图确实很花时间,但这无疑对了解DMA的特性有重大意义。上面的电路分析是我和同学讨论的结果,如果有错误之处,希望老师指正。
我觉得这个实验创造性显得不足,能否尝试让我们自己设计电路和程序。