当前位置:文档之家› 汇编语言课程设计打字计时练习

汇编语言课程设计打字计时练习

学生课程设计(论文)

题目:打字计时练习

学生姓名:学号:

所在院(系): m 专业:计算机科学与技术

班级:

指导教师:职称:

2008年12 月26 日

攀枝花学院本科学生课程设计任务书

注:任务书由指导教师填写。

摘要

在IBM-PC系统中,驻留的ROM中有8KB的BIOS。它实现对系统中种种常用设备的输入输出操作的管理。其中的16H中断调用即为键盘输入输出中断调用,实现从键盘输入字符到AL寄存器、读键盘缓冲区字符到AL寄存器、读取特殊功能键的状态等功能。本程序是一个在键盘上练习打字并能统计时间的程序,在缓冲区中预放了一些字母,运行时,可按照屏幕上显示的字母输入练习,每输入完一行按回车键后,可显示出练习输入的时间。通过它练习英文打字练习,并能够统计时间。程序运行时,使用自编的中断向量处理程序。程序退出时,恢复中断向量。

关键词打字计时,寄存器,缓冲区,中断向量

1、课程设计题目描述和要求

1.1 问题提出及功能要求

设计一个在键盘上练习打字并能统计时间的程序。通过它练习英文打字练习,并能够统计时间。屏幕上显示出提示信息和练习例句,按照例句从键盘上输入字母即可,每输入完一行后按回车键,可显示出练习输入的时间和下一行例句。按Esc键可退出程序。

1.2 运行环境

Windows XP/98/2000操作系统、文本编辑器使用EDIT或NOTEPAD,汇编程序使用MASM.EXE,连接程序使用LINK.EXE,调试程序使用DEBUG.EXE。

1.3 本课题涉及的知识点

定义数据段,设置主要参数:设置9号中断向量地址,9号中断向量首址,1C 向量地址;定义时间参数为秒、分、小时。在代码段,调用中断8259、键盘中断、时钟中断、并设置打字计时文件程序顺序。整个程序使用序分化各子功能。

2、算法设计

2.1设计思路

在键盘上练习的打字例句及其地址表、计时单元等预先放在DATA数据段中,自编的中断程序kbint检测按键时产生的中断,并把按键的扫描码转换为ASCII 码存入缓存区buffer,这个工作和ROM09类型的键盘中断例行程序所完成的工作大致相同,只是在解释各个键时作了简化,即只解释了可显示字符,如英文字母、数字及一些符号;其他特殊键,如组合键、双态键、功能键等都未作解释,只作为字符码0来处理。在主程序部分保存原09类型的中断向量,设置自编例行程序的中断向量,设置中断屏蔽位,然后开中断。当键盘中断处理后,主程序中安排指令读取缓冲区中的字符并显示在屏幕上。在主程序的末尾,利用DOS功能恢复原09类型的中断向量,然后返回DOS。在显示键入的字符时,还应判断字符是否为回车(0DH)。如为回车符,说明一个句子输入完毕,此时调用显示时间的子程序显示出打字时间,然后顺序显示下一个例句。如果所存放的例句都已显示完,则又从第一个例句开始显示,直至键入某一功能键(如Esc键、Shift键等)退出程序,结束打字练习。打字时间统计利用自定时器中断处理程序clint来完成。每输完一例句,计时一次。在此中断例行程序中,定时器中断的次数记录在计数单元count中,当count计数值为18时,sec计数单元加1 ,当sec计数值达到60时,min计数单元加1 。因为输入完一个句子无论如何也不会达到小时级,所以对hours计数值的调整判断,实际上只起到退出定时器中断的作用。

显示时间的子程序disptime分别将各遍野单元的二进制数转换为十进制数,并以min:sec:msec的形式显示出来。其中msec是由count记数值转换成的:count×1秒/18.2=count×55ms

2.2程序流程图

3、代码设计

3.1功能模块说明

3.1.1定义数据段,设置主要参数:

缓冲区:BUFFER, BUFPT1 ,BUFPT2

3.1.2代码段

调用中断8259,键盘中断,时钟中断,设置打字计时文件程序顺序

3.1.3使用子程序分化各子功能

DISPTIME PROC NEAR

BINDEC PROC NEAR ;将二进制转化为十进制显示时间

DECDIV PROC NEAR ;转化成字符显示

