基于Proteus的16路流水灯实验(汇编语言)
实验内容
采用proteus仿真16路流水灯。编写程序,使8255的A口和B口均为输出,数据灯D8~D1 由左向右,每次仅亮一个灯,循环显示,D16~D9 与D8~D1正相反,由右向左,每次仅点亮一个灯,循环显示。
电路连接图
最小系统
电路连接总图
程序代码
DATA SEGMENT
IOCON EQU 0B006H ;0000 1011 0000 0000 0110 ;8255控制端口地址
IOA EQU 0B000H ;0000 1011 0000 0000 0000 ;8255 A口地址
IOB EQU 0B002H ;0000 1011 0000 0000 0010 ;8255 B口地址
IOC EQU 0B004H ;0000 1011 0000 0000 0100 ;8255 C口地址
DATA ENDS
STACKS SEGMENT
DW 100h DUP(?)
STACKS ENDS
CODE SEGMENT
ASSUME CS:CODE,SS:STACKS,DS:DATA
START:
MOV DX,IOCON ;输控制字
MOV AL,80H ;1000 0000
;标志位为1(D7=1),A口模式选用模式0(D6=0, D5=0)
;A口输出(D4=0)
;C口输入输出均可,默认选输出,即D3=0和D0=0
;B口模式选用模式0(D2=0),同时B口也输出(D1=0)
OUT DX,AL
;这里用BL和BH的目的是为了保存端口值
;因为输入输出指令(IN,OUT)的目的操作数只能是AL或AX
MOV BL, 01111111B ;初始化,这里因为是低电平亮,所以初始置D8亮
;这里要注意0111 1111从左往右是高位到低位的变化,即0为高位
MOV BH, 11111110B ;这里同理,也是初始化
;0位最低位,对应电路图中的D9亮
ENDLESS:
MOV AL,BL ;将BL值赋给AL,便于输出
MOV DX,IOA ;A端口进行输出,就是将BL的值进行输出
;比如初始时BL值为0111 1111
;那么A口输出后,PA7~PA0的值依次为01111111,从而就使得D8灯亮
OUT DX,AL
MOV AL,BH ;将BH值赋给AL,便于输出
MOV DX,IOB ;B端口进行输出,就是将BH的值进行输出
OUT DX,AL ;比如初始时BH值为1111 1110,那么B口输出后
;PB7~PB0的值依次为11111110,从而就使得D9灯亮
CALL DELAY0 ;调用延时子程序
;目的是为了让相邻两灯亮时有一小段停留时间
MOV CL,1
ROR BL,CL ;将BL循环右移一位,达到每次只点亮一个灯
ROL BH,CL ;将BH循环左移一位,达到每次只点亮一个灯
;这里一个循环左移,一个循环右移就是为了到达相反亮的目的
JMP ENDLESS ;循环显示灯亮
DELAY0 PROC
PUSH CX
MOV CX,0
LOOP $
LOOP $
LOOP $
MOV CX,15000
LOOP $
POP CX
RET
DELAY0 ENDP
CODE ENDS
END START
补充说明
对于程序中端口地址的定义取决于电路连接图中的最小系统。
比如本篇文章中搭建的这个最小系统中,8255A控制端口地址为1011 0000 0000 0110 ,A端口地址为1011 0000 0000 0000 ,B端口地址为1011 0000 0000 0010 ,C端口地址为1011 0000 0000 0100 。
因为8255A CS ‾ \overline{\text{CS}} CS接的是IO3,对应74HC138中A12,A13,A14对应的值为011,由于74HC138接的是A15,所以A15的值为1,所以8255各端口值的高4位都是1011,又由于8255A芯片的A0端和A1端接的是A1和A2(注意这里8255A的A0端接的是A1,A1端接的是A2),所以当选择控制端口操作时A1和A2为11,当选择A端口操作时A1和A2为00,当选择B端口操作时A1和A2为01,当选择C端口操作时A1和A2为10。这样就得出了不同端口对应的端口值。
在dosbox中最小系统对应的8255A控制端口地址为63H,A端口地址为60H,B端口地址为61H,C端口地址为62H。在实验箱中就可能又是另外一个地址。总而言之,不同系统对应的芯片端口值不一样,这个需要注意一下。