合肥工业大学
计算机与信息学院
课程设计
课 程:微机原理与接口技术设计
专业班级:计算机科学与技术x班
学 号:
姓 名:
一、设计题目及要求:
【课题6】 数字时钟
1. 通过 8253 定时器作产生秒脉冲定时中断。 在中断服务程序中实现秒、 分、 小时的进位 (24小时制) 。
2.在七段数码管上显示当前的时分秒(例如,12 点 10 分 40 秒显示为 121040) 。
3.按“C”可设置时钟的时间当前值(对准时间) 。
二、设计思想:
总体思想:
1、功能概述:
实验箱连线:
本实验建立在Dais实验箱基础上完成的基本连线及程序如下:
138译码器:
A,B,C,D,分别连接A2,A3,A4,GS;
y0连接8253的CS片选信号;
y1连接8259的CS片选信号;
8253连线:
分频信号T2接8253的 CLK0;
8253的OUT0接8259的IR7;
8253的gate信号接+5V;
8259连线:
8259的数据线接入数据总线;
本程序包括显示模块,键盘扫描模块,时间计数模块,设置模块等几个模块,
(1)程序运行后,LED显示000000初始值,并且开始计数
(2)按C键进行设置初始时间,考虑到第一个数只能是0,1,2,当第一个数显示2时第二个数只能显示0~4,同理下面各位应满足时钟数值的合理的取值;
(3)在手动输入初始值时,按D键进行回退1位修改已设置值,连续按D键可以全部进行删除修改。
2、主程序设计
主程序中完成通过调用子程序完成对8253及8259的初始化,对8259进行中断设置。主要在显示子程序和键盘子处理程序之间不断循环,8253每一秒给8259一个刺激,当8259接受到刺激后会给CPU一个中断请求,CPU会转去执行中断子程序,而中断子程序设置成时间计数加,即完成电子表的整体设计。详细流程图见图三-1。
3、LED显示子程序设计
本程序显示部分用了6个共阳极LED作为显示管,显示程序要做到每送一次段码就送一次位码,每送一次位码后,将位码中的0右移1位作为下次的位码,从而可以实现从左到右使6个LED依次显示出相应的数字。虽然CPU每隔一定时间便执行显示程序,但只要这个时间段不太长,由于人眼的视觉作用,就可以在6个LED上同时见到数字显示。
4、键盘扫描子程序设计
本程序需要用键盘对时间的初始值进行设置,因此对键盘扫描的子程序需要满足的功能如下:
判断是否是C键,若不是就返回至主程序,若是C键就开始对时间初始值进行设置,同时因注意到第一个值不可以超过2,第一个数是2时第二数不能超过4,余下的同理要满足时间数值的取值范围呢,若不是合法输入不予反应继续等待输入。当遇到输入数值错误时可以按下D键进行删除一位重新设置;当6位初始值全部设置成功后,电子表将自动开始走表。
5、时间运算子程序设计
该子程序的主要功能是对时、分、秒的运算,并把运算出的最终结果存到事先已经开辟的内存单元里,以便显示模块即时地显示出来。该模块可以细分为秒定时模块和运算模块。定时模块交由8253通过对分频出来的频率进行放大至1秒,因此每隔1秒对8259进行刺激,进而使CPU处理中断子程序及时间运算的子程序。另外,在中断服务程序里,必须对秒、分和时的单元内的数值进行判断,当秒加到60时,分必须加1 、秒清零;当分加到60时,时加1、分清零。当时加到24时,直接清零。
6、中断设置
8259芯片:在该系统中,8259主要担负着处理8253的一秒时间的脉冲信号,通过8253的每秒的刺激下向CPU发送中断请求,进而CPU处理担负时间计算的中断子程序,即可完成每秒钟时间自加1秒的功能,因此8259的设置应为:
ICW1:单片,边沿触发,写入ICW4
ICW2:写入08H
ICW3:
7、定时器设置
8253芯片:在系统中定时/计数芯片8253主要与CPU及中断扩展芯片8259之间存在着连接关系。8253主要担负着时间计时的功能,通过对分频单元提供的频率信号进行方法产生一秒时间为周期的脉冲信号,因此8253的设置应为:
控制口写入:00110100b;计算器0选择先低后高两字节读或写 方式2 二进制计数;
计数器0写入:38400;时间系数通过计算可以产生1秒的脉冲信号;
8、编址及控制字确定
(1)8259端口及控制字设置:
Port_8259_0 EQU 0FFE0H
Port_8259_1 EQU 0FFE1H
8259初始化设置:
ICW1:00010011,边沿触发,单片方式,写入ICW4;
ICW2:00001000,
INIT8259:
MOV AL,13H
MOV DX,Port_8259_0
OUT DX,AL
MOV AL,08H
MOV DX,Port_8259_1
OUT DX,AL
MOV AL,09H
OUT DX,AL
MOV AL,7FH ;IRQ7
OUT DX,AL
RET
(2)8253端口及控制字设置:
Port_8253_00 EQU 0FFE4H
Port_8253_01 EQU 0FFE5H
Port_8253_10 EQU 0FFE6H
Port_8253_11 EQU 0FFE7H
8253初始化设置:
initCLK0:
mov dx,Port_8253_11
mov al,00110100b ;
out dx,al
mov dx,Port_8253_00 ;clk0
mov ax,38400
out dx,al
mov al,ah
out dx,al
ret
(2)LED端口:
OUTSEG equ 0ffdch ;段控制口
OUTBIT equ 0ffddh ;位控制口/键扫口
(3)键盘端口:
IN_KEY equ 0ffdeh ;键盘读入口
(4)LED数码管字型码:
LedMap:
db 0c0h,0f9h,0a4h,0b0h,099h,092h,082h,0f8h
db 080h,090h,088h,083h,0c6h,0a1h,086h,08eh
db 0bfh
(5)键码定义:
KeyTable:
db 07h,04h,08h,05h,09h,06h,0ah,0bh
db 01h,00h,02h,0fh,03h,0eh,0ch,0dh
三、功能流程图:
1、主程序流程图
2、LED显示子程序流程图
3、按键处理子程序流程图
4、中断子程序-时间计数子程序流程图
四、结果讨论:
1、实验结果:
程序运行,数码管开始从000000走表,按C键后显示‘——————’开始对时钟进行初始值设置,设置初始值时可以按D键进行回退修改。
2、问题解决:
(1) 添加D键的回退删除功能:在C键功能实现区域里不断检测D键是否按下,若按下则将LED上一位数码管设置成‘—’并将设置时间的地址回退1,及可完成对D键的功能设置;
(2) 调试程序时发现时钟初始值可以设置,D键回退功能也是可以的,8253gate信号也正确连接着,但是初始值设置完后时钟并没有走表,于是将8253的输出端的线接入至手动的单脉冲的发生器,进行手动给8259刺激,结果时钟开始随手按动开始走表,可以断定该8253芯片可能已经损坏,换了个试验箱后遇到了同样的情况,直至换了功能正常的实验箱后实验现象才正确展现。
3、功能完善
可以在课题要求的基础上添加一些功能,使得电子时钟的功能更加完善:
(1)添加暂停功能,按键A时间暂停,再按A键时间继续走;
(2)添加闹铃功能,按键B设置闹铃时间,时间到时控制鸣笛闹铃;
(3)添加倒数计时的功能,按键E设置倒数的初始值,时间到即鸣笛闹铃;
可以看出本次课程设计的课题可以完善的地方有很多,如果只满意于已完成的则大错特错了,课程设计虽然已经结束,但是课下仍然可以对自己的课题进行进步的探索,不断完善,不断追求完美,这也是我们需要的。
4、实验总结
(1) 通过此次课程设计,将微机原理与接口技术课程所学的知识运用到了实际操作中,并学会了数码管显示电子时钟的制作方法;实验过程中遇到了一些困难和问题,通过同学之间的讨论和查找资料也一一攻破,顺利完成了课程设计,实验结果符合课题要求。
(2) 中断服务程序设计时还应注意以下几个问题:
A.因为8086CPU在响应中断时不能自动地保护它的各寄存器(除标志寄存器外)内容,虽然可用寄存器在主程序和中断服务程序之间传送参量和结果,但这样做极易引起意想不到的错误,所以应当避免,而采用指定内存单元进行参数传递;
B.使用堆栈实现保护现场与恢复现场。使用时要注意堆栈的先进后出的特性,同时要确保堆栈有足够的空间,防止堆栈溢出;
C.只有中断服务程序用到的那些寄存器(标志寄存器除外)的内容才需要加以保护;
D.在从中断服务程序返回之前,即使CPU处于关中断状态也不必开中断。在执行IERT指令后,CPU自动恢复中断前标志寄存器。
(3) 调试的时候因为遇到两个实验箱都是有问题的,本来以为是程序出现了问题,来回检查程序,直到最后又换了个实验箱才知道程序是正确的,实验箱是实验的基础,我们做实验时都应该细心爱护,弄坏了芯片,给自己和他人都带来了不便。
附录:实验代码:(完整的源程序)
CODE SEGMENT
ASSUME CS:CODE,DS:CODE,ES:CODE
ORG 3400H
Start: JMP program
LedMap: 八段管显示码
db 0c0h,0f9h,0a4h,0b0h,099h,092h,082h,0f8h
db 080h,090h,088h,083h,0c6h,0a1h,086h,08eh
;db 0bfh
db 0f7h
KeyTable: ;键码定义
db 07h,04h,08h,05h,09h,06h,0ah,0bh
db 01h,00h,02h,0fh,03h,0eh,0ch,0dh
OUTSEG equ 0ffdch ;段控制口
OUTBIT equ 0ffddh ;位控制口/键扫口
IN_KEY equ 0ffdeh ;键盘读入口
LedBuf db 6 dup(?) ;显示缓冲
time DB 0,0,0,0,0,0
;INTNum equ 20
Port_8259_0 EQU 0FFE0H ;1110_0000
Port_8259_1 EQU 0FFE1H
Port_8253_00 EQU 0FFE4H ; 0_01
Port_8253_01 EQU 0FFE5H
Port_8253_10 EQU 0FFE6H
Port_8253_11 EQU 0FFE7H
program:
call initCLK0
CLI
MOV AX,OFFSET int8259
MOV BX,003CH
MOV [BX],AX
MOV BX,003EH
MOV AX,0000H
MOV [BX],AX
STI
call init8259
call update_ledbuff
mainLoop:
call display
call handle_key
jmp mainLoop
;================================
initCLK0:
mov dx,Port_8253_11
mov al,00110100b
out dx,al
mov dx,Port_8253_00 ;clk0
mov ax,38400
out dx,al
mov al,ah
out dx,al
ret
;================================init8259:
MOV AL,13H
MOV DX,Port_8259_0
OUT DX,AL
MOV AL,08H
MOV DX,Port_8259_1
OUT DX,AL
MOV AL,09H
OUT DX,AL
MOV AL,7FH ;IRQ7
OUT DX,AL
RET
;================================int8259:
cli
push ax
push bx
push cx
MOV AL,20H 0010
MOV DX,Port_8259_0
OUT DX,AL
call timeInc
call update_ledbuff
pop cx
pop bx
pop ax
sti
iret
;=========================================
timeInc:
push bx
push cx
mov bx,offset time
add bx,5 ;取time[5]
inc byte ptr [bx]
cmp byte ptr [bx],10
jb next5
mov byte ptr [bx],0 ;该位清零
dec bx ;下一位加1
inc byte ptr [bx]
inc bx
next5: dec bx
cmp byte ptr [bx],6
jb next4
mov byte ptr [bx],0
dec bx
inc byte ptr [bx]
inc bx
next4: dec bx
cmp byte ptr [bx],10
jb next3
mov byte ptr [bx],0
dec bx
inc byte ptr [bx]
inc bx
next3: dec bx
cmp byte ptr [bx],6
jb next2
mov byte ptr [bx],0
dec bx
inc byte ptr [bx]
inc bx
next2: dec bx
dec bx
cmp byte ptr [bx],2
jnz cmp10
cmp4: inc bx
cmp byte ptr [bx],4
jb next1
mov byte ptr [bx],0
dec bx
mov byte ptr [bx],0
jmp over_timeInc
cmp10: inc bx
cmp byte ptr [bx],10
jb next1
mov byte ptr [bx],0
dec bx
inc byte ptr [bx]
inc bx
next1: dec bx
cmp byte ptr [bx],3
jb over_timeInc
mov byte ptr [bx],0
over_timeInc:
pop cx
pop bx
ret
;================================
display:
push ax
push bx
push cx
push dx
mov bx,offset LEDBuf
mov cl,6 ;共6个八段管
;从左边开始显示
mov ah,00100000b
DLoop:
mov dx,OUTBIT
mov al,0
out dx,al ;关所有八段管
mov al,[bx]
mov dx,OUTSEG
out dx,al
mov dx,OUTBIT
mov al,ah
out dx,al ;显示一位八段管
push ax
mov ah,1
call Delay
pop ax
shr ah,1
inc bx
dec cl
jnz DLoop
mov dx,OUTBIT
mov al,0
out dx,al ;关所有八段管
pop dx
pop cx
pop bx
pop ax
ret
;================================
update_ledbuff:
push ax
push bx
push cx
push dx
mov cl,6
uloop: mov bx,offset time
mov al,cl
dec al
mov ah,0
xlat ;取出time[cl-1]
mov bx,offset LEDMAP
mov ah,0
xlat ;查找对应字形码
mov bx,offset LedBuf
mov ch,0
add bx,cx
dec bx
mov [bx],al ;放入LedBuf[cl-1]
dec cl
jnz uloop
pop dx
pop cx
pop bx
pop ax
ret
;================================
Delay: ;延时子程序
push cx
mov cx,256
loop $
pop cx
ret
Delay1: 延时子程序
push cx
mov cx,50
lxxx:
call display
loop lxxx
pop cx
ret
;================================
handle_key:
call read_key
cmp al,0ch
jne nextR
jmp nextC
nextR:
ret
nextC:
cli
mov bx, offset time
mov cl,6
loop_d:
mov byte ptr [bx],16
inc bx
loop loop_d
call update_ledbuff
mov bx, offset time
t1:
call Display
call read_key
cmp al,2
ja t1
t1_over:
mov [bx],al
call update_ledbuff
call Delay1
t2: call Display
call read_key
CMP AL,0DH
JNE T22
mov byte ptr [bx],16
call update_ledbuff
call Delay1
JMP T1
T22:
cmp al,9
ja t2
cmp byte ptr [bx],2
je cmp_k_4
jmp t2_over
cmp_k_4:cmp al,3
ja t2
jmp t2_over
t2_over:
inc bx
mov [bx],al
call update_ledbuff
call Delay1
t3:
call Display
call read_key
CMP AL,0DH
JNE T33
mov byte ptr [bx],16
DEC BX
call update_ledbuff
call Delay1
JMP T2
T33:
cmp al,5
ja t3
t3_over:
inc bx
mov byte ptr[bx],al
call update_ledbuff
call Delay1
t4:
call Display
call read_key
CMP AL,0DH
JNE T44
mov byte ptr [bx],16
DEC BX
call update_ledbuff
call Delay1
JMP T3
T44:
cmp al,9
ja t4
t4_over:
inc bx
mov [bx],al
call update_ledbuff
call Delay1
t5:
call Display
call read_key
;++++++++++++
CMP AL,0DH
JNE T55
mov byte ptr [bx],16
DEC BX
call update_ledbuff
call Delay1
JMP T4
T55:
cmp al,5
ja t5
t5_over:
inc bx
mov [bx],al
call update_ledbuff
call Delay1
t6:
call Display
call read_key
CMP AL,0DH
JNE T66
mov byte ptr [bx],16
DEC BX
call update_ledbuff
call Delay1
JMP T5
T66:
cmp al,9
ja t6
t6_over:
inc bx
mov [bx],al
call update_ledbuff
call Delay1
call Delay1
key_over:
sti
ret
;================================
read_key:
push bx
push cx
push dx
mov al,0ffh ;关显示口
mov dx,OUTSEG
out dx,al
mov bl,0
mov ah,0feh
mov cx,8
key1: mov al,ah
mov dx,OUTBIT
out dx,al
shl al,1
mov ah,al
nop
nop
nop
nop
nop
nop
mov dx,IN_KEY
in al,dx
not al
nop
nop
and al,0fh
jnz key2
inc bl
loop key1
nkey: mov al,20h
pop dx
pop cx
pop bx
ret
key2: test al,1
je key3
mov al,0
jmp key6
key3: test al,2
je key4
mov al,8
jmp key6
key4: test al,4
je key5
mov al,10h
jmp key6
key5: test al,8
je nkey
mov al,18h
key6: add al,bl
cmp al,10h
jnc fkey
mov bx,offset KeyTable
xlat
fkey:
pop dx
pop cx
pop bx
ret
;================================
CODE ENDS
END Start