DISPCHAR PROC NEAR

KBGET PROC NEAR ;获取键盘键入的信息

KBINT PROC NEAR ;查表查到相应的字符

RESET09 PROC ;重新设置09号中断

RESET1C PROC ;重新设置1c功能

RESET PROC ;回复1C与09

3.2源程序

STACK SEGMENT PARA STACK 'STACK'

DB 256 DUP(0)

TOP LABEL WORD

STACK ENDS

DATA SEGMENT PARA PUBLIC 'DATA'

BUFFER DB 16H DUP(0) ;缓冲区大小

BUFPT1 DW 0 ;缓冲区1

BUFPT2 DW 0 ;缓冲区2

KBFLAG DB 0 ;参数,80H表示允许,00表示不允许PROMPT DB ' *PLEASE PRACTISE TYPING*',0DH,0AH,'$' ;定义提示语句SCANTAB DB 0,0,'1234567890-=',8,0 ;定义键盘

DB 'QWERTYUIOP[]',0DH,0 ;定义键盘第一行英文字母及符号DB 'ASDFGHJKL;',0,0,0,0 ;键盘第二行英文字母及符号

DB 'ZXCVBNM,./',0,0,0 ;键盘第三行英文字母及符号

DB ' ',0,0,0,0,0,0,0,0,0,0,0,0,0

DB '789-456+1230.'

******设置一些存储地址便于理解******

EVEN

OLDCS9 DW ? ;9号中断向量地址

OLDIP9 DW ? ;9号中断向量首地址

******预设置打字练习的句子******

STR1 DB 'ABCD EFGH IJKL MNOP QRST UVWX YZ.' ;句子1 DB 0DH,0AH,'$'

STR2 DB 'THERE ARE SOME NEWSPAPERS ON THE TABLE.'

DB 0DH,0AH,'$'

STR3 DB 'THERE ARE SOME CLOUDS IN THE SKY.'

DB 0DH,0AH,'$'

STR4 DB 'SHE ALWAYS EATS HER LUNCH AT NOON.'

DB 0DH,0AH,'$'

STR5 DB 'I DO NOT LIKE AUTUMN AND WINTER.'

CRLF DB 0DH,0AH,'$'

COLON DB ':','$'

EVEN

SADDR DW STR1,STR2,STR3,STR4,STR5

******定义时间参数******

COUNT DW 0 ;记时器记数

SEC DW 0 ;秒

MIN DW 0 ;分

HOURS DW 0 ;小时

SAVE_LC DW 2 DUP(?) ;1C向量地址

DATA ENDS

CODE SEGMENT

ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK

MAIN PROC FAR

START:

MOV AX,STACK

MOV SS,AX

MOV SP,OFFSET TOP

PUSH DS ;现场保护

SUB AX,AX

PUSH AX

MOV AX,DATA

MOV DS,AX

MOV ES,AX

;*******将原中断向量09H保存在自设的单元中******

MOV AH,0

MOV AL,4

INT 21H

MOV AH,0BH

MOV BH,0

MOV BL,4

INT 11H

MOV AH,35H ;取中断向量的功能调用

MOV AL,09H

INT 21H

MOV OLDCS9,ES

MOV OLDIP9,BX

;******设置自编处理程序的中断向量******

PUSH DS

MOV DX,SEG KBINT ;自编中断类型程序段地址放入DS MOV DS,DX

MOV DX,OFFSET KBINT ;自编中断类型程序偏移地址放入DX MOV AL,09H

MOV AH,25H ;设置中断向量功能调用

INT 21H

POP DS

;******将原中断向量1CH保存在自设的单元中******

MOV AH,35H

MOV AL,1CH

INT 21H

MOV SAVE_LC,BX

MOV SAVE_LC+2,ES

;******设置自编处理程序的中断向量******

PUSH DS

MOV DX,SEG CLINT

MOV DS,DX

MOV DX,OFFSET CLINT

MOV AL,1CH

MOV AH,25H

INT 21H

POP DS

;******允许键盘和定时器中断******

IN AL,21H ;允许键盘和定时器中断

AND AL,11111100B

OUT 21H,AL

;******设置显示方式******

FIRST: MOV AH,0

MOV AL,3

INT 10H

;******显示提示信息******

MOV DX,OFFSET PROMPT ;显示提示信息MOV AH,9

INT 21H

