存储器读写、中断、8255、8254、数码管显示、模数转换等。
实验01 存储器读写
TPC01-1.ASM
信息显示程序
俺也不清楚能不能麻溜的使用call dispmsg直接显示,对第一个实验印象不深了。
include io.inc
.model small
.stack
.data
msg 'Hello,Assembly!',13,10,0
.code
start:
mov ax,@data
mov ds,ax
mov ah,9
mov dx,offset msg
int 21h
mov ax,4cooh
int 21h
end start
.exit 0
end start
TPC01-2.ASM
存储器的读写
实验报告中已指出:SRAM的段地址为0D000H,而SRAM6264的地址范围为D6000H~D6FFFH,说明初始偏移量为6000H,用“段基地址:偏移地址”(比如es:[bx])即可表示出存储器的位置。对存储器的读和写就是汇编的循环语句问题。
include io.inc
.model small
.stack
.data
msg byte 'start read!',13,10,0
.code
start:
mov ax,@data
mov ds,ax
mov ax,0d000h ;6264段地址
mov es,ax ;段基地址
mov bx,6000h ;偏移地址
mov al,20h ;ASCII码从20H开始
mov cx,95 ;ASCII码有95个字符
push es
push bx
push cx
write:
mov es:[bx],al
inc al
inc bx
loop write
mov ax,offset msg
call dispmsg
call readc
pop cx
pop bx
pop es
read:
mov al,es:[bx]
call dispc
inc bx
loop read
.exit 0
end start
实验04 中断实验
TPC04-1.ASM
主片8259中断实验
该中断属于可屏蔽中断,编程思路与课本例7-6思路一致。因为中断向量号为0BH,所以需要做一些改动。
include io.inc
.model small
.stack
.data
intmsg byte 'TPCA Interrupt No.3!',13,10,0
counter byte 0 ;中断次数
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量表项
mov ax,350bh
int 21h
push es
push bx
cli ;关中断
;设置新中断向量表项
push ds
mov ax,seg new0bh
mov ds,ax
mov dx,offset new0bh
mov ax,250bh
int 21h
pop ds
;获取原IMR
in al,21h
push ax ;push最少跟16位,所以不能用push al
;设置新IMR
and al,0f7h ;11110111
out 21h,al
mov counter,0 ;设置中断次数初值
sti ;开中断
start1:
cmp counter,5
jb start1
cli ;关中断
;恢复IMR
pop ax
out 21h,al
;恢复原中断向量表项
pop dx ;offset
pop ds ;seg
mov ax,250bh
int 21h
sti
.exit 0
new0bh proc
sti
push ax
push si
push ds
mov ax,@data
mov ds,ax
inc counter
mov si,offset intmsg
call dpstri ;不能使用DOS系统功能调用,所以需要调用ROM-BIOS
;EOI
mov al,20h
out 20h,al
pop ds
pop si
pop ax
iret
new0bh endp
dpstri proc ;显示字符串子程序
push ax
push bx
dps1:
mov al,[si]
cmp al,0
jz dps2
mov bx,0
mov ah,0eh
int 10h
inc si
jmp dps1
dps2:
pop bx
pop ax
ret
dpstri endp
end start
TPC04-2.ASM
从片8259中断实验
首先需要修改中断向量号为72H带来的变化。同时,因为是从片,所以需要修改主片的IR2状态和EOI命令。
include io.inc
.model small
.stack
.data
intmsg byte 'TPCA Interrupt No.3!',13,10,0
counter byte 0 ;中断次数
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量表项
mov ax,3572h
int 21h
push es
push bx
cli ;关中断
;设置新中断向量表项
push ds
mov ax,seg new72h
mov ds,ax
mov dx,offset new72h
mov ax,2572h
int 21h
pop ds
;获取原IMR
in al,21h
push ax
;设置新IMR
and al,0fbh ;11111011
out 21h,al
;获取原IMR
in al,0a1h
push ax
;设置新IMR
and al,0fbh ;11111011
out 0a1h,al
mov counter,0 ;设置中断次数初值
sti ;开中断
start1:
cmp counter,5
jb start1
cli ;关中断
;恢复IMR
pop ax
out 0a1h,al
pop ax
out 21h,al
;恢复原中断向量表项
pop dx ;offset
pop ds ;seg
mov ax,2572h
int 21h
sti
.exit 0
new72h proc
sti
push ax
push si
push ds
mov ax,@data
mov ds,ax
inc counter
mov si,offset intmsg
call dpstri
;EOI:先从片后主片
mov al,20h
out 0a0h,al
out 20h,al
pop ds
pop si
pop ax
iret
new72h endp
dpstri proc ;显示字符串子程序
push ax
push bx
dps1:
mov al,[si]
cmp al,0
jz dps2
mov bx,0
mov ah,0eh
int 10h
inc si
jmp dps1
dps2:
pop bx
pop ax
ret
dpstri endp
end start
TPC04-3.ASM
中断嵌套实验
实验3类似于实验1和2的结合,在优先级低的中断服务程序中加入delay函数即可。
实验3:
include io.inc
.model small
.stack
.data
msg3 byte 'TPCA Interrupt No.3!',13,10,0
msg31 byte 'TPCA Interrupt No.3 Again!',13,10,0
msg10 byte 'TPCA Interrupt No.10!',13,10,0
msg101 byte 'TPCA Interrupt No.10 Again!',13,10,0
counter3 byte 0
counter10 byte 0
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量表项
mov ax,350bh
int 21h
push es
push bx
mov ax,3572h
int 21h
push es
push bx
cli
;设置新中断向量表项
push ds
mov ax,seg new0bh
mov ds,ax
mov dx,offset new0bh
mov ax,250bh
int 21h
pop ds
push ds
mov ax,seg new72h
mov ds,ax
mov dx,offset new72h
mov ax,2572h
int 21h
pop ds
;获取原IMR(主)
in al,21h
push ax
;设置新IMR(主)
and al,0f3h ;11110011
out 21h,al
;获取原IMR(从)
in al,0a1h
push ax
;设置新IMR(从)
and al,0fbh ;11111011
out 0a1h,al
mov counter3,0 ;设置中断次数初值
mov counter10,0
sti ;开中断
start1:
cmp counter3,5
jb start1
start2:
cmp counter10,5
jb start2
cli ;关中断
;恢复IMR
pop ax
out 0a1h,al
pop ax
out 21h,al
;恢复原中断向量表项
pop dx ;offset
pop ds ;seg
mov ax,2572h
int 21h
pop dx
pop ds
mov ax,250bh
int 21h
sti
.exit 0
new0bh proc
sti
push ax
push si
push ds
mov ax,@data
mov ds,ax
inc counter3
mov si,offset msg3
call dpstri
call delay
mov si,offset msg31
call dpstri
;EOI
mov al,20h
out 20h,al
pop ds
pop si
pop ax
iret
new0bh endp
new72h proc
sti
push ax
push si
push ds
mov ax,@data
mov ds,ax
inc counter10
mov si,offset msg10
call dpstri
call delay
mov si,offset msg101
call dpstri
;EOI
mov al,20h
out 0a0h,al
out 20h,al
pop ds
pop si
pop ax
iret
new72h endp
dpstri proc ;显示字符串子程序
push ax
push bx
dps1:
mov al,[si]
cmp al,0
jz dps2
mov bx,0
mov ah,0eh
int 10h
inc si
jmp dps1
dps2:
pop bx
pop ax
ret
dpstri endp
delay proc
push bx
push cx
mov bx,2000
delay1:
xor cx,cx
delay2:
loop delay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start
实验05 可编程定时器/计数器(8253/8254)
TPC05-1.ASM
编程记录脉冲个数
通过计数器0的I/O端口号读取计数器当前计数值,如果相同则继续说明没有经过一个时钟周期,反复读取,直到计数值变化,输出计数值。若计数未结束(计数值不为0),则循环上述步骤。
include io.inc
.model small
.stack
.data
.code
start:
mov ax,@data
mov ds,ax
;写入方式控制字
mov dx,283h
mov al,10h ;00010000
out dx,al
;写入计数值
mov dx,280h
mov al,5
out dx,al
mov ah,al
again:
;反复读取计数值需要加延时
call delay
in al,dx
cmp al,ah
jz again ;计数值没变
call dispuib
call dispcrlf
mov ah,al
cmp al,0
jnz again ;计数未结束
.exit 0
delay proc
push bx
push cx
mov bx,2000
delay1:
xor cx,cx
delay2:
loop dalay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start
TPC05-2.ASM
编程输出一定频率的方波信号
方波信号应该选用方式3,在设定好初始化程序后,8254芯片就可以周期性地生成方波了
include io.inc
.model small
.stack
.data
.code
start:
mov ax,@data
mov ds,ax
;写入方式控制字(计数器0)
mov dx,283h
mov al,37h ;00110111
out dx,al
;写入计数初值
mov dx,280h
mov ax,1000h
out dx,al
mov al,ah
out dx,al
;写入方式控制字(计数器1)
mov dx,283h
mov al,76h ;01110110
out dx,al
;写入计数初值
mov dx,281h
mov ax,1000
out dx,al
mov al,ah
out dx,al
.exit 0
end start
TPC05-3.ASM
实现定时1秒的功能
这道题与课本上例7-6完全一样,例7-6的前提是该PC系统的IRQ来源于定时器,这里我们只需要补充定时器的实现细节即可(即定时器的初始化操作)
include io.inc
.model small
.stack
.data
intmsg byte 'Interrupt.',13,10,0
counter byte 0
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量
mov ax,350bh
int 21h
push es
push bx
;设置新中断向量
cli
push ds
mov ax,seg new0bh
mov ds,ax
mov dx,offset new0bh
mov ax,250bh
int 21h
pop ds
;获取原IMR
in al,21h
push ax
;设置新IMR
and al,0f7h ;11110111
out 21h,al
;8253/8254初始化
;计数器0
mov dx,283h
mov al,37h ;00110111
out dx,al
mov ax,1000h
mov dx,280h
out dx,al
mov al,ah
out dx,al
;计数器1
mov dx,283h
mov al,77h ;01110111
out dx,al
mov ax,1000h
mov dx,281h
out dx,al
mov al,ah
out dx,al
mov counter,0
sti
start1:
cmp counter,5
jb start1
;恢复
cli
pop ax
out 21h,al
pop dx
pop ds
mov ax,250bh
int 21h
sti
.exit 0
new0bh proc
sti
push ax
push si
push ds
mov ax,@data
mov dx,ax
inc counter
mov si,offset intmsg
call dpstri
mov al,20h
out 20h,al
pop ds
pop si
pop ax
iret
new0bh endp
dpstri proc
push ax
push bx
dps1:
mov al,[si]
cmp al,0
jz dps2
mov bx,0
mov ah,0eh
int 10h
inc si
jmp dps1
dps2:
pop bx
pop ax
ret
dpstri endp
end start
实验06 可编程并行接口(8255)
TPC06-1.ASM
方式0(基本输入输出)实验
先初始化,再对数据端口读写即可。 其中,端口A为方式0输出,端口C为方式0输入(输入信号为K0~K7),端口B任意。
include io.inc
.model small
.stack
.data
.code
start:
mov ax,@data
mov ds,ax
mov dx,28bh
mov al,89h ;10001001
out dx,al
mov dx,28ah
in al,dx
mov dx,288h
out dx,al
.exit 0
end start
TPC06-2.ASM
方式1(选通)输出实验
中断服务程序,中断的来源是手动按一次单脉冲按钮。我们只需要完善8255的初始化程序和把中断服务程序修改为数据端口的写操作即可。
include io.inc
.model small
.stack
.data
msg byte 01h
counter byte 0
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量
mov ax,350bh
int 21h
push es
push bx
;设置新中断向量
cli
push ds
mov ax,seg new0bh
mov ds,ax
mov dx,offset new0bh
mov ax,250bh
int 21h
pop ds
;获取原IMR
in al,21h
push ax
;设置新IMR
and al,0f7h ;111101111
out 21h,al
mov counter,0
;8255初始化
mov al,0a0h ;10100000h
mov dx,28bh
out dx,al
sti
start1:
cmp counter,8
jb start1
;恢复
cli
pop ax
out 21h,al
pop dx
pop ds
mov ax,250bh
int 21h
sti
.exit 0
new0bh proc
sti
inc counter
call litlight
;EOI
mov al,20h
out 20h,al
iret
new0bh endp
litlight proc
mov al,msg
call disphb
call dispcrlf
mov dx,288h
out dx,al
rol light,1
ret
litlight endp
end start
TPC06-3.ASM
方式1(选通)输入实验
中断仍由手动产生,和上一个实验一样,我们只需完善8255的初始化程序和修改中断服务程序。
include io.inc
.model small
.stack
.data
counter byte 0
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量
mov ax,350bh
int 21h
push es
push bx
;设置新中断向量
cli
push ds
mov ax,seg new0bh
mov ds,ax
mov dx,offset new0bh
mov ax,250bh
int 21h
pop ds
;获取原IMR
in al,21h
push ax
;设置新IMR
and al,0f7h ;111101111
out 21h,al
mov counter,0
;8255初始化
mov al,0b0h ;10110000
mov dx,28bh
out dx,al
sti
start1:
cmp counter,5
jb start1
;恢复
cli
pop ax
out 21h,al
pop dx
pop ds
mov ax,250bh
int 21h
sti
.exit 0
new0bh proc
sti
inc counter
call displed
;EOI
mov al,20h
out 20h,al
iret
new0bh endp
displed proc
mov dx,288h
in al,dx
call disphb
call dispcrlf
ret
displed endp
end start
实验08 数码管显示
TPC08-1.ASM
一位静态显示
输入一个数,通过并行接口8255传给数码管,这里涉及8255的初始化编程。因为传给数码管的数需要让其对应段发亮,所以需要换码操作。因为已经通过硬件方式选中S3,所以只需要关注段控制,将段表提前写好进行换码即可。
include io.inc
.model small
.stack
.data
ledtb byte 3fh,06h,5bh,4fh,66h
byte 6dh,7dh,07h,7fh,6fh
.code
start:
mov ax,@data
mov ds,ax
;8255初始化
mov dx,28bh
mov al,80h ;10000000
out dx,al
;1位数码管显示
call readuiw ;出口参数为ax
mov bx,ax
mov al,ledtb[bx] ;换码为显示代码
mov dx,288h
out dx,al
.exit 0
end start
1234567891011121314151617181920212223242526
TPC08-2.ASM
多位动态显示
让处理器通过8255传给段控制端口段显示代码,然后传给位控制端口位显示代码,顺序地输出段码和位码,依次让每个数码管显示数字,并不断重复显示。为此,可以开辟一个数码缓冲区,存放要显示地数字,第一个数字在最左边地数码管显示,下一个数字送到左边第二个数码管显示,以此类推,利用rol指令即可实现这一过程。和课本不同之处在于课本是循环8位,而实验要求循环4位,需稍加修改。
include io.inc
.model small
.stack
.data
leddt byte 3,4,5,6 ;存放要显示的数字
ledtb byte 3fh,06h,5bh,4fh,66h
byte 6dh,7dh,07h,7fh,6fh
.code
start:
mov ax,@data
mov ds,ax
;8255初始化
mov al,80h ;10000000
mov dx,28bh
out dx,al
mov si,offset leddt
call displed
displed proc
push ax
push bx
push dx
again:
xor bx,bx
;选中最左边的数码管
;也有可能是最右边...
mov ah,01h ;位码00000001
led1:
mov bl,[si]
mov al,ledtb[bx] ;换码
mov dx,288h ;段控制端口
out dx,al
mov al,ah
mov dx,289h ;位控制端口
out dx,al
call delay
inc si
rol ah,1 ;指向下一个数码管
;是否循环一个周期
cmp ah,10h ;00010000
jz again
jmp led1
pop dx
pop bx
pop ax
ret
displed endp
delay proc
push bx
push cx
mov bx,5
delay1:
xor cx,cx
delay2:
loop delay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start
TPC08-3.ASM
多位循环显示
俺这道题不会,下面的代码感觉不怎么对。为了应付期末考试的话可以不用看这个了(追求满绩也不用看)
include io.inc
.model small
.stack
.data
buf byte 0,0,0,0 ;存放要显示的数字
ledtb byte 3fh,06h,5bh,4fh,66h
byte 6dh,7dh,07h,7fh,6fh
.code
start:
mov ax,@data
mov ds,ax
;8255初始化
mov dx,28bh
mov al,80h
out dx,al
start1:
xor si,si
mov ah,08h ;位码
again:
mov bl,buf[si]
mov bh,0
mov al,led[bx]
mov dx,288h
out dx,al ;段
mov al,ah
mov dx,289h
out dx,al ;位
call delay
inc si
shr ah,1
jnz again
mov bl,buf+3 ;要显示的数加1
inc bl
cmp bl,10
jb next3
mov bl,0
mov bh,buf+2
inc bh
cmp bh,10
jb next2
mov bh,0
mov cl,buf+1
inc cl
cmp cl,10
jb next1
mov cl,0
mov ch,buf
inc ch
cmp ch,10
jb next0
mov ch,0
next0:
mov buf,ch
next1:
mov buf+1,cl
next2:
mov buf+2,bh
next3:
mov buf+3,cl
.exit 0
delay proc
push bx
push cx
mov bx,5
delay1:
xor cx,cx
delay2:
loop delay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start
实验10 模/数转换器
TPC10-1.ASM
软件延时方式
软件延时方式不需要考虑EOC信号,因此只需要应用out和in指令实现对ADC0809进行启动和读数据两个操作即可。
include io.inc
.model small
.stack
.data
msg byte 'press any key to exit',13,10,0
.code
start:
mov ax,@data
mov ds,ax
mov ax,offset
call dispmsg
again:
mov dx,298h ;启动ADC
out dx,al
call delay
in al,dx ;从ADC读入数据
call disphb
call dispcrlf
call readkey
jz again
.exit 0
delay proc
push bx
push cx
mov bx,2000
delay1:
xor cx,cx
delay2:
loop delay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start
TPC10-2.ASM
查询方式
查询方式两步走:循环+test
include io.inc
.model small
.stack
.data
.code
start:
mov ax,@data
mov ds,ax
;8255的初始化
mov al,88h ;10001000(PC7作输入端)
mov dx,28bh
out dx,al
start1:
mov dx,298h ;启动ADC
out dx,al
call delay
mov dx,28ah ;端口C
start2:
in al,dx
test al,80h ;10000000
jz start2
mov dx,298h
in al,dx ;读取数字量
call disphb
call dispcrlf
jmp start1
.exit 0
delay proc
push bx
push cx
mov bx,2000
delay1:
xor cx,cx
delay2:
loop delay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start
TPC10-3.ASM
中断方式
中断方式的编程已经很熟悉了,和之前的处理方法一样。我们需要设置好中断服务程序之前的环境和修改相应的中断服务程序。
include io.inc
.model small
.stack
.data
counter byte 0
.code
start:
mov ax,@data
mov ds,ax
;获取原中断向量
mov ax,350bh
int 21h
push es
push bx
;设置新中断向量
cli
push ds
mov ax,seg new0bh
mov ds,ax
mov dx,offset new0bh
mov ax,250bh
int 21h
pop ds
;获取原IMR
in al,21h
push ax
;设置新IMR
and al,0f7h ;111101111
out 21h,al
mov counter,0
;启动ADC
mov dx,298h
out dx,al
call delay
sti
start1:
cmp counter,10
jb start1
;恢复
cli
pop ax
out 21h,al
pop dx
pop ds
mov ax,250bh
int 21h
sti
.exit 0
new0bh proc
sti
inc counter
;读取并显示数字量
mov dx,298h
in al,dx
call disphb
call dispcrlf
;EOI
mov al,20h
out 20h,al
iret
new0bh endp
delay proc
push bx
push cx
mov bx,2000
delay1:
xor cx,cx
delay2:
loop delay2
dec bx
jnz delay1
pop cx
pop bx
ret
delay endp
end start