资源描述
微机原理课程设计
目 录
摘要…………………………………………………1
实验线路……………………………………………1
设计思想……………………………………………2
功能流程图…………………………………………3
结果讨论……………………………………………6
设计心得……………………………………………6
参考文献……………………………………………7
程序清单……………………………………………8
一、 摘要
课题六:数字闹钟
1. 通过8253定时器产生秒脉冲定时中断。在中断服务程序中实现秒、分、小时的进位(24小时制)。
2. 将当前时分秒在七段LED显示器上显示(如:091132)。
3. 可设置闹钟的时间当前值(对准时间),设置闹铃时间,闹铃功能的关闭和开放.
关键词:数字闹钟,8253定时器,LED显示器,8255A并行口
二、 实验线路
三、 设计思想
u 概述:
程序主体设计:本程序共有分端口设置模块,计数模块,显示模块等几个模块。
1. C--DISPLAY 12, 45, 37 ----将闹钟设置为12:45: 37;
2. G--GO AHEAD----开中断,闹钟恢复走时
3. D--STOP TO DISPLAY-----关中断,闹钟停止走时
4. E--EXIT TO DOS----返回DOS
5. M--SET THE CLOCK -----设置闹铃时间
6. F--OPEN THE CLOCK-----设置闹钟功能为开
7. B--CLOSE THE CLOCK-----设置闹钟功能为关
8. P--POSITION THE BENINNING DATE------设置闹钟的时间
1. 计时器软件的设计:
主程序中,要对各个用到的芯片进行初始化,目的是使其每20豪秒产生一次方波。8253A的定时器输出与8259A的IR2连接,计数器0工作在模式3(方波发生器),计数值采用二进制格式,输出作为计数器1的输入, 计数器1工作在模式2(分频器),计数值采用二进制格式,输出到总线IRQ2,向CPU发送时钟中断信号,根据两个计数器的设置,系统每隔20毫秒便由8253A产生一次中断请求,即每隔20豪秒执行一次中断处理程序。这个方法将与时间相关的两个模块即显示模块和计时模块放在中断处理程序中,这样,就保证了数字显示的稳定,中断处理程序完成计时功能要依靠两个方面,因为中断处理程序是每20豪秒执行一次,但计时并不是以20豪秒为单位进行的,而是以秒为单位进行的,所以,计时功能的实现一方面要利用20毫秒这个基准时间单位,另一方面借助一个计数单位。计数单位的初始值为50,每进行一次中断,便使计数单元的内容减1。每当计数单元从50减为0时,说明已经过了1秒时间。并判断是否有进位,如有则进行修改,实现进位。并在LED上显示。
2. 显示部分:
本程序显示部分用了6个共阴极LED作为显示管,显示程序要做到每送一次段码就送一次位码,每送一次位码后,将位码中的0右移1位作为下次的位码,从而可以实现从左到右使6个LED依次显示出相应的数字。虽然CPU每隔一定时间便执行显示程序,但只要这个时间段不太长,由于人眼的视觉作用,就可以在6个LED上同时见到数字显示。
程序中,用8255A的PA口作为输出,输出扫描信号,PB口作为输入,读进列值。
本程序用行扫描法来识别键盘的闭合键。先使第0行接地,其余行为高电平,然后看第0行是否有键闭合,这是通过检查列线电位来实现的,即在第0行接地时看是否有哪条列线变成低电平。如果有某条列线变为低电平,则表示第0行和此列线位置上的键被按下如果没有,则说明第0行上没有键被按下。此后,再将第1行接地,然后检测列线中是否有变为低电平的线。如此往下逐行扫描,直到最后一行。为消除键的抖动,所以调用延迟程序,然后再判断具体按下的到底是哪个键,如果得到的是FFH,则程序在循环中等待。
3. 计数部分:见流程图
4. 时间设定模块
对于输入的检测,若超出范围,则对其置F------,
四、 功能流程图
程序主流程控制图
D键?
P键?
M键?
F键?
B键?
E键?
N
N
N
N
N
N
Y
Y
Y
Y
Y
Y
G键?
N
Y
C键?
Y
显示初始化时间
开始计时
停止计时
开启闹铃
设置闹铃
设置时间
关闭闹铃
退出回到DOS
N
中断服务子程序流程图
收到50次中断?
进位处理部分(下)
闹铃开?
计数值减一(初值为50)
Y
N
闹铃时间到?
中断进入
Y
Y
N
响铃
退出中断服务
进位处理部分流程图
开始
秒钟是否到59(此部分的转换从略)
秒加1
秒十位和各位赋值为0 0
N
Y
分钟是否到59(此部分的转换从略)
分钟加1
N
Y
分钟十位和各位赋值为0 0
分钟是否到23(此部分的转换从略)
小时加1
N
Y
小时十位和各位赋值为0 0
闹铃判断响铃部分
五、 结果讨论
本程序共有分端口设置模块,计数模块,显示模块等几个模块。经过调试,本程序可以实现题目的要求。时、分、秒都分两位。个位满十后就向前进一位。分秒的十位满六十后也向前进一位。显示小时两位在满二十四后重新计数。在置数时,使用者可置任意值,但如果有某位超过计数值,则在LED显示器上输出出错信息。程序中设置压C键为LED显示器清0,压E键为退出,压D键为计数暂停,压P键为设置LED显示器初始值。应该注意的是,程序中设定的键值为实验台上的小键盘的键值,并非计算机键盘。经测试,程序中设置的功能全都可以良好运行。
本程序参照实验室电脑中16BIT文件中的kl.asm编制
定时器/计数器8253计数初值的设定。
下面对几个重点部分的调试过程和遇到的问题作一定的讨论:
1. 修改后的中断服务子程序(改变进位的条件)
其中进位的条件判断以及后面的闹铃的程序段位置的设置都与程序结果有很大的关系.进位判断特别要注意仔细,编程实现前应该画个流程图,直接再源文件上改不但不能节省时间,反而更加浪费时间.
2: 此中断服务子程序的类型设置为FAR调用,这里要特别注意.因为相对于中断发生时的运行状态,此程序段与之不在同一代码段,所以应该定义为FAR类型.这样产生了另外一个问题,在此程序段中若想调用此CODE段中以他过程,则那个过程也应该被定义为FAR调用,当然可以简单的通过不使用过程调用解决.以解决此中断子程序过程和其他普通过程对对应过程的调用冲突.
u 设计心得
通过对数字闹钟的汇编实现,对硬件特别是8253A,8255并行口的原理和实现都有了很深的了解。更加深了对汇编语言的使用.
整个程序中涉及8253A,8255并行口的使用,汇编语言熟练掌握的要求。
可以说整个文件中最麻烦的就是进位条件的判断,编程中经常犯想当然的错误。另外对于中断服务子程序的类型设置问题,由于以前对这个概念的理解留于表面,编程中出现了不少奇怪的错误。再调试中尝试使用了分割法,对错误模块进行定位,再进行排查.
在算法实现上要有一定的思路要更能体现设计的目的。同时上机调试也是十分重要的,在调试的过程中能够不断的发现在编写算法时应该注意的一些细节和算法语句的非法使用,在调试过程中通过对算法的不断测试、更正、扩充功能、修饰细节,使算法程序不断的得到完善。
通过这次的课程设计使我认识到要将微机原理这门计算机专业的课学好不仅仅是要把书上的基本知识学好而且还要不断进行实践,将所学的跟实践操作结合起来才能更好地巩固所学,才能提高自己实践能力.通过这次的设计使我认识到只停留在表面理解问题是很难使问题得到很好的解决的,实践能力与理论知识同样重要。可以说此课程设计的理论难度并不大,但是若要深入发掘其中的东西,并且实际去编程实现,就遇到了相当大的难度。因为与之涉及的很多方面并没有学过,需要自己去自学和实践检验。
所以在以后的学习中一方面我要不断的巩固自己所学的理论知识,一方面还要多参加实际操作工作以便提高自己的实际操作能力。
其实这次课程设计的最大收获应该是找到了解决问题的几个很好的途径:1.讨论2.通过网络,在自己的网站上也收获了很多,共享让我们共同进步。此外,我学会了看硬件结构图,并学会了自己去独立的完善一个程序,对程序的效用等做思考。并体会到:问别人只能帮你开拓思路,真正解决问题还是要靠自己去摸索。当然讨论是很好的学习途径,它会让你事半功倍.
由于时间不是很充裕,程序中有很多值得改善的地方,我尝试再其中加入更多的功能,但调试的结果没有,所以需要继续努力。
六、 参考文献
1. 微机原理与接口技术(复习与考试指导)
2. 戴梅萼等. 微型计算机技术及应用.北京:清华大学出版社,2003
3. 王成耀等. 汇编语言程序设计.北京:机械工业出版社,2004
七、 源程序以及注释
;此程序实现数字闹钟的设定,闹铃时间得设定,闹铃功能的开关
;试验硬件平台是TPC-1型试验培训系统
;386以上微机适用
;纯DOS下才能使用
;TASM4.1或以上编译
;*********************;
;* 键盘显示 8255LED *;
;*********************;
IO_PLX_DEVICE_ID EQU 05406H ;TPC卡设备ID
IO_PLX_VENDOR_ID EQU 010B5H ;TPC卡厂商ID
IO_PLX_SUB_ID EQU 0905410B5H ;TPC卡子设备及厂商ID
PA55 EQU 218H-200H ;8255端口地址
PB55 EQU 219H-200H
P55CTL EQU 21BH-200H
PORTSEG EQU 211H-200H ;LED端口地址
PORTBIT EQU 210H-200H
TIM_CTL EQU 203H-200H ;8253端口地址
TIMER0 EQU 200H-200H
TIMER1 EQU 201H-200H
MODE03 EQU 36H ;0011-0111
MODE12 EQU 74H ;0111-0101
DATA SEGMENT
CSREG DW ?
IPREG DW ? ;旧中断向量保存空间
IO_9054BASE_ADDRESS DB 4 DUP(0) ;TPC卡PCI接口芯片I/O基地址暂存空间
IO_BASE_ADDRESS DB 4 DUP(0) ;TPC卡I/O基地址暂存空间
INTERRUPT_LINE DB 2 DUP(0) ;TPC卡中断号暂存空间
PCICARDNOTFIND DB 0DH,0AH,'TPC PCI CARD NOT FIND OR ADDRESS/INTERRUPT ERROR !!!',0DH,0AH,'$'
IO9054BASEADDRESS DB 0DH,0AH,'TPC PCI CARD 9054 CHIP I/O BASE ADDRESS : ','$'
IOBASEADDRESS DB 0DH,0AH,'TPC PCI CARD I/O BASE ADDRESS : ','$'
INTNUMBER DB 0DH,0AH,'TPC PCI CARD INTERRUPT LINE : ','$'
ENTER_RETURN DB 0DH,0AH,'$'
MESS DB '8253A TIMER0 IN MODE3! COUNT=0200H',0AH,0DH
DB '8253A TIMER1 IN MODE2! COUNT=0AH',0AH,0DH,'$'
MESS1 DB 'I AM RINGING',0AH,0DH,'$'
IRQ_VECT DB 08H,09H,0AH,0BH,0CH,0DH,0EH,0FH,70H,71H,72H,73H,74H,75H,76H,77H
;新的中断向量,中断0-7的向量为:08H-0FH,中断8-15的向量为:70H-77H
IRQ_MASK_0_7_TABLE DB 011111110B,011111101B,011111011B,011110111B
DB 011101111B,011011111B,010111111B,001111111B
DB 011111011B,011111011B,011111011B,011111011B
DB 011111011B,011111011B,011111011B,011111011B
;新的中断掩码,中断0-7时从低至高相应位为零,中断8-15时第2位为零
IRQ_MASK_8_15_TABLE DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 011111110B,011111101B,011111011B,011110111B
DB 011101111B,011011111B,010111111B,001111111B
;新的中断掩码,中断0-7时全一,中断8-15时从低至高相应位为零
COUNT DB 15
CTIME DB 00H,00H,00H,00H,00H,00H
CLOCK DB 0AH,0AH,0AH,0AH,0AH,0AH
BUF DB 00H,00H,00H,00H,00H,00H;*****************
MYBELL DB 00H ;***********OFF***INITIALIZE
MONTH3 DB 0
DAY3 DB 0
CHAR1 DB ?
INTMASK DB ?
CONST1 DW ?
LED DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,40H,79H,00H
TABLE1 DW 0101H,0201H,0401H,0801H,1001H,2001H,4001H,8001H
DW 0102H,0202H,0402H,0802H,1002H,2002H,4002H,8002H
DW 0104H,0204H,0404H,0804H,1004H,2004H,4004H,8004H
CHAR DB 'CDEFBA9845673210 RPMG'
;MAXDAY DB 00H,1FH,1CH,1FH,1EH,1FH,1EH,1FH,1FH,1EH,1FH,1EH,1FH
MES DB 'IN SMALL KEYRORD',0AH,0DH
DB 'C--DISPLAY 12, 45, 37 ; G--GO AHEAD',0AH,0DH
DB 'D--STOP TO DISPLAY ; E--EXIT TO DOS',0AH,0DH
DB 'M--SET THE CLOCK ; F--OPEN THE CLOCK',0AH,0DH
DB 'B--CLOSE THE CLOCK',0AH,0DH
DB 'P--POSITION THE BENINNING DATE',0AH,0DH,'$'
DATA ENDS
STACKS SEGMENT
DB 100 DUP (?)
STA DW 512 DUP (?)
TOP EQU LENGTH STA
STACKS ENDS
CODE SEGMENT
;ASSUME CS:CODE,DS:DATA,SS:STACKS,ES:DATA
START:
;ENABLE LOCAL INTERRUPT INPUT
.386
CLI
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AX,STACKS
MOV SS,AX
CALL FINDTPC ;查找TPC卡资源并显示
MOV AH,0
INT 1AH ;时间中断,保存到DX中
MOV BX,DX
T1: MOV AH,0
INT 1AH
CMP BX,DX
JZ T1
MOV BX,DX
MOV SI,0
T2: MOV AH,0
INT 1AH
MOV AX,800H
T3: DEC AX ;循环800H次
JNZ T3
INC SI
CMP BX,DX
JZ T2
MOV AX,30H
MOV BX,SI
MUL BX
MOV BX,56H
DIV BX
MOV WORD PTR CONST1,AX
MOV DX,WORD PTR IO_BASE_ADDRESS ;初始化8253
ADD DX,TIM_CTL ;控制口
MOV AL,MODE03 ;36H==0011 0110 ;计数器0工作在模式3(方波发生器),计数值采用二进制格式
OUT DX,AL
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,TIMER0 ;计时器0
MOV AL,00H
OUT DX,AL
MOV AL,02H
OUT DX,AL
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,TIM_CTL ;74H==0111 0100 ;设置计数器1工作在模式2(分频器),计数值采用二进制格式
MOV AL,MODE12
OUT DX,AL
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,TIMER1
MOV AL,0AH
OUT DX,AL
MOV AL,00
OUT DX,AL
MOV DX,OFFSET MES
MOV AH,09
INT 21H
MOV DX,WORD PTR IO_9054BASE_ADDRESS
ADD DX,68H ;设置 TPC 卡中9054芯片IO口,使能中断
IN AX,DX
OR AX,0900H
OUT DX,AX
MOV BX,WORD PTR INTERRUPT_LINE ;保存原中断向量
MOV AL,BYTE PTR [IRQ_VECT+BX]
MOV AH,35H
INT 21H
MOV AX,ES
MOV CSREG,AX
MOV IPREG,BX
MOV BX,WORD PTR INTERRUPT_LINE ;设置新中断向量
MOV AL,BYTE PTR [IRQ_VECT+BX]
MOV CX,CS
MOV DS,CX
MOV DX,OFFSET INT_PROC
MOV AH,25H
INT 21H
MOV AX,DATA
MOV DS,AX
MOV ES,AX
IN AL, 21H ;设置中断掩码
MOV BX,WORD PTR INTERRUPT_LINE
MOV AH,BYTE PTR [IRQ_MASK_0_7_TABLE+BX]
AND AL,AH
OUT 21H, AL
IN AL, 0A1H
MOV BX,WORD PTR INTERRUPT_LINE
MOV AH,BYTE PTR [IRQ_MASK_8_15_TABLE+BX]
AND AL,AH
OUT 0A1H, AL
STI ;开中断
;*********************************************************
;********************小键盘的查询过程*********************
LKEY: CALL KEY ;获得TPC键盘输入值
MOV DL,[CHAR1] ;C--DISPLAY 12, 45, 37
CMP DL,'C'
JNZ LGY
CALL CPRO
JMP LKEY
LGY: CMP DL,'G' ; G--GO AHEAD'
JNZ LDY
CALL GPRO
JMP LKEY
LDY: CMP DL,'D' ; D--STOP TO DISPLAY
JNZ LPY
CALL DPRO
JMP LKEY
LPY: CMP DL,'P' ; 'P--POSITION THE BENINNING
JNZ LMY
CALL PPRO
JMP LKEY
LMY: CMP DL,'M' ;SET THE CLOCK TIME
JNZ LFY
CALL MPRO
JMP LKEY
LFY: CMP DL,'F' ;BELLING ON/OFF
JNZ LBY
MOV MYBELL,01H ;ON
JMP LKEY
LBY: CMP DL,'B' ;B--CLOSE THE CLOCK
JNZ LEY
MOV MYBELL,00H ;OFF
JMP LKEY
LEY: CMP DL,'E' ; EXIT TO DOS'
JNZ LKEY
;**********************非规定的按键时继续等待*************
;*********************************************************
EXIT: CLI
MOV BX,WORD PTR INTERRUPT_LINE ;恢复中断掩码
MOV AH,BYTE PTR [IRQ_MASK_0_7_TABLE+BX]
NOT AH
IN AL, 21H
OR AL, AH
OUT 21H, AL
MOV BX,WORD PTR INTERRUPT_LINE
MOV AH,BYTE PTR [IRQ_MASK_8_15_TABLE+BX]
NOT AH
IN AL, 0A1H
OR AL, AH
OUT 0A1H, AL
MOV BX,WORD PTR INTERRUPT_LINE ;恢复原中断向量
MOV AL,BYTE PTR [IRQ_VECT+BX]
MOV DX,IPREG
MOV CX,CSREG
MOV DS,CX
MOV AH,25H
INT 21H
MOV AX,DATA ;设置 TPC 卡中9054芯片IO口,关闭中断
MOV DS,AX
MOV DX,WORD PTR IO_9054BASE_ADDRESS
ADD DX,68H
IN AX,DX
AND AX,0F7FFH
OUT DX,AX
MOV AX,4C00H
INT 21H ;退出
;------------------------------------------------------------------
INT_PROC PROC FAR ;修改后的中断服务子程序(改变进位的条件)
;此中断服务子程序的类型设置为FAR调用,这里要特别注意.因为相对于中断发生时的运行
;状态,此程序段与之不在同一代码段,所以应该定义为FAR类型.这样产生了另外一个问题,
;在此程序段中若想调用此CODE段中以他过程,则那个过程也应该被定义为FAR调用,当然
;可以简单的通过不使用过程调用解决.以解决此中断子程序过程和其他普通过程对对应过程
;的调用冲突
CLI
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
MOV AX,DATA ;INTERRUPT TO DO
MOV DS,AX
DEC [COUNT]
JNZ DDD
MOV [COUNT],20
MOV DI,OFFSET CTIME
MOV AL,[DI+4]
MOV AH,0AH
MUL AH
ADD AL,[DI+5]
CMP AX,59 ;先判断秒钟是否等于59秒,是则判断分钟,否则加1
JZ FENZHONG
INC BYTE PTR [DI+5]
CMP BYTE PTR [DI+5],0AH
JNZ DDD
MOV BYTE PTR [DI+5],00H
INC BYTE PTR [DI+4]
JMP DDD
FENZHONG:
MOV WORD PTR [DI+4],0000H ;先将秒钟置为0,再转换分钟为十进制形式
MOV AL,[DI+2]
MOV AH,0AH
MUL AH
ADD AL,[DI+3]
CMP AX,59 ;判断是否应该向时钟进位
JZ SHIZHONG
INC BYTE PTR [DI+3]
CMP BYTE PTR [DI+3],0AH
JNZ DDD
MOV BYTE PTR [DI+3],00H
INC BYTE PTR [DI+2]
JMP DDD
SHIZHONG: MOV WORD PTR [DI+2],0000
MOV AL,[DI]
MOV AH,0AH
MUL AH
ADD AL,[DI+1]
CMP AH,23 ;判断时钟该不该循环了
JNZ QQQ
MOV WORD PTR [DI],0000H
JMP DDD
QQQ: INC BYTE PTR [DI+1]
CMP BYTE PTR [DI+1],0AH
JNZ DDD
MOV BYTE PTR [DI+1],00H
INC BYTE PTR [DI]
DDD: ;将闹铃功能键与闹铃条件的判断放在20次中断计数条件满足后的执行代码中
;有效缩短延迟时间以及误差时间
CMP BYTE PTR MYBELL,00H ;检测闹铃有没有开,
JZ ZZZ
LEA DI,CTIME
LEA SI,CLOCK
MOV CX,5
CHECK: ;检测门铃时间是否到了
MOV AL,[DI]
MOV BL,[SI]
CMP AL,BL
JNZ ZZZ
INC DI
INC SI
LOOP CHECK
;************** 闹铃时的检测输出
MOV DL,07H
MOV AH,02H
INT 21H
LEA DX,MESS1
MOV AH,09H
INT 21H
MOV BYTE PTR MYBELL,00H
ZZZ:
MOV AL,20H ;SEND EOI
OUT 0A0H,AL
OUT 20H,AL
MOV CX,0FFFFH
LOOPX:
NOP
LOOP LOOPX ;延时
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
STI
IRET
INT_PROC ENDP
;------------------------------------------------------------------
KEY PROC NEAR ;AB口端口读取的控制,是对小键盘的控制
PUSH CX
KST: MOV AL,82H
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,P55CTL
OUT DX,AL
MOV AL,00H
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,PA55
OUT DX,AL
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,PB55
IN AL,DX
OR AL,0F8H
CMP AL,0FFH
JZ DELAY
PUSH AX
MOV CX,0A00H ;两重循环
DLY: MOV AX,WORD PTR CONST1
DLY1: DEC AX
JNZ DLY1
DEC CX
JNZ DLY
POP AX
MOV CL,08H
MOV AH,0FEH
SCAN1:
MOV DX,WORD PTR IO_BASE_ADDRESS;行列扫描,得到小键盘输入
ADD DX,PA55
MOV AL,AH
OUT DX,AL
MOV DX,WORD PTR IO_BASE_ADDRESS
ADD DX,PB55
IN AL,DX
OR AL,0F8H
CMP AL,0FFH
JNZ KEYN
ROL AH,1
DEC CL
JNZ SCAN1
展开阅读全文