按改指键说明:
1、不输入任何数字,直接按回车键,可结束程序,返回 *** 作系统
2、每次最多能够输入N(本程序,N=8)个数字(1~8)
3、不足8位数字的,按回车结束输入
本程序在MASMPlus 1.2集成环境下通过编译,经过调试,运行正确。
Code Segment
Assume CS:Code,DS:Code
CR EQU 000DH
LF EQU 000AH
-------------------------------------
功能:显示指定地址(Str_Addr)的字符串
入口:
Str_Addr=字符串地址(要求在数据段)
用法: Output Str_Addr
用法举例:Output PromptStr
Output MACRO Str_Addr
lea dx,Str_Addr
mov ah,9
int 21h
EndM
-------------------------------------
功能:输出一个字符
入口:dl=要显示的字符
Output_Chr proc Near
push ax
mov ah,02h
int 21h
pop ax
ret
Output_Chr endp
-------------------------------------
功能:输出回车换行
Output_CTLF proc Near
push ax
push dx
mov ah,02h
mov dl,0dh
int 21h
mov dl,0ah
int 21h
pop dx
pop ax
ret
Output_CTLF endp
-------------------------------------
Subroutine 延时指定的时钟嘀嗒数
入袜歼模口:
Didas=时钟嘀嗒数(1秒钟约嘀嗒18.2次,10秒钟嘀嗒182次。若延时不是秒的10数次倍,误差稍微大点)
Delay Proc Near
push dx
push cx
xor ax,ax
int 1ah
mov Times,dx
mov Times[2],cx
Read_Time: xor ax,ax
int 1ah
sub dx,Times
sbb cx,Times[2]
cmp dx,Didas
jb Read_Time
pop cx
pop dx
ret
Times dw 0,0
Delay EndP
-告缓----------------------------------------
功能:从键盘输入N位数字
入口:N=数字位数;di=保存输入的数字首地址
出口:cx=实际接收的数字位数
Input_Digit Proc Near
cld
mov cx,N
@@Input: mov ah,1
int 21h
cmp al,CR
jz @@Return
cmp al,'1'
jb @@Input
cmp al,'8'
ja @@Input
stosb
loop @@Input
@@Return: mov ax,N
sub ax,cx
xchg ax,cx
ret
Input_Digit EndP
-----------------------------------------
入口参数
SI=声音频率地址
CX=时间
Music Proc Near
in al,61h
push ax
or al,3
out 61h,al 接通扬声器
push cx
push dx
push si
mov al,0b6h
out 43h,al
mov dx,12h
mov ax,348ch
div word ptr [si]
out 42h,al
mov al,ah
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
mov cx,3314
push ax
@@Waitf1: in al,61h
and al,10h
cmp al,ah
jz @@Waitf1
mov ah,al
loop @@Waitf1
pop ax
call Delay 延时
mov al,ah
out 61h,al 关闭扬声器
pop si
pop dx
pop cx
pop ax
out 61h,al
ret
Music EndP
-----------------------------------------
Didas equ 18 延时(时钟嘀嗒次数)
frequency dw 262,294,330,349,392,440,492,524 频率值
dw 441,495,556,589,661,742,833 从其它音乐程序抄来的频率值
dw 882,990,1112,1178,1322,1484,1655 同上行
N equ 8
PromptStr db 'Please Enter ',N or 30h,' digitals(1-8): $'
Number db N dup(?)
Press_Key dbCR,LF,CR,LF,'Press any key to exit...$'
-----------------------------------------
Start:push cs
pop ds
push cs
pop es 使数据段、附加段与代码段同段
Input_Str: Output PromptStr 提示输入N位数字
lea di,Number 数字保存地址
call Input_Digit 从键盘接收数字
call Output_CTLF 输出一个回车、换行
call Output_CTLF 输出一个回车、换行
jcxz Exit_Proc
lea bx,Number 数字保存地址
Sound: push cx
push bx
mov dl,[bx] 读入一个数字
call Output_Chr 屏幕显示这个数字
and dl,0fh
dec dl
shl dl,1
mov bl,dl
mov dl,0eh
call Output_Chr 显示一个音乐符号
mov dl,20h
call Output_Chr 显示一个空格
lea si,frequency[bx] 对应的频率值地址
call Music 激活扬声器,使之发出指定频率、指定时长的声音
pop bx
inc bx 增1,处理下一个音符
pop cx
loop Sound
call Output_CTLF 输出一个回车、换行
call Output_CTLF 输出一个回车、换行
jmp Input_Str
-------------------------------------
Exit_Proc: Output Press_Key 提示 *** 作完成,按任意键结束程序
mov ah,1
int 21h
mov ah,4ch 结束程序
int 21h
Score_Table: 学生成绩存储区
Code ENDS
END Start 编译到此结束
这个我曾经用单片机写过《青正粗塌花瓷》这首歌,不知道你用什么硬件实现。我用的原理是:用汇编来产生一系列频率不同的方波信号,并将该信号输出到扬声器,如过驱动功率不够则需要加放大电路凳缺。你找些资料查一下简谱中的 do rua mi fa sao la xi 这些记谱符号的频举圆率,然后用汇编语言产生同频信号即可。这是张雨生的《大海》片断数据段中FREQ定义的是一首歌的各个音调频率,TIME定义的是各个音调的发音持续时间。
代码段中首慧铅誉先将变量表FREQ和TIME对应位置的元素分别存入寄存器CX和BX,然后用这两个寄存器的内容作为传入参数调用子程序GENSOUND。
子程序GENSOUND通过控制计算机主板上的硬件从而控制蜂鸣器发声。过程为:通过传入的cx中的参数计算出主板计数器通道2的计数初激升值并进行设置,然后使主板61h端口的低两位同时为1,使得计数器2的门控信号有效,计数通道2开始工作并产生一定频率的信号驱动蜂鸣器发出声音。然后通过传入的bx中的参数延时一段时间,再将61h端口的低两位恢复为零,使得计数器2的门控信号无效,禁止其工作,停止发声。
将变量表FREQ和TIME对应位置一对元素作为参数,重复调用子程序就可以演奏音乐了。
变量表FREQ定义的最后一个元素“-1”作为程序前段的结束条件。
data segment
freq dw 196,220
dw 262,262,262,262,262,220,196
dw 262,262,262,262,294,262,220,262
dw 294,294,294,294,294,262,220
dw 294,294,294,294,330,294,330,392
dw 440,440,392,440,392,330
dw 294,294,330,294,262,220,196,220
dw 262,262,262,262,262,220
dw 262,196,220
dw 440,440,392,440,524,440
dw 392,330,294,262,220,196,220
dw 262,262,262,262,294,262
dw 262,330,392
dw 440,440,440,440,524,440
dw 392,392,392,440,392,330,294
dw 262,262,262,262,294
dw 330,330,294
dw 262,262,262,262,524,440
dw 392,392,392,440,392,330,392
dw 440,524,524,440,392
dw 392,330,392
dw 440,440,440,440,524,440
dw 392,392,392,440,392,330,294
dw 262,262,262,262,392
dw 330,330,294
dw 262,262,262,262,294,330
dw 392,392,330,392,330,392
dw 440
dw 9,9,196,660,294,294,262
dw 262,-1 ;定义一首歌的各音调信息,最后的-1作为结束标志
time dw 400,400
dw 400,200,400,400,800,400,400
dw 400,200,400,200,200,800,400,400
dw 400,200,400,400,800,400,400
dw 400,200,400,200,200,800,400,400
dw 400,800,400,800,400,400
dw 400,200,200,400,400,800,400,400
dw 400,200,400,400,800,800
dw 1600,800,800
dw 400,800,400,800,400,400
dw 400,400,400,400,800,400,400
dw 400,800,400,800,400,200
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,200,200,800,400,400
dw 400,800,400,800,800
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,200,200,800,400,400
dw 800,400,800,400,200
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,200,200,800,400,400
dw 400,800,400,800,800
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,400,800,400,400
dw 3200
dw 800,400,400,400,400,400,400
dw 4000 ;定义各音调的演奏时间信息,与FREQ中的信息一一对应
data ends
code segment
assume cs:code,ds:data
main proc far
start:mov ax,data
mov ds,ax ;装载数据段
mov si,offset freq ;初始freq表的指针
mov di,offset time ;初始time表的指针
l1: mov cx,[si] ;取freq的一个数据到cx
cmp cx,-1 ;判断是否是结束标志
je exit ;取到结束标志,程序转至exit结束
mov bx,[di] ;取time表中对应位置的元素到bx
call gensound ;以cx,bx为参数调用子程序
add si,2
add di,2 ;修改两个变量表的指针寄存器
jmp l1
exit:mov ax,4c00h
int 21h ;程序结束,返回dos系统
main endp
gensound proc near
push dx ;保护现场
mov al,0b6h
out 43h,al ;初始化主板上计数通道2,16位计数初值,工作方式3. 43h为计数器控制口地址
mov dx,8h
mov ax,3208h ;dx,ax联合存放计数通道2的输入时钟频率值83208h,即537KHz
div cx ;除以传入的音调频率,得到计数通道2的计数初值保存至ax
out 42h,al
mov al,ah
out 42h,al ;计数初值写入计数通道2。42h为其地址
in al,61h ;读主板61h端口的值
mov ah,al ;保存至ah,后面要用到
or al,3 ;将最低两位置1,其余位不变
out 61h,al ;将修改后的信息写回61h端口,计数通道2开始工作,驱动扬声器发出一个音调
l2: push dx
push ax
mov dx,8h
mov ax,0f05h
s1: sub ax,1
sbb dx,0
jnz s1
pop ax
pop dx
dec bx
jnz l2 ;cpu通过以上程序片断延迟一段时间,延时由传入的bx的值决定。延时时间就是一个音调的持续发声时间
mov al,ah
out 61h,al ;将保存的61h端口原信息写回,禁止通道2工作,暂停发声
pop dx ;恢复现场
ret ;子程序返回
gensound endp
code ends
end start
一首歌的音调及延时信息不好确定,除非是专业人士,其实想知道也没必要。这个程序主要是要看懂其原理,数据倒是次要的。你在原数据的基础上随便修改后也能演奏,只不过听上去跑调
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)