北邮微机原理硬件实验二,8255A并行接口应用。基于8086的汇编编程实现。
嗯,已经第二次实验了。第一次实验看了学长的代码,已经学到不少东西了,这一次该自己好好写了!
实验要求
简要说明
在方式0(输入/输出)下,以A口为输出口,B口为输出口, A口接六个共阴极数码管的八位段码,高电平点亮数码管的某一段, B口接数码管的位选(即要使哪个数码管亮),高电平选中某一位数码管点亮。
8255A中 A端口地址 EE00H
B端口地址 EE01H
C端口地址 EE02H
控制地址 EE03H
八段数码管的显示规律及数码管的位选规律自己查找,可用实验一中,学过的I、O命令来做。
6位数码管静态显示
在数码管电路上静态地显示6位学号,当主机键盘按下任意键时,停止显示,返回DOS。提示:该电路6个数码管的同名阳极段已经复接,当段选寄存器寄存了一个字型编码之后,6个数码管都有可能显示出相同的数字。如果要使6个数码管“同时”显示不同的数字,必须采用扫描显示的方法,通过选位寄存器选择某一位数码管,显示其数字(对应段值为1),然后关闭此数码管,再选择下一位数码管进行显示;如果在一秒钟内,每一位数码管都能显示30次以上,则人眼看到的是几位数码管同时在显示。
实验证明,在扫描显示过程中,每一位显示延迟1ms是最佳选择。
6位数码管动态显示
要求在数码管电路1-6位数码管上按图3.2所示的规律,动态显示字符串HELLO,当主机键盘按下任意键时结束。
提示:
①本实验应在上面实验的基础上完成
②在数据段,按下列规律设置12个字型码:
MESG DB 0,0,0,0,0,0,3DH,0DCH,8CH,8CH,0EDH,0
POINT DW MESG
… …
POINT单元存放MESG单元的有效地址,程序取出POINT单元的内容→BX,然后用BX间址取数送数码管电路,扫描显示6个字符。每过0.5s将POINT单元的内容加1,再将POINT单元的内容→BX,……。POINT单元内容加1,使字符串显示的首地址向高地址移动一个单元,从而使6位字符串向“左”移动一位,实现动态显示。
③动态显示的速度可控制(快或慢),利用实验一读入端口的功能
编程思路
要干掉这么一坨东西,还真是很头痛。
实验一已经学习过怎么对程序进行分块了,也知道如何使用变量了。
要实现6个数显管“同时显示数字”,出于节省引脚的考虑,我们也只能运用时分复用,每次只亮一个数显管,显示该数显管的数字,然后切换到下个数显管显示下一个数字,当扫频速度足够快时,就可以做出“同时显示”的效果了。嗯,各种实验都做过很多次数显管显示了,网上也有很多资料,不累赘了。
本实验还要使用8255A用作输出,可以下载到它的Data Sheet用作参考。
伪代码:
int main()
{
initialize();
while(1){
read_switch(); // Read switch state.
out_cat(); // Turn the next ONE Nixie-tube on.
out_led(); // Display the current number.
delay(); // Have some delay.
return_to_DOS(); // Check if switch state acquires exit.
}
return 0;
}
源代码
; Exercise 2: Nixie_tube Display
; AUTHOR: feichashao
; DATE: 2013-12-7
DATA SEGMENT
CatState DB 01H
STUDENT DB 00H,0F4H,21H,0EDH,0F1H,61H,61H,00H
HELLO DB 00H,03DH,0DCH,8CH,8CH,0EDH,00H,00H
DIGIT DB 00H
COUNT DW 0000H
SwState DB 0
DATA ENDS
STACK SEGMENT STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
Main PROC
PUSH DS
XOR AX,AX
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV CatState,1H
MOV DIGIT,1H
CALL Initialize
CALL EndlessRepeat
RET
Main ENDP
Initialize PROC
PUSH DX
PUSH AX
MOV AL,80H
MOV DX,0E803H
OUT DX,AL
POP AX
POP DX
RET
Initialize ENDP
EndlessRepeat PROC
EndlessLoop: CALL ProcToRepeat
JMP EndlessLoop
RET
EndlessRepeat ENDP
ProcToRepeat PROC
CALL readSw
CALL outCat
CALL outLED
CALL excuteDelay
CALL returnToDOS
ProcToRepeat ENDP
readSw PROC
PUSH AX
PUSH DX
MOV DX,0E8E0H
IN AL,DX
MOV SwState,AL
POP DX
POP AX
readSw ENDP
DivFreq PROC
PUSH CX
MOV CX,0100H
MyLoop: PUSH CX
MOV CX,0800H
MyNestedLoop: DEC CX
JNZ MyNestedLoop
POP CX
DEC CX
JNZ MyLoop
POP CX
RET
DivFreq ENDP
outCat PROC
CMP COUNT,00FFH
JZ MOVECAT
ROL CatState,01H
PUSH DX
PUSH AX
MOV AL,CatState
MOV DX,0E801H
OUT DX,AL
POP AX
POP DX
RET
MOVECAT: ROL CatState,01H
ROL CatState,01H
MOV COUNT,0000H
RET
outCat ENDP
outLED PROC
INC DIGIT
; TEST DIGIT,06H
CMP DIGIT,08H
JNC CLEAR
PUSH DX
PUSH AX
PUSH BX
MOV BL,DIGIT
MOV BH,0H
TEST SWSTATE,01H
JNZ printHello
MOV AL,STUDENT[BX]
MOV DX,0E800H
OUT DX,AL
POP BX
POP AX
POP DX
RET
printHello: MOV AL,HELLO[BX]
; MOV AL,DS:[BX]
MOV DX,0E800H
OUT DX,AL
; MOV DX,0E8E0H
; OUT DX,AL
POP BX
POP AX
POP DX
RET
CLEAR: MOV DIGIT,00H
RET
outLED ENDP
excuteDelay PROC
CALL DIVFREQ
TEST SWSTATE,01H
JZ exitDelay
INC COUNT
exitDelay: RET ; Do Nothing this time.
excuteDelay ENDP
returnToDOS PROC
TEST SWSTATE,02H
JZ exitReturnToDOS
CALL exereturnToDOS
exitReturnToDOS: RET
returnToDOS ENDP
exereturnToDOS PROC
MOV AX,4C00H
INT 21H
exereturnToDOS ENDP
CODE ENDS
END MAIN
数显管亮灭控制
控制6位数显管的亮灭,1为亮,0为灭。
我们可以用一个8bits的变量,来记录和控制这6位数显管的状态。
初始状态
CatState DB 00000001B
要显示下一个数字的时候,只要对CatState进行左移一位就可以了。
但是,这个数据是8位的,但实际只显示6位,所以学号的数据一定要有8位,填充两个无意义的字符即可。
(前后的00H都是不显示的,占个坑就好。)
STUDENT DB 00H,0F4H,21H,0EDH,0F1H,61H,61H,00H
动态显示“HELLO”
要求显示的“HELLO”看上去是移动的。
实现的方法其实很简单,只要每隔1秒,将数显管的控制变量CatState多移动一位就好,其他的还是按原来的样。
吐槽
上课之前,碰到一女生。她实验一的代码,是自己写的。(天啊,这是什么一个时代,抄袭代码竟然是常态。)
然后她上周的实验,辛辛苦苦写了半天代码,却因为功能不全,而得了低分。
像我这些,直接挪用学长代码,三下两下完成实验的,却得了高分。
所以她说,这次实验就改用别人代码了。
大学教育就是这么引导的?
我也因为这个实验没有按时完成,被老师不爽了一下。
不爽就不爽吧,反正学到的是自己的。