前言
这是笔者微机原理的结课大作业,看到这里相信应该读者已经掌握了绝大部分课程所需的知识。
一、项目要求
编写以完整程序,要求显示班级号,班级人数,接收年月日信息并送显,键盘输入班级同学的高数成绩,求最高分、最低分、平均分,并全部显示出来。
二、思路介绍
从本程序中有着以下的几个部分,首先是获取从键盘上输入的信息。首先程序采用DOS软中断的09H号命令,获得键盘输入的年月日信息。紧接着程序采用DOS软中断的01H号命令,对逐位数据输入,获取每个同学的成绩。
接下来便是需要处理这些获取的成绩,通过十位×10 +个位的方式,将每次输入的两个单元的信息内容合并成一个单元的数据。其中×10的操作采用向左移动3次加向左移动一次完成,提高程序的执行效率。
紧接着就是获取处理好的这堆内容的各项信息,通过从首地址进行遍历,找到这堆成绩中的最高分,最低分和总分,并保存下来,通过用总分整除人数,即可获得班级同学的平均分。
最后,在屏幕上输出提示信息,并将各类处理好的结果输出上去,即可完成本次项目的要求。
三、各类子程序介绍
程序初始化 (START)
设置数据段寄存器,显示班级信息,然后请求输入当前日期和学生成绩。
输入成绩 (INPUT_GRADE PROC)
通过循环接收用户输入的成绩,并将其存储在GRADE数组中。每次读取两个字符(假设成绩为两位数),并在读取每个成绩后跳过一个空格。
输出成绩 (OUTPUT_GRADE PROC)
将成绩输出到屏幕上,这通常用于调试。
转换成绩 (CONVERT PROC)
将输入的ASCII码表示的数字转换为实际的数值,并计算每个学生的成绩,存储在GRADE数组中。
查找成绩 (FIND_GRADE PROC)
计算最高分、最低分和平均分。遍历GRADE数组,同时累加总分,然后计算平均分。
显示结果 (SHOW PROC)
将数值转换为ASCII码并显示到屏幕上。该子程序使用了除法和栈来反转数字,因为它从最低位开始打印,直到所有数字都被处理。
四、程序流程图
五、程序代码及注释
DATAS SEGMENT
NUM EQU 20 ;班级人数
GRADE DB 100 dup(?) ;成绩存放位置
CRLF DB 0AH,0DH,'$' ;换行,清晰程序
MAX DB 0 ;存放最大值
MIN DB 0 ;存放最小值
TOTAL DW 0 ;存放全体数的和
AVG DB 0 ;存放平均数
MAX_MSG DB 'The highest score is: ','$' ;最高分提示信息
MIN_MSG DB 'The lowest score is: ','$' ;最低分提示信息
AVG_MSG DB 'The average score is: ','$' ;最低分提示信息
DATE_MSG DB 'Today is: ','$' ;日期提示信息
BUFFER1 DB 101,?,101 DUP (?) ;第一个101表示最大长度为101个字符,?占用的那个字节在调用结束后会被放入实际输入的字符个数
CLASS_MEG DB 'The class is XXX',0AH,0DH,'$' ;班级号信息
NUM_MEG DB 'The class size is 20',0AH,0DH,'$' ;班级人数信息
ASK_MEG1 DB 'Please input the current date,for example: 2023.12.04',0AH,0DH,'$' ;输入时间提示信息
ASK_MEG2 DB 'Please input grades,separated by space: ',0AH,0DH,'$' ;输入成绩提示信息
DATAS ENDS
STACKS SEGMENT
DW 256 DUP (?) ;涉及到进入子程序的断点保护,需要入栈出栈
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
;初始化
MOV AX,DATAS
MOV DS,AX
LEA DX,CLASS_MEG ;提示信息
MOV AH,09H
INT 21H
LEA DX,NUM_MEG ;提示信息
MOV AH,09H
INT 21H
LEA DX,ASK_MEG1 ;日期提示信息
MOV AH,09H
INT 21H
;输入日期到缓冲区
LEA DX,BUFFER1
MOV AH,0AH
INT 21H
MOV AL, BUFFER1+1 ;对字符串进行处理,该位置为字符串长度
ADD AL, 2 ;长度占一个字节,'$'在字符串最末尾,因此加2
MOV AH, 0
MOV SI, AX
MOV BUFFER1[SI], '$' ;对字符串最末尾补上'$'
LEA DX,ASK_MEG2 ;成绩提示信息
MOV AH,09H
INT 21H
CALL INPUT_GRADE ;输入成绩
;CALL OUTPUT_GRADE ;输出成绩(检查调试)
CALL CONVERT ;转化成BCD码
CALL FIND_GRADE ;查找最大值,最小值和平均数
;显示日期
LEA DX,DATE_MSG
MOV AH,09H
INT 21H
LEA DX,BUFFER1+2
MOV AH,09H
INT 21H
LEA DX,CRLF ;换行
MOV AH,09H
INT 21H
;显示最高分结果
LEA DX,MAX_MSG
MOV AH,09H
INT 21H
MOV AL,MAX
CALL SHOW
;显示最低分结果
LEA DX,MIN_MSG
MOV AH,09H
INT 21H
MOV AL,MIN
CALL SHOW
;显示平均分结果
LEA DX,AVG_MSG
MOV AH,09H
INT 21H
MOV AL,AVG
CALL SHOW
;结束程序
MOV AH,4CH
INT 21H
;输入成绩子程序
INPUT_GRADE PROC
MOV CX,NUM
LEA SI,GRADE
INPUT:
MOV AH,01H
INT 21H
MOV [SI],AL
MOV AH,01H
INT 21H
MOV [SI+1],AL
MOV AH,01H ;吃掉空格
INT 21H
ADD SI,2 ;将指针对准下一个单元
LOOP INPUT
RET
INPUT_GRADE ENDP
;输出成绩子程序
OUTPUT_GRADE PROC
MOV GRADE[SI],'$' ;给最末尾加上'$'用以方便输出检查
LEA SI,GRADE ;指针移回首地址
MOV AH,09H
MOV DX,SI
INT 21H
MOV AH,09H ;换行
LEA DX,CRLF
INT 21H
RET
OUTPUT_GRADE ENDP
;转换子程序
CONVERT PROC
LEA SI,GRADE
XOR CX,CX
MOV CX,2*NUM ;两个单元内容合成一个
BEGIN:
MOV AL,[SI]
SUB AL,30H ;ASCII转化为BCD码
MOV [SI],AL
INC SI
LOOP BEGIN
lea SI,GRADE
lea DI,GRADE
MOV CX,NUM
C1:
MOV AL,[SI]
MOV BL,AL
SHL BL,1
SHL AL,1
SHL AL,1
SHL AL,1
ADD AL,BL ;乘以十相当于左移三位加左移一位
ADD AL,[SI+1] ;十位乘以十加上个位
MOV [DI],AL
ADD SI,2
INC DI
LOOP C1
RET
CONVERT ENDP
;查找子程序
FIND_GRADE PROC
LEA DI,GRADE
MOV AH,0H
MOV AL,[DI]
ADD TOTAL,AX
MOV MIN,AL
MOV MAX,AL
MOV CX,NUM-1 ;设定循环次数
AGAIN:
INC DI
MOV AL,[DI]
ADD TOTAL,AX ;总和加上当前AX中的值
CMP AL,MAX
JBE L1 ;如果AX<=MAX,则不是最大数,不需要更改MAX的值
MOV MAX,AL
L1:
CMP AL,MIN
JAE L2 ;如果AX>=MIN,则不是最小数,不需要更改MIN的值
MOV MIN,AL
L2:
LOOP AGAIN ;CX大于0就继续循环
MOV AX,TOTAL
MOV BL,NUM
DIV BL
MOV AVG,AL ;总分除以人数得到平均分
RET
FIND_GRADE ENDP
;显示结果子程序
SHOW PROC
MOV AH,0
MOV CL,10 ;cl是每次 除以 10
MOV CH,0 ;计算除了多少次,也就是有几位
L0:
DIV CL ;ax 除以 cl
PUSH AX ;此时的商存储在AL中,
;余数存储在AH中,此时 ax = ah
ADD CH,1
MOV AH,0
CMP AX,0 ;如果 ax 是 0,说明除干净了
JNE L0
MY_LOOP:
CMP CH,0 ;此时CH的值就是位数,每次出栈,然后 ch 减一即可
JE OVER
POP DX ;把栈顶元素存储到 dx 中
MOV DL,DH ;然后将 dl 的值等于 dh
ADD DL,48
MOV AH,02H
INT 21H
DEC CH
JMP MY_LOOP
OVER:
LEA DX,CRLF
MOV AH,09H
INT 21H
RET
SHOW ENDP
CODES ENDS
END START
六、实验结果
七、注意事项
因为题目要求接收年月日笔者默认是手动输入然后再显示出来,就省去了很多的工作量。如果是需要自动获取计算机的年月日,那么需要调用其他的接口进行操作,由于精力原因笔者没有这么做。
如果有需要的话只需要更改一下子程序即可,预祝读者学习顺利。