乐曲演奏硬件电路设计报告.docx
《乐曲演奏硬件电路设计报告.docx》由会员分享,可在线阅读,更多相关《乐曲演奏硬件电路设计报告.docx(19页珍藏版)》请在冰豆网上搜索。
乐曲演奏硬件电路设计报告
乐曲硬件演奏电路设计
一、设计任务要求
在EDA开发平台上利用VHDL语言设计数控分频器电路,利用数控分频的原理设计乐曲硬件演奏电路,并定制LPM-ROM存储音乐数据,以古典名曲“梁祝”乐曲为例,将音乐数据存储到LPM-ROM,就达到了以纯硬件的手段来实现乐曲的演奏效果。
与利用微处理器来实现乐曲演奏相比,一纯硬件完成乐曲演奏电路的逻辑要复杂得多,如果不借助于功能强大的EDA工具和硬件描述语言,仅凭传统的数字逻辑技术,即使最简单的演奏电路也难以实现。
二、系统设计总述
系统设计由以下五个部分组成,分别是乐曲演奏电路基本原理,音符频率的获得,乐曲节奏的控制,乐谱发生器,乐曲演奏电路总体设计流程这五个部分。
乐曲演奏电路基本原理
硬件电路的发声原理是,因为声音的频谱范围约在几十到几千赫兹,若能利用程序来控制FPGA芯片某个引脚输出一定频率的矩形波,接上扬声器就能发出相应频率的声音。
乐曲中的每一音符对应着一个确定的频率,要想FPGA发出不同音符的音调,实际上只要控制它输出相应音符的频率即可。
乐曲都是由一连串的音符组成,因此按照乐曲的乐谱依次输出这些音符所对应的频率,就可以在扬声器上连续地发出各个音符的音调。
不过要准确地演奏出一首乐曲,仅仅让扬声器能够发生还是不够的,还必须准确地控制乐曲的演奏节奏,就是指乐曲能够连续演奏的两个关键因素:
乐曲中每个音符的发声频率及其持续时间。
音符频率的获得
多个不同频率的信号可通过对某个基准频率进行分频获得。
由于各个音符的频率多为非整数,而分频系数又不能为小数,故必须将计算机得到的分频系数四舍五入取整。
若基准频率过低,则分频系数过小,四舍五入取整后的误差较大。
若基准频率过高,虽然可以减少频率的相对误差,但分频结构将变大。
实际上应该综合考虑这两个方面的因素,在尽量减少误差的前提下,选取合适的基准频率。
本设计中选取750KHz的基准频率。
由于现有的高频时钟脉冲信号的频率为12MHz,故需先对其进行16分频,才能获得750KHz的基准频率。
对基准频率分频后的输出信号是一些脉宽极窄的尖脉冲信号(占空比=1/分频系数)。
为提高输出信号的驱动能力,以使扬声器有足够的功率发音,需要再通过一个分频器将原来的分频器的输出脉冲均衡为对称方波(占空比=1/2),但这时的频率将是原来的1/2。
各音符的分频系数是从750KHz的基准频率二分频得到的375KHz频率基础上计算得到的。
由于最大分频系数是1274,故分频器采用的二进制计数器能满足要求,乐曲中的休止符,只要将分频系数设为0,即初始值=211-1=2047,此时扬声器不会发声。
乐曲节奏的控制
本设计中的乐曲“梁祝”,最小节拍为1/4拍,若将1拍的时间定为1秒,则只需要提供一个4Hz的时钟频率即可产生1/4拍的时长(0.25秒),对于其它占用时间较长的节拍(必为1/4拍的整数倍)则只需要将该音符连续输出相应的次数就可以了。
计数时钟信号作为输出音符快慢的控制信号,时钟快时输出节拍速度就快,演奏的速度也相应的快,时钟慢时输出节拍的速度就慢,演奏的速度自然也相应的降低。
乐谱发生器
乐谱中的音符数据存储在LPM-ROM中,比如“梁祝”乐曲中的一个音符为“3”,此音在逻辑中停留了4个时钟节拍,即1秒的时间,相应地,音符“3”就要在LPM-ROM中连续的四个地址上都存储。
当一个4Hz的时钟来时,相应地就从LPM-ROM中输出一个音符数据。
乐曲演奏电路总体设计流程
当一个4Hz的时钟脉冲来到时,乐谱发生器模块输出一个音符数据给分频系数模块,分频系数模块输出此音符相应的分频系数,将分频系数送给数控分频器模块,当12MHz的时钟脉冲来到时,数控分频器就根据分频系数输出相应的频率(即此音符所对应的发生频率)给扬声器,扬声器就可发出对应音符的声音来.连续的4Hz的时钟脉冲就将乐谱发生器里所存储的音符数据一个接一个的送给了分频系数模块,再经过数控分频模块,最后扬声器一个接一个的发出音符数据所对应的声音来,曲子也就流畅的播放出来。
三、总体程序设计
总体系统框图
该系统主要由三个部分组成,顶层设计文件,其内部有三个功能模块:
TONETABA.VHD、NOTATABS.VHD、和SPEAKERA.VHD。
首先定制TONETABA.VHD、模块一类似于弹琴人的手指,模块二类似于琴键,模块三类似于琴弦或音调发生器。
模块中的音符数据ROM“music”。
然后根据给出的乘法器逻辑原理图及其模块的VHDL描述在QuartusⅡ上完成设计。
最后完成编译,综合,仿真,管脚锁定,编程下载。
音符的频率可由Speakera获得,这是一个数控分频器。
由其clk端输入一个具有较高频率的信号,通过Speakera分频后由SPKOUT输出,由于直接数控分频器出来的输出信号是脉宽极窄的脉冲式信号,为了有利于驱动扬声器,需要另加一个D触发器以均衡器占空比,但这是的频率将是原来的1/2。
Speakera对clk输入信号的分频比由11位预置数Tone[10..0]决定。
SPKOUT输出频率将决定每一个音符的音调,这样,分频计数器的预置值Tone[10..0]与SPKOUT的输出频率就有了对应关系。
音频的持续时间需根据乐曲的速度及每个音符的节拍数来确定,模块ToneTaba的功能首先是为Speakera提供决定所发音符的分频预置数,而次数在Speakera输入口停留的时间即为此音符的节拍值。
模块ToneTaba是乐曲简谱码对应的预置数,共13个,每一音符的停留时间由音乐节拍和音调发生器模块NoteTabs的clk的输入频率决定,在此喂4Hz。
这13个值的输出由对应于ToneTaba的4位输入值Index[3..0]确定,而Index[3..0]最多有16种可选值。
输向ToneTaba中的Index[3..0]的值ToneIndex[3..0]的输出值与持续时间由模块NoteTabs决定。
在NoteTabs中设置了一个8位二进制计数器计数最大值为138),作为音符数据ROM的地址发生器。
这个计数器的技术频率选为4Hz,即每一个计数值的停留时间为0.25秒,恰为当全音符设为1秒时,四四拍的4分音符持续时间。
顶层电路VHDL程序设计
LIBRARYIEEE;--硬件演奏电路顶层设计
USEIEEE.STD_LOGIC_1164.ALL;
ENTITYSongerIS
PORT(CLK12MHZ:
INSTD_LOGIC;--音调频率信号
CLK8HZ:
INSTD_LOGIC;--节拍频率用于控制音长(节拍)的时钟频率;
CODE1:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);--简谱码输出显示
HIGH1:
OUTSTD_LOGIC;--高8度指示
SPKOUT:
OUTSTD_LOGIC);--声音输出
END;
ARCHITECTUREoneOFSongerIS
COMPONENTNoteTabs--元件u1例换化
PORT(clk:
INSTD_LOGIC;
ToneIndex:
OUTSTD_LOGIC_VECTOR(3DOWNTO0));
ENDCOMPONENT;
COMPONENTToneTaba--元件u2例换化
PORT(Index:
INSTD_LOGIC_VECTOR(3DOWNTO0);
CODE:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);
HIGH:
OUTSTD_LOGIC;
Tone:
OUTSTD_LOGIC_VECTOR(10DOWNTO0));
ENDCOMPONENT;
COMPONENTSpeakera--元件u3例换化
PORT(clk:
INSTD_LOGIC;
Tone:
INSTD_LOGIC_VECTOR(10DOWNTO0);
SpkS:
OUTSTD_LOGIC);
ENDCOMPONENT;
SIGNALTone:
STD_LOGIC_VECTOR(10DOWNTO0);
SIGNALToneIndex:
STD_LOGIC_VECTOR(3DOWNTO0);
BEGIN
u1:
NoteTabsPORTMAP(clk=>CLK8HZ,ToneIndex=>ToneIndex);--参数传递映射语句
u2:
ToneTabaPORTMAP(Index=>ToneIndex,Tone=>Tone,CODE=>CODE1,HIGH=>HIGH1);
u3:
SpeakeraPORTMAP(clk=>CLK12MHZ,Tone=>Tone,SpkS=>SPKOUT);
END;
单元模块程序设计
共分为music模块、地址发生器模块、分频预置数模块、十六进制模块、数控分频模块这五个模块。
music模块存放乐曲中的音符数据,地址发生器模块作为music模块中所定制的音符数据ROM的地址发生器,分频预置数模块提供分频预置数即给数控分频模块提供计数初值,十六进制模块对12MHz的时钟脉冲进行16分频,得到750KHz的频率,给数控分频模块提供时钟脉冲。
数控分频模块根据分频预置数输出各个音符所对应的频率。
音符的频率由数控分频模块获得,这是一个数控分频电路。
它是由一个初值可变的加法计数器构成。
该计数器的模为2047,当计数器记满时,计数器产生一个溢出信号FULL,此溢出信号就是用作发音的频率信号。
在计数器的输入端给定不同的初值,而此预置数就是表1中的计数初值,就可得到不同音符的发音频率信号。
它计满时所需要的计数初值可由下式来表示。
计数初值(Tone)=2047-分频系数,而分频系数又可有下式来求:
分频系数=基准频率/音符的发生频率。
低音时Tone值小,分频系数大,溢出信号周期长,扬声器发出的声音低,Tone随音乐的乐谱变化大,自动控制分频比,实现了数控分频,发生信号的频率与音调Tone成正比。
这就是利用数控分频器自动演奏音乐的原理。
时钟(Clk)端输入的是在十六进制模块里对12MHz的信号进行16分频得到的750KHz,750KHz的信号根据分频预置数模块中所提供的计数初值,分别得出相应音符频率的两倍值。
此时从数控分频器中出来的输出信号是脉宽极窄的脉冲式信号,为了有利于驱动扬声器,需另加一个D触发器以均衡其占空比,这时的频率就变为原来的1/2,刚好就是相应音符的频率。
数控分频模块中对Clk输入信号的分频比由11位预置数tone[10..0]决定。
Fout的输出频率将决定每一个音符的音调,这样,分频计数器的预置值tone[10..0]与Fout的输出频率就有了对应关系。
例如在分频预置数模块中若取tone[10..0]=1036,将发出音符为“3”音的信号频率。
音符的频率由数控分频模块VHDL程序:
LIBRARYIEEE;
LIBRARYIEEE;--音乐符数控分频电路模块
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYSpeakeraIS
PORT(clk:
INSTD_LOGIC;--音调频率信号12MHZ
Tone:
INSTD_LOGIC_VECTOR(10DOWNTO0);--音乐符对应分频11位
SpkS:
OUTSTD_LOGIC);--声音输出
END;
ARCHITECTUREoneOFSpeakeraIS
SIGNALPreCLK,FullSpkS:
STD_LOGIC;
BEGIN
DivideCLK:
PROCESS(clk)
VARIABLECount4:
STD_LOGIC_VECTOR(3DOWNTO0);
BEGIN
PreCLK<='0';--将CLK进行16分频,PreCLK为CLK的16分频
IFCount4>11THENPreCLK<='1';Count4:
="0000";
ELSIFclk'EVENTANDclk='1'THENCount4:
=Count4+1;
ENDIF;
ENDPROCESS;
GenSpkS:
PROCESS(PreCLK,Tone)--11位可预置计数器
VARIABLECount11:
STD_LOGIC_VECTOR(10DOWNTO0);
BEGIN
IFPreCLK'EVENTANDPreCLK='1'THEN
IFCount11=16#7FF#THENCount11:
=Tone;FullSpkS<='1';
ELSECount11:
=Count11+1;FullSpkS<='0';ENDIF;
ENDIF;
ENDPROCESS;
DelaySpkS:
PROCESS(FullSpkS)--将输出再2分频,展宽脉冲,使扬声器有足够功率发音
VARIABLECount2:
STD_LOGIC;
BEGIN
IFFullSpkS'EVENTANDFullSpkS='1'THENCount2:
=NOTCount2;
IFCount2='1'THENSpkS<='1';
ELSESpkS<='0';ENDIF;
ENDIF;
ENDPROCESS;
END;
音乐谱对应分频预制数查表电路VHDL程序设计
音乐谱分频预置数模块是乐曲简谱码对应的分频预置数查表电路。
它提供了每个音符所对应的分频预置数,即给数控分频模块提供计数初值,这里以“梁祝”乐曲为例,列出了在这个乐曲中所用到的13个音符的分频预置数。
在这个模块的VHDL逻辑描述中设置了四四拍乐曲中全部音符所对应的分频预置数,共13个,每一音符的停留时间由音乐节拍和地址发生器模块的时钟(Clk)的输入频率决定,在此为4Hz。
这13个值的输出由程序[3]的4位输入值index[3..0]确定。
输向程序[4]中index[3..0]的值又由地址发生器模块的输出toneindex[3..0]的输出值和持续时间决定。
模块的功能是输出各个音符所对应的分频预置数,即当index是“0000”,tone输出为2047,即休止符的分频预置数;当index是“0101”时,tone输出为1197即低音5的分频预置数;当index是“1111”时,tone输出为1728即高音1的分频预置数等等其它状态时,tone分别输出相应音符的分频预置数。
分频预置数模块的VHDL设计程序:
LIBRARYIEEE;--音乐谱对应分频预制数查表电路模块
USEIEEE.STD_LOGIC_1164.ALL;
ENTITYToneTabaIS
PORT(Index:
INSTD_LOGIC_VECTOR(3DOWNTO0);--4位预制数查表
CODE:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);
HIGH:
OUTSTD_LOGIC;--音乐高8度指示
Tone:
OUTSTD_LOGIC_VECTOR(10DOWNTO0));--音乐符对应分频11位
END;
ARCHITECTUREoneOFToneTabaIS
BEGIN
Search:
PROCESS(Index)
BEGIN
CASEIndexIS--译码电路,查表方式,控制音调的预置数13组频率
WHEN"0000"=>Tone<="11111111111";CODE<="0000";HIGH<='0';--2047
WHEN"0001"=>Tone<="01100000101";CODE<="0001";HIGH<='0';--773;
WHEN"0010"=>Tone<="01110010000";CODE<="0010";HIGH<='0';--912;
WHEN"0011"=>Tone<="10000001100";CODE<="0011";HIGH<='0';--1036;
WHEN"0101"=>Tone<="10010101101";CODE<="0101";HIGH<='0';--1197;
WHEN"0110"=>Tone<="10100001010";CODE<="0110";HIGH<='0';--1290;
WHEN"0111"=>Tone<="10101011100";CODE<="0111";HIGH<='0';--1372;
WHEN"1000"=>Tone<="10110000010";CODE<="0001";HIGH<='1';--1410;
WHEN"1001"=>Tone<="10111001000";CODE<="0010";HIGH<='1';--1480;
WHEN"1010"=>Tone<="11000000110";CODE<="0011";HIGH<='1';--1542;
WHEN"1100"=>Tone<="11001010110";CODE<="0101";HIGH<='1';--1622;
WHEN"1101"=>Tone<="11010000100";CODE<="0110";HIGH<='1';--1668;
WHEN"1111"=>Tone<="11011000000";CODE<="0001";HIGH<='1';--1728;
WHENOTHERS=>NULL;
ENDCASE;
ENDPROCESS;
END;
音乐节拍和音调发生器模块VHDL程序设计
LIBRARYIEEE;--音乐节拍和音调发生器模块
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYNoteTabsIS
PORT(clk:
INSTD_LOGIC;--音乐节拍时钟4HZ
ToneIndex:
OUTSTD_LOGIC_VECTOR(3DOWNTO0));
END;
ARCHITECTUREoneOFNoteTabsIS
COMPONENTmusic--音符数据ROM1
PORT(address:
INSTD_LOGIC_VECTOR(7DOWNTO0);
inclock:
INSTD_LOGIC;
q:
OUTSTD_LOGIC_VECTOR(3DOWNTO0));
ENDCOMPONENT;
SIGNALCounter:
STD_LOGIC_VECTOR(7DOWNTO0);--8位二进制计数器
BEGIN
CNT8:
PROCESS(clk,Counter,sel,rst)
BEGIN
IF((clk'EVENTANDclk='1')and(Counter=256orrst='0'))thenCounter<="00000000";Counter<=Counter+1;
endif;
IF((clk'EVENTANDclk='1')and(sel='0'))THENCounter<="10010000";Counter<=Counter+1;
ENDIF;
ENDPROCESS;
u1:
MUSICPORTMAP(address=>Counter,q=>ToneIndex,inclock=>clk);
END;
ROM中的音符数据模块(music)程序为:
WIDTH=4;--“梁祝“乐曲演奏数据
DEPTH=256;
ADDRESS_RADIX=DEC;
DATA_RADIX=DEC;
CONTENTBEGIN
00:
3;01:
3;02:
3;03:
3;04:
5;05:
5;06:
5;07:
6;08:
8;09:
8;
10:
8;11:
9;12:
6;13:
9;14:
5;15:
5;16:
12;17:
12;18:
12;19:
15;
20:
13;21:
12;22:
6;23:
12;24:
9;25:
9;26:
9;27:
9;28:
9;29:
9;
30:
9;31:
0;32:
9;33:
9;34:
9;35:
10;36:
7;37:
7;38:
6;39:
6;
40:
5;41:
5;42:
5;43:
6;44:
8;45:
8;46:
9;47:
9;48:
3;49:
3;
50:
8;51:
8;52:
6;53:
5;54:
6;55:
8;56:
5;57:
5;58:
5;59:
5;
60:
5;61:
5;62:
5;63:
5;64:
10;65:
10;66:
10;67:
12;68:
7;69:
7;
70:
9;71:
9;72:
6;73:
8;74:
5;75:
5;76:
5;77:
5;78:
5;79:
5;
80:
3;81:
5;82:
3;83:
3;84:
5;85:
6;86:
7;87:
9;88:
6;89:
6;
90:
6;91:
6;92:
6;93:
6;94:
5;95:
6;96:
8;97:
8;98:
8;99:
9;
100:
12;101:
12;102:
12;103:
10;104:
9;105:
9;106:
10;107:
9;108:
8;109:
8;
110:
6;111:
5;112:
3;113:
3;114:
3;115:
4;116:
8;117:
8;118:
8;119:
8;
120:
6;121:
8;122:
6;123:
5;124:
3;125:
5;126:
6;127:
8;128:
5;129:
5;
130:
5;131:
8;132:
5;133:
5;134:
5;135:
5;136:
0;137:
0;138:
0;
End;
其中WIDTH=4,表示数据输出为宽为4;DEPTH=256,表示共有256个4位数据点;ADDRESS-RADIX=DEC,表示地址信号用十进制;DATA-RADIX=DEC,表示输出数据是十进制数。
形成ROM中的配置数据(初始化数据)文件的方法是:
在QuartusII中编辑.mif文件。
首先在File菜单下的New菜单上选择TextEditorFile命令,进入文本编辑器,然后输入以上格式的数据文件。
文件中的关键词WIDTH设置ROM的数据宽度;DEPTH设置ROM数据的深度,即4位数据的数量,文件中设置的256等效于8位地址线宽度;ADDRESS-RADIX=DEC和DATA-RADIX=DEC表示设置地址和数据的表达式格式都是十进制;地址/数据表以CONTENTBEGIN开始,以END结束;其中的地址/数据表达方式是冒号左边写ROM地址值,冒号右边写对应此地址放置的十进制数据,如24:
9,表示24为地址,9为该地址中的数据。
这样每读到一个地址,即可输出其相应的数据。
文件编辑好后,保存时取文件名为“songer.mif”。
定制音符数据的ROM文件
定制的基本步骤如下:
(1) 进入QuartusII,选菜单TOOL->megawizardplug-inmanager,选择“creatanew…”,然后按“next”键,选择LPM-ROM;最后在browse下的栏中