;******在屏幕上显示例句******

MOV SI,0

NEXT: MOV DX,SADDR[SI] ;显示例句

MOV AH,09H

INT 21H

;******初始化变量******

MOV COUNT,0 ;设置初值

MOV SEC,0

MOV MIN,0

MOV HOURS,0

;******允许更高一级的中断******

STI

FOREVER:

CALL KBGET

TEST KBFLAG,80H

JNZ ENDINT

PUSH AX

CALL DISPCHAR

POP AX

CMP AL,0DH

JNZ FOREVER

MOV AL,0AH

CALL DISPCHAR

;******显示时间******

CALL DISPTIME

LEA DX,CRLF

MOV AH,09H

INT 21H

;******显示例句结束否?******

ADD SI,2

CMP SI,5*2

JNE NEXT

JMP FIRST

;******原来的中断向量******

ENDINT: CLI

PUSH DS

MOV DX,SAVE_LC

MOV AX,SAVE_LC+2

MOV DS,AX

MOV AL,1CH ;恢复中断向量1CH

MOV AH,25H

INT 21H

POP DS

PUSH DS

MOV DX,OLDIP9

MOV AX,OLDCS9

MOV DS,AX

MOV AL,09H

MOV AH,25H

INT 21H

POP DS

STI

RET

MAIN ENDP

;******定时器中断处理程序******

CLINT PROC NEAR

PUSH DS

MOV BX,DATA

MOV DS,BX

LEA BX,COUNT

INC WORD PTR[BX]

CMP WORD PTR[BX],18 ;初始化记数JNE RETURN

CALL INCT

ADJ:

CMP HOURS,12 ;是否满12小时JLE RETURN

SUB HOURS,12 ;满足减去12 RETURN:

POP DS

STI

IRET

CLINT ENDP

INCT PROC NEAR

MOV WORD PTR[BX],0

ADD BX,2

INC WORD PTR[BX] ;BX内容自增1 CMP WORD PTR[BX],60 ;和60比较

JNE EXIT

CALL INCT

EXIT: RET

INCT ENDP

;******显示打字练习时间******

DISPTIME PROC NEAR ;显示时间主段MOV AX,MIN ;分移动到AX寄存器CALL BINDEC ;显示数字

MOV BX,0

MOV AL,':'

MOV AH,0EH ;显示冒号

INT 10H

MOV AX,SEC ;秒移动到AX

CALL BINDEC

MOV BX,0

MOV AL,':'

MOV AH,0EH

INT 10H

MOV BX,COUNT

MOV AL,55D ;百分秒

MUL BL

CALL BINDEC

RET

DISPTIME ENDP

******将二进转化为十进显示时间******

BINDEC PROC NEAR

MOV CX,100D ;显示百位

CALL DECDIV

MOV CX,10D ;显示十位

CALL DECDIV

MOV CX,1 ;显示个位

CALL DECDIV

RET

BINDEC ENDP

DECDIV PROC NEAR ;转化成字符显示

MOV DX,0

DIV CX

MOV BX,0

ADD AL,30H ;转换成ASCII

MOV AH,0EH

INT 10H ;显示一个字符

MOV AX,DX

RET

DECDIV ENDP

******获取键盘键入的信息******

KBGET PROC NEAR

PUSH BX

CLI

MOV BX,BUFPT1 ;标志缓冲区的大小

CMP BX,BUFPT2

JNZ KBGET2

CMP KBFLAG,0 ;!=00H的时候,一直获取键盘JNZ KBGET3

STI

POP BX

JMP KBGET

KBGET2:

MOV AL,[BUFFER+BX]

INC BX

CMP BX,16H

JC KBGET3

MOV BX,0

KBGET3:

MOV BUFPT1,BX

POP BX

RET

KBGET ENDP

;******键盘中断处理程序******

KBINT PROC NEAR

PUSH BX

PUSH AX

IN AL,60H ;键盘输入寄存器端口地址PUSH AX

IN AL,61H ;控制商品寄存器地址

OR AL,80H

OUT 61H,AL ;读数据

AND AL,7FH ;第八位清0,ASCII只有7位OUT 61H,AL

POP AX

TEST AL,80H

JNZ KBINT2

MOV BX,OFFSET SCANTAB ;查表输出字符

XLAT SCANTAB ;查表

CMP AL,0

JNZ KBINT4

