汇编语言课程设计--计算机钢琴程序

题目:计算机钢琴程序

1.题目要求:
本项目编写程序,程序运行时使PC机成为一架可弹奏的钢琴。
1)程序首先加载的是菜单界面,有3个功能选项:1是音乐演奏,2是钢琴,ctrl+c是退出程序。
2)当选择1号功能时,会播放一首音乐,音乐播放完自动回到菜单界面。
3)当选择2号功能时,进入钢琴界面,按下数字键1-8时,依次发出8个音调。在钢琴界面时,按下ESC键会返回到菜单界面。
4)在键盘输入非功能键时会提示输入错误。
5)按CTRL和C组合键则退出程序。(字母c不区分大小写)
2.题目分析:
对于题目要求中所提到的内容,总的来看可以分为3个方面,分析如下:第一,对于第一个要求,要建立按键与汇编程序之间的联系并且能够重复输入字符直到按下(ctrl+c),这就涉及到对应中断程序的调用以及i/o端口的使用,另外,还要求按1-8中不同的按键发出不同的声音,这就要求要根据中断的返回值调用执行不同的处理子程序,所以子程序的设计不可缺少。第二方面,在解决第一个要求的基础上,只需输出提示错误信息即可,这就需要在数据段预先设置好字符串并通过中断实现对字符串的整体输出。第三方面,相对来说比较简单,因为输入字符中断的返回值时该字符的ascii,也就是说,只要识别出是ctrl+c组合键的ascii,直接调用中断退出程序即可。
另外,在对子程序的设计中,还要分析如何让计算机根据按键发声。
3.题目设计:
总体流程图如图所示:
程序总体流程图
4.代码实现:

assume cs:code,ds:data,ss:stack
data segment
    ratetable dw 524,588,660,784,880,988,1048;频率表
    str db 0ah,0dh,'Welcome to the masm player!',0ah,0dh;提示菜单信息供用户选择
	db '-----------------------MENU--------------------',0ah,0dh
	db '|','     You could choose 1 to play music        |',0ah,0dh
	db '|','     You could choose 2 to play the pinao    |',0ah,0dh
	db '|','     Press the (Ctrl+C) to exit the player   |',0ah,0dh
	db '-----------------------------------------------',0ah,0dh,'$'
    pianoStr db 0ah,0dh,'You could enter number 1-8 '			;钢琴功能提示信息
	db 'to play the masm pinao!',0ah,0dh
	db 'Press the (Esc) back to memu',0ah,0dh
	db 'Press the (Ctrl+C) to exit',0ah,0dh,'$'
    mus_freq dw 262,262,262,196							;音乐功能频率表
         dw 330,330,330,262
         dw 262,330,392,392
         dw 349,330,294
         dw 294,330,349,349
         dw 330,294,330,262
         dw 262,330,294,196
         dw 247,294,262,-1
    mus_time dw 3 dup(12,12,25,25),12,12,50
         dw 3 dup(12,12,25,25),12,12,50

    error1 db 0ah,0dh,'Error:No such option, please re-enter!',0ah,0dh,'$';选择功能时提示错误
    error2 db 0ah,0dh,'Error: Only number 1 - 8 are allowed!',0ah,0dh;钢琴提示输入错误
	db 'Remind: Please enter the correct number!',0ah,0dh,'$'
data ends

stack segment
	db 100 dup(0)
stack ends

code segment
start:
	mov ax,data;初始换寄存器
	mov ds,ax
	mov ax,stack
	mov ss,ax
	mov sp,100

;*****************************************************************
; 标号段:choice
; 功能:用户进行功能选择
; 入口参数:ds,表示数据段地址
;	    ss,sp,表示栈段地址
; 出口参数:无
; 调用注意事项:无
;-----------------------------------------------------------------
; 中断:Dos下21h下的09h中断
; 功能:输出一个字符串到标准输出设备上
; 入口参数:ah=09h
;			Ds:dx=待输出字符的地址
; 出口参数:无
; 调用注意事项:待显示的字符串以‘$’作为结束标志
;-----------------------------------------------------------------
; 中断:Dos下21h下的01h中断
; 功能:从标准输入设备读入一个字符
; 入口参数:ah=01h
; 出口参数:al=输入字符的ascii
; 调用注意事项:此中断会过滤掉控制字符并回显
;*****************************************************************
    c:  call clear;清屏子程序
	lea dx,str
	mov ah,09h;输出str字符串
	int 21h
    choice:

	mov ah,01h				;输入字符
	int 21h
	cmp al,03h				;al保存的是输入字符的ascii,(ctrl+c)的ascii是03h
	je quit					;跳出这个choice循环的条件
	cmp al,'1'
	je playmusic			;执行播放音乐程序
	cmp al,'2'
	je playpiano			;执行钢琴子程序

	lea dx,error1			;提示错误信息
	mov ah,09h				;输出error1字符串
	int 21h
	jmp choice				;只要输入数据不是功能按键,就循环执行choice

;退出程序
    quit:
	mov ax,4c00h
	int 21h
;清屏
    clear:    
	mov ax, 3h  			;调用10H的3号中断
	int 10h
	ret

    playpiano:
	call clear
	lea dx,pianoStr;lea指令获取数据段pianoStr字符串的首地址并存到dx寄存器
	mov ah,09h				;输出pianoStr字符串
	int 21h
      a:
	mov ah,01h				;输入字符
	int 21h
	cmp al,03h				;al保存的是输入字符的ascii,(ctrl+c)的ascii是03h
	je quit					;跳出这个choice循环的条件
	cmp al,1Bh				;Esc的ascii
	je c
	call piano
	jmp a
    playmusic:
	lea si, mus_freq
	lea di, mus_time
	call music
	jmp choice

