前言
做这个实验耗时近半天,其中安装虚拟机5小时,编写程序3小时。
踩过不少的坑,比如说一开始一直显示不出来usb插件,最后发现是开关没开;又比如,程序逻辑没有问题,但始终显示不出正确的结果,最后发现是先连接反了…不过好在,在一天快要结束的时候和搭档一起完成了实验。成就感满满,虽然本人没怎么参与编写代码
实验目的
掌握8255A和微机接口的连接方法,了解8255A的基本的工作原理和编程方法。
实验内容
PA口接8个拨动开关K1-K8,PB口接8个LED。初始由开关K1-K8设定8位不同的值,当执行程序后LED按K1-K8初始设定的值点亮,并向右流动。8255工作在0方式。
实验编程提示
在LED右流水中,如果开关的位置发生了变化,LED右流水从变化的位置重新开始。
提示:程序要能检测到某个时间开关状态的变化,并针对变化后的开关状态右流水,因此程序中要有两个变量,一个保存当前开关的状态以检测开关状态是否发生了变化,一个存LED右流水的状态,以便使LED连续右流动。为了使流水显示明显,每个位置应加延时程序。
连线图
注意那个美丽的彩虹线不要接反了,要一一对应(是个坑!!
代码分解
数据段初始化端口地址
DSEG SEGMENT
PORTA EQU 280H; A端口
PORTB EQU 281H; B端口
PORTD EQU 283H; 命令与状态口
DSEG ENDS
方式命令设置
PA口接8个拨动开关K1-K8所以为1输入,PB口接8个LED所以为0输出。
MOV DX,PORTD
MOV AL,90H;1001 0000 初始化命令:A端口0方式输入,B端口0方式输出
OUT DX,AL;将初始化命令输入到命令状态口
保存最开始的流水状态
MOV DX,PORTA;
IN AL,DX; 输入初始开关状态到AL
MOV CL,AL; CL保存流水状态
MOV BL,AL; BL保存旧的开关状态, 在此初始化BL
亮灯
这个点,不理解之前觉得好难,理解了之后觉得不过如此——无非就是读PA处的代码,然后输出到PB去,由于都是八位,只需要一个中间寄存器CL。
MOV AL,CL; AL中存入流水线状态
MOV DX,PORTB;
OUT DX,AL; 灯亮
控制时延
要让灯亮就必须控制延长时间啊,一次循环最多ffffh,那就多来几个循环呗!哈哈哈
DELAY1 PROC ;子程序
mov cx,25
AGAIN:
mov dx,0ffffh
delay:dec dx
jnz delay
LOOP AGAIN
RET
DELAY1 ENDP
流水灯流动
软件控制硬件,也就是靠程序实现实际功能。如下一行代码,令人叹服!妙哉妙哉。
ROR AL,1;右移一个灯
核心
救命,我的字好吃藕
CL负责控制当前该亮的灯,在light程序段中负责控制灯的亮和延时.
而BL,BH分别保存上一时刻的开关和现在的开关,注意这里每移动一个灯就判断一次。
MOV DX,PORTA
IN AL,DX
MOV BH,AL; BH存放新的开关状态
CMP BH,BL; 判断开关状态是否发生改变
JZ LIGHT; 如果开关状态未变,则调转到LIGHT
MOV BL,BH; 否则旧的开关状态变为新状态
MOV CL,BL; 把当前开关状态存入CL, 更新流水线状态
代码
下面这个是第一次写的。漏洞百出…而且写的很不美观,看着乐呵乐呵就好,比如那个可怕的delay大循环hhh惨不忍睹,最后趁着老师还在检查别人代码的时候改成了使用双层函数,此外也调了很多很多的不过。
.model small
.386 ;老师说要加...
DSEG SEGMENT
PORTA EQU 280H; A端口
PORTB EQU 281H; B端口
PORTD EQU 283H; 命令与状态口
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX,DSEG;
MOV DS,AX;
MOV DX,PORTD
MOV AL,90H;1001 0000 初始化命令:A端口0方式输入,B端口0方式输出
OUT DX,AL;将初始化命令输入到命令状态口
MOV DX,PORTA;
IN AL,DX; 输入初始开关状态到AL
MOV CL,AL; CL保存流水状态
MOV BL,AL; BL保存旧的开关状态, 在此初始化BL
LP1:
MOV DX,PORTA
IN AL,DX
MOV BH,AL; BH存放新的开关状态
CMP BH,BL; 判断开关状态是否发生改变
JZ LIGHT; 如果开关状态未变,则调转到LIGHT
MOV BL,BH; 否则旧的开关状态变为新状态
MOV CL,BL; 把当前开关状态存入CL, 更新流水线状态
LIGHT:
MOV AL,CL; AL中存入流水线状态
MOV DX,PORTB;
OUT DX,AL; 灯亮
mov bx,0ffffh;
delay:dec bx
jnz delay
mov bx,0ffffh
delay1:dec bx
jnz delay1
mov bx,0ffffh
delay2:dec bx
jnz delay2
mov bx,0ffffh
delay3:dec bx
jnz delay3
mov bx,0ffffh
delay4:dec bx
jnz delay4
mov bx,0ffffh
delay5:dec bx
jnz delay5
mov bx,0ffffh
delay6:dec bx
jnz delay6
ROR AL,1;右移一个灯
MOV CL,AL; CL 保存下一个要亮的灯
JMP LP1;
CSEG ENDS
END START
.model small
.386 ;老师说要加...
DSEG SEGMENT
PORTA EQU 280H; A端口
PORTB EQU 281H; B端口
PORTD EQU 283H; 命令与状态口
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX,DSEG;
MOV DS,AX;
MOV DX,PORTD
MOV AL,90H;1001 0000 初始化命令:A端口0方式输入,B端口0方式输出
OUT DX,AL;将初始化命令输入到命令状态口
MOV DX,PORTA;
IN AL,DX; 输入初始开关状态到AL
MOV CL,AL; CL保存流水状态
MOV BL,AL; BL保存旧的开关状态, 在此初始化BL
LP1:
MOV DX,PORTA
IN AL,DX
MOV BH,AL; BH存放新的开关状态
CMP BH,BL; 判断开关状态是否发生改变
JZ LIGHT; 如果开关状态未变,则调转到LIGHT
MOV BL,BH; 否则旧的开关状态变为新状态
MOV CL,BL; 把当前开关状态存入CL, 更新流水线状态
LIGHT:
MOV AL,CL; AL中存入流水线状态
MOV DX,PORTB;
OUT DX,AL; 灯亮
CALL DELAY1
ROR AL,1;右移一个灯
MOV CL,AL; CL 保存下一个要亮的灯
JMP LP1;
DELAY1 PROC ;子程序
mov cx,25
AGAIN:
mov dx,0ffffh
delay:dec dx
jnz delay
LOOP AGAIN
RET
DELAY1 ENDP
CSEG ENDS
END START
又是一个被汇编实验折磨的夜晚啊