MOV KBFLAG,80H

JMP KBINT2

KBINT4:

MOV BX,BUFPT2

MOV [BUFFER+BX],AL

INC BX

CMP BX,16H

JC KBINT3

MOV BX,0

KBINT3:

CMP BX,BUFPT1

JZ KBINT2

MOV BUFPT2,BX

KBINT2: CLI

MOV AL,20H

OUT 20H,AL ;送825920H端口POP AX

POP BX

STI

IRET

KBINT ENDP

DISPCHAR PROC NEAR ;显示字符

PUSH BX

MOV BX,0

MOV AH,0EH ;显示一个字符在AL里INT 10H ;显示一个字条符

POP BX

RET

DISPCHAR ENDP

CODE ENDS

END START

4、调试与运行

4.1实验步骤:

1)打开windows命令窗口

2)进入masm程序的安装目录,汇编源文件,如图:

图4.1.2 汇编程序

3)连接程序,并查看生成可执行文件weijia.exe。

图4.1.3 查看生成可执行文件

4)关闭对话框,打开可执行文件weijia.exe,开始打字计时练习。

4.2运行程序:

1)设置主程序段显示提示信息,程序功能应该实现下图所示:

图4.2.1 程序调试

2)调用DISPCHAR PROC NEAR 显示用户字条,调用DISPTIME PROC NEAR 显示时间,然后输出下一句提示程序应该实现下图所示:

图4.2.2 程序调试

3)如此循环多次,当第五个例句输入完成后,再返回第一句继续打字计时。

图4.2.3 程序调试

4.3调试中出现的问题

没有注意到要操作的目标数据(内存中的数据)的大小和使用的操作容器(寄存器)的大小没有一致。另外,对于处理数据的ds:[bx]方式,如mov ds:[bx],dx add bx,2在循环中应注意bx的递增或递减大小,如果处理字节,比如用dl,循环中就加或减1;如果处理字,比如用dx,就加或减2。在以后应该留意这个一致性。在8086上,ss和sp都是16位的,栈所处理数据的最小单位也是16位的,

即最小是一个字,栈一次读和一次写,都至少是一个字那么大。

5、总结

课程设计对我们多数初学汇编的学生来说,确实是个一座高峰。翻越它是要付出诸多努力的。我也是摸索了好久才弄明白它的。在此做个小结,也许对自己今后的学习有一些借鉴的作用。为了避免寄存器冲突的问题,在设计子程序时,应把所有用到的寄存器都入栈保存,但用来传递参数和结果的寄存器则要注意,不必入栈的就不入栈了,以免得不到预期的结果。可以把寄存器当作变量来看待,有时候它存储的是数据变量(如把BP当作字符个数的记录器),而有时候它存储的是地址变量(如DI、SI);内存中的数据,按它们的结构关系,则可以把它们看待成数组,我们对数组,可以通过首地址来访问它们。传递参数和结果的,一般可以用寄存器,也可以用一段内存空间来传递,特别是需要传递的数据较多的时候。在设计子程序时,往往涉及到许多的循环,这时候就要注意把不该循环的变量要放在循环体外。一周的汇编语言课程设计结束了,我的收获是很大的。通过课程设计的编程和对编程过程中遇到的问题的思考,有效的提高了我对汇编的认识和理解,切实的提高了我的编程能力,补全了我的不足。通过这次课程设计,我巩固所了学过的知识,能用汇编语言熟练地运用顺序、选择、循环三大结构,进一步掌握了各个指令的功能,特别是转向指令,掌握了子程序的定义及调用,以及正确地运用DEBUG指令。在整个程序的编写中,调试占了很大部分的时间。要想写好汇编语言的程序,必须认真对待代码的每一个细节,还必须熟练的掌握debug命令,这对程序的调试是非常重要的。通过这次实际动手能力的培养,我进一步熟悉了汇编语言的结构和使用方法,基本达到了能独立阅读、编制和调试一定规模的汇编语言程序的水平另外,我觉得,学习汇编有一个比较大的好处,就是可以了解到在电脑中每一个字节数据的来龙去脉,我觉得学习汇编可以发挥一下自己的空间想像力,特别是对内存中数据的组织、存储关系的想像。当然,学习汇编还有另一个重要的收获,就是如何处理数据的问题。

相关主题
文本预览
相关文档 最新文档