;*****************************************************************
; 子程序:piano
; 功能:实现钢琴功能
; 入口参数:al——表示从键盘输入字符的ascii
; 出口参数:无
;调用注意事项:主要是进出子程序前后对子程序中要用到的寄存器进行进栈出栈操作
;*****************************************************************
piano proc
	push ax;先将子程序中可能要使用的寄存器进栈,方便使用
	push bx
	push dx
	
	cmp al,'1'				;输入数字1跳转
	je one
	cmp al,'2'				;输入数字2跳转
	je two
	cmp al,'3'				;输入数字3跳转
	je three
	cmp al,'4'				;输入数字4跳转
	je four
	cmp al,'5'				;输入数字5跳转
	je five
	cmp al,'6'				;输入数字6跳转
	je six
	cmp al,'7'				;输入数字7跳转
	je seven
	cmp al,'8'				;输入数字8跳转
	je eight
	jmp wrong			;输入其他字符跳转

    wrong:				;按下除了1-8之外的其他非控制按键会提示错误信息
	lea dx,error2			;获取数据段error2字符串的首地址
	mov ah,09h			;输出字符串
	int 21h
	jmp exit_piano
;***************
; 标号段:one--eight
; 功能:实现按下键盘1-8执行不同程序
; 入口参数:无
; 出口参数:bx,表示在数据段标号处的偏移地址
;调用注意事项:无
;*****************************************************************
    one:
	mov bx,0
	jmp output
    two:
	mov bx,2
	jmp output
    three:
	mov bx,4
	jmp output
    four:
	mov bx,6
	jmp output
    five:
	mov bx,8
	jmp output
    six:
	mov bx,10
	jmp output
    seven:
	mov bx,12
	jmp output
    eight:
	mov bx,14
	jmp output
;*****************************************************************
; 标号段:output
; 功能:实现演奏功能
; 入口参数:bx——表示数据段ratetable标号处的偏移量
; 出口参数:无
;调用注意事项:无
;*****************************************************************
    output:
	mov ax,3280h
	mov dx,0012h				;置被除数
	div ratetable[bx]				;计算频率值(16位),设置声音的频率
	mov bx,ax

	mov al,0b6h					;设置定时器工作方式,对8253的定时器2进行初始化,因为定时器2连接扬声器
	out 43h,al					;将al的值放到43h端口,43h是8253芯片控制口的端口地址

	mov ax,bx					;装入16位的计数值
	out 42h,al					;设置低位
	mov al,ah
	out 42h,al					;设置高位

	in al,61h						;读设备控制器端口原值,61h端口与喇叭相连
	or al,03h						;bit0和bit1都为1时,打开扬声器和定时器
	out 61h,al					;接通扬声器,发声

	call delay2

	in al,61h						;关闭扬声器声音
	and al,0fch
	out 61h,al

    exit_piano:					;退出钢琴子程序,注意将子程序开始时进栈的寄存器出栈
	pop dx						;还要注意出栈顺序要与进栈是顺序相反
	pop bx
	pop ax
	ret
piano endp

;*****************************************************************
; 子程序:music
; 功能:实现播放音乐功能
; 入口参数:si--表示数据段频率表偏移量
; 出口参数:无
; 说明:music子程序演奏结束后自动回到MENU界面,音乐演奏中按下键盘会等到演奏结束执行
;*****************************************************************
music proc;播放音乐
    play:
	mov dx, [si]
	cmp dx, -1
	je end_play
	call sound
	add si, 2
	add di, 2
	jmp play

;演奏一个音符
;入口参数:si - 要演奏的音符的频率的地址
;          di - 要演奏的音符的音长的地址
;*****************************************************************
; 标号段:sound
; 功能:实现演奏功能
; 入口参数:si——表示数据段标号mus_freq处的偏移量
; 出口参数:无
;调用注意事项:无
;*****************************************************************
    sound:
	push ax
	push dx
	push cx
    ;8253 芯片(定时/计数器)的设置
	mov al,0b6h				;8253初始化
	out 43h,al				;43H是8253芯片控制口的端口地址
	mov dx,12h
	mov ax,34dch
	div word ptr [si] 			;计算分频值,赋给ax。[si]中存放声音的频率值。
	out 42h, al				;先送低8位到计数器,42h是8253芯片通道2的端口地址
	mov al, ah
	out 42h, al				;后送高8位计数器

	;设置8255芯片, 控制扬声器的开/关
	in al,61h					;读取8255 B端口原值
	mov ah,al				;保存原值
	or al,3 					;使低两位置1,以便打开开关
	out 61h,al				;开扬声器, 发声

	mov dx, [di]				;保持[di]时长
    wait1:
	mov cx, 28000
    delay1:					;延迟子程序
	nop
	loop delay1
	dec dx
	jnz wait1

	mov al, ah				;恢复扬声器端口原值
	out 61h, al

	pop cx
	pop dx
	pop ax
	ret
    end_play:
	ret
music endp

;*****************************************************************
; 子程序:delay2
; 功能:实现延时效果
; 入口参数:bx——表示数据段ratetable标号处的偏移量
; 出口参数:无
; 说明:由于cpu执行一条语句太快,近似1us,我们没法看清楚,所以通过增加cpu执行语句的数量的方式起到延时的效果
;*****************************************************************

delay2 proc					;延迟子程序,使结果更清晰
	push cx
	mov cx,60000
    delay2_loop:
	nop
	loop delay2_loop
	pop cx
ret
delay2 endp
code ends
end start

5.测试结果:
程序加载初始界面

  • 6
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值