汇编发声程序

汇编发声程序,第1张

我这有个现成的,希望对你能有所帮助。

按改指键说明:

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

一首歌的音调及延时信息不好确定,除非是专业人士,其实想知道也没必要。这个程序主要是要看懂其原理,数据倒是次要的。你在原数据的基础上随便修改后也能演奏,只不过听上去跑调


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12537963.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存