电子琴演奏设计.docx
《电子琴演奏设计.docx》由会员分享,可在线阅读,更多相关《电子琴演奏设计.docx(17页珍藏版)》请在冰豆网上搜索。
![电子琴演奏设计.docx](https://file1.bdocx.com/fileroot1/2023-3/29/4d528530-8346-4ed1-9901-82065e4e0a11/4d528530-8346-4ed1-9901-82065e4e0a111.gif)
电子琴演奏设计
设计报告
电子琴演奏电路
摘要:
本课程设计主要采用EDA技术,基于VHDL语言设计一个简易的八音符电子琴,并且可以选择通过按键输入或者自动演奏来奏出存入的乐曲。
课程设计中,程序运行平台为QuartusⅡ。
根据音符的分频预置数来弹奏出不同的音符,将演奏出的《小红帽》既而再通过各个子模块,编程,仿真,达到最终的验证。
关键字:
EDA;VHDL;电子琴;音符;频率
一、设计目的
在本课程中,将要运用本学期所学的VHDL语言设计一个简易的电子琴来演奏音乐,设计的主要目的有以下两点:
1、通过课程设计,加深理解,能够更深地掌握这门课所学的知识,以及掌握和运用QuartusⅡ软件,以便在以后的生活学习中能够得心应手进行其他的设计。
2、通过编程,波形仿真,以培养开动脑筋,自主能动性以及学会思考问题,学会动手的能力,通过理论与实践的结合学会在以后的生活中可以自如地将所学习的知识运用到实际。
二、设计整体思路及原理
(一)设计思路
本课程设计主要是基于VHDL文本输入法设计乐曲演奏电路,,在课本《EDA技术》的P251页中,有一个“乐曲硬件演奏”的实验,该实验中用到三个子模块,而我所设计的“简易八音符电子琴演奏电路”与次实验很相似,也要涉及到类似的三个子模块,但是,相比之下,我所设计的电路新增加一个功能,即“电子琴可以自动播放音乐,在演奏乐曲中,通过AUTO子模块既可以用手动弹奏键盘输入音乐,也可以选择自动演奏”。
由前面所述可知,一首乐曲的节拍频率很重要,因此在编程时应当要考虑到每一个音符所占的时钟节拍。
课本中采用的是优美动听的中国古典音乐《梁祝》这首曲子,我决定在程序中填入《小红帽》这首琅琅上口的儿歌,它的节奏感比较鲜明,曲长较短,每个音符几乎都涉及到,并且简单易懂。
由乐理知识可知,《小红帽》是一首2/4拍的歌曲,即:
“以四分音符为一拍,每小节两拍”。
图二是选自《小红帽》歌曲中前八小节的简谱:
《小红帽》
2/4节拍
图二
以上是整个歌曲的部分简谱,从中可以看出,每一小节的是两拍,如果令一个时钟周期CLK为一拍,那么可知在第一小节中,音符1和2个占1/2拍,3和4也是同理。
若定义一个时钟周期是1S,那么1、2、3、4各时占0.5S。
根据歌曲的节拍频率,可知音符的持续时间需要根据乐曲的速度计每个音符的拍数来确定,所以需要给每一个音符设定分频预置数,由课本中可知,每一个音符都有固定分频预置数,在本首歌曲中,出现的音符一共有1,2,3,4,5,6,8(8为简谱中的高音do),查表可得,他们的分频预置数分别为:
音符
分频预置数
1
773
2
912
3
1036
4
1116
5
1197
6
1290
8
1410
图三
根据上表中所示的预置分频数,就可以区分不出不同的音符,既而可以在键盘上输入自己想要的音乐。
(二)设计原理
经过分析之后,可知课程设计所需要三个子模块,它们分别是:
●乐曲自动演奏模块
●发音模块
●分频模块
1、乐曲自动演奏模块
代码实体:
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYAUTOIS
PORT(CLK:
INSTD_LOGIC;--系统时钟信号
AUTO:
INSTD_LOGIC;--键盘输入/自动演奏
CLK2:
BUFFERSTD_LOGIC;--时钟输出
INDEX2:
INSTD_LOGIC_VECTOR(3DOWNTO0);--键盘输入信号
INDEX0:
OUTSTD_LOGIC_VECTOR(3DOWNTO0));--音符信号输出
ENDAUTO;
此模块主要用来产生想要演奏的音乐,而在程序中,软件不能够辨认出简谱,而是信号,因为基本的音符是8个,因此,对于输入的每一个音符,都设置成4位发生控制输入信号。
将他们输入,电脑便根据4位2进制的值来确定相对应的音符,还有一点应当注意:
此模块输入音乐有两种方式,可以同步演奏也可以自动演奏,这需要有AUTO(0或1)的值来确认,总之,AUTO的主要目的是将二进制信号转化为能够发声的音乐。
由程序可知,AUTO为低电平有效,当AUTO为“1”时,此时为手动输入音乐演奏,当AUTO为“0”时,为自动输入演奏,当确定了时钟信号输出的值后,在第二个PROCESS中就可以由它控制4位发声控制输入信号了。
即CLK2的值为0时,COUNT0为1。
最后的COM1便是由前两个PROCESS所确定的COUNT0、AUTO和键盘输入信号值INDEX2将4位的二进制数转化为音符信号的输出,达到自动演奏的目的。
2、发音模块
代码实体:
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYTONEIS
PORT(INDEX:
INSTD_LOGIC_VECTOR(3DOWNTO0);--音符输入信号
CODE:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);--音符显示信号
HIGH:
OUTSTD_LOGIC;--高低音显示信号
TONE0:
OUTINTEGERRANGE0TO2047);--音符的分频系数
ENDTONE;
此模块主要是产生音符的分频预置数,根据不同的音符产生不同的分频预置数,分频预置值控制数控分频模块进行分频,由此得到每个音符对应的频率。
该模块的输入信号INDEX是为上一个模块的输出INDEX0,且高低音显示信号HIGH和音符分频系数都是根据音符输入确定的。
比如INDEX为1是,表示弹奏了一个do,它的分频系数则为773Hz,音符显示信号为1001111,是773的二进制表示,此时高低音显示0表示低音。
INDEX为输入的音乐,CODE显示分频预置数,当HIGH为“1”时,表示高了8度,为“0”时,表示低音。
3、分频模块
代码实体:
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYFENPINIS
PORT(CLK1:
INSTD_LOGIC;--系统时钟信号
TONE1:
ININTEGERRANGE0TO2047;--音符分频系数
SPKS:
OUTSTD_LOGIC);--驱动扬声器音频信号
ENDENTITYFENPIN;
此模块主要是对时基脉冲进行分频,得到与0、1、2、3、4、5、6、8八个音符相对应的频率。
首先根据时钟信号输入得到时基脉冲及计数器的值,然后将时基脉冲值转化为音符的频率。
注意最后一个PROCESS则是用来设置扬声器输出信号的,扬声器信号由0和1控制,当且仅当前一个PROCESS中的FULLSPKS输出为1时,扬声器才有输出,再根据计数器取值来确定输出是1还是0
三个子模块的总体流程如下:
顶层电路的图形:
代码实体:
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYDIANZIQINIS
PORT(CLK12MHZ:
INSTD_LOGIC;--系统时钟信号
CLK8HZ:
INSTD_LOGIC;--系统时钟信号
HANDTOAUTO:
INSTD_LOGIC;--键盘输入/自动演奏信号
CODE1:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);--音符显示信号
INDEX1:
INSTD_LOGIC_VECTOR(3DOWNTO0);--键盘输入信号
HIGH1:
OUTSTD_LOGIC;--高低音节信号
SPKOUT:
OUTSTD_LOGIC);--音频信号
该顶层模块是整个设计的核心,并且是VHDL程序的主程序,通过调用子程序最终实现乐曲演奏的目的,奏出《小红帽》。
利用VHDL语言COMPONENT将三个模块组合起来,其中3个模块和DIANZIQIN模块的输入输出是一一对应的,比如AUTO对应HANDTOAUTO,TONE0对应TONE2,SPKS对应SPKOUT。
可知总体电路图为:
三、仿真波形图
(一)乐曲自动演奏模块的波形图:
可知它分为了两种情况,我们分别用两个波形图来解释说明:
1、当为自动演奏音乐时的波形如下:
说明:
可知此时,INDEX0以及计数器COUNT0和COUNT都和时钟输入CLK2有关,而此时,INDEX0和INDEX2无需时序一致,因为在自动演奏的情况下,是先将音乐输入,然后通过播放来自动演奏,AUTO始终为高电平,而CLK只是一个系统时钟,控制着输入端口INDEX2的节拍。
歌曲弹奏如下:
123455318864553
2、当为手动按键输入的方式时,波形如下:
说明:
由图可知,此时CLK2,COUNT0,COUNT的值都变为0,因为我们要求的是手动弹奏,所以此时自动播放便没有任何意义,输出端口INDEX0只和输入INDEX2有关系,并且两者时序是一致的,在整个过程中,AUTO始终为高电平。
(二)发音模块波形图
说明:
由图可知,INDEX此时为输入端口,TONE0为每一个音符的预置分频数,跟前文的表格式相一致的,CODE是为相应得二进制形式,另外,HIGH表示是否高8度,通过图可知当弹到8即高音do时,HIGH变为高电平,表示此时高8度,而其他时候都低音。
(三)分频模块的波形图:
说明:
由图可知,音乐由时基脉冲值转化为音符的频率,TONE1为音符的预置分频数。
当COUNT11加1时,扬声器SPKS变为1。
(四)顶层文件波形图:
说明:
由图可知此时的ANDTIAUTO也是控制自动演奏的,CLK为系统时钟,同理,INDEX1为所输入的音符,而CODE1直接描述出分频的过程,显示和INDEX1一致,HIGH1控制高低音。
四、引脚锁定
硬件仿真时,我采用的是电路模式5,各引脚的锁定如下表所示:
五、硬件仿真
1、仿真时,选择电路模式5,各引脚锁定如上所示,用短路帽选中Clock0、
Clock2、蜂鸣器SPKER,Clock0接入12MHZ的系统时钟,Clock2接入8HZ的系统时钟,KEY2接模式选择开关HANDAUTO,KEY4,KEY5,KEY6,KEY7,作为四个手弹奏的按键,HIGH1接D1,用来显示高音节。
CODE[0..3]接数码管8,用来显示此时的音符。
2、实验结果:
连接好EDA实验箱,把设计内容下载到实验箱上的芯片上。
(1)、不按下KEY2,此时HANDAUTO=0,可以听到《小红帽》演奏起来,同时数码管8显示对应的音符,D1在数码管显示8时亮,其余不亮。
(2)、按下KEY2,此时HANDAUTO=1,我们手弹奏KEY4---KEY7,我们按《小红帽》简谱弹奏,可听到小红帽这首动听的音乐。
同时数码管8显示对应的音符,D1在数码管显示8时亮,其余不亮。
六、总结
开始按照查到的资料上做,数控分频器模块FEPIN的输入时钟和自动演奏模块AUTO的时钟均为32MHZ。
音乐播放度太快,此时听不到正常的音乐播放,而且在原资料上只给了一个时钟输入,乐曲的自动演奏和手动演奏无法正常转换,硬件仿真时也验证了我的推论,所以在自己的设计中,我选用了两个时钟,CLK12MHZ和CLK8HZ,CLK12MHZ用于数控分频输入,CLK8HZ用于AUTO模块的时钟输入,由于我们EDA实验箱上的数码管已经接好了译码器,只有4个外接引脚,我把资料里的7位二进制数改为4位二进制数,同时把编码改好,使数码能够在实验箱上正常的显示。
即把CODE[6..0]修改为CODE[3..0]。
在仿真的过程中开始不知道到怎么给时钟信号,老是出不来,后来看资料问同学,知道了AUTO模块的作用有两个,要分开加信号,所以才有两个不同的仿真结果。
在硬件调试的过程中开始因为只有一个时钟信号,只能手动演奏不能自动演奏而且过程中还有噪音,后来改为两个时钟信号,结果就正确了。
通过实验我体会到能力的重要性,按照别人给好的东西做起来都如此费劲,我明白了不管做什么在做之前一定要好好预习,弄懂它的原理,就像这次实验,开始什么都不懂,照着给的瞎做,出现了很多问题,其次上课要好好听课,弄懂老师说的,在实践中提升自己的能力。
九、参考文献:
[1]潘松,黄继业.《EDA技术实用教程》.北京:
科学出版社,2002
[2]甘历.VHDL应用于开发实践.北京:
科学出版社,2003
[3]齐洪喜,陆颖.VHDL电路设计实用教程.北京:
清华大学出版社,2004
十、附录
此处为自动演奏模块的详细代码;
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYAUTOIS
PORT(CLK:
INSTD_LOGIC;--系统时钟信号
AUTO:
INSTD_LOGIC;--键盘输入/自动演奏
CLK2:
BUFFERSTD_LOGIC;--时钟输出
INDEX2:
INSTD_LOGIC_VECTOR(3DOWNTO0);--键盘输入信号
INDEX0:
OUTSTD_LOGIC_VECTOR(3DOWNTO0));--音符信号输出
ENDAUTO;
ARCHITECTUREBEHAVIORALOFAUTOIS
SIGNALCOUNT0:
INTEGERRANGE0TO47;--定义信号计数器,有47个信号元素
BEGIN
PULSE0:
PROCESS(CLK,AUTO)--PULSE0工作进程开始
VARIABLECOUNT:
INTEGERRANGE0TO8;--定义变量计数器从0到8
BEGIN
IFAUTO='1'THEN--键盘输入为1
COUNT:
=0;CLK2<='0';--计数器值为0,时钟信号2幅值为0
ELSIF(CLK'EVENTANDCLK='1')THEN--输入的时钟信号为其他值
COUNT:
=COUNT+1;--计数器加1即为1
IFCOUNT=1THEN
CLK2<='1';
ELSIFCOUNT=2THEN
CLK2<='0';COUNT:
=0;
ENDIF;
ENDIF;
ENDPROCESS;
MUSIC:
PROCESS(CLK2)--MUSIC工作进程开始
BEGIN
IF(CLK2'EVENTANDCLK2='1')THEN--时钟信号2为1
IF(COUNT0=47)THEN--计数器值为47
COUNT0<=0;--计数器清0
ELSE
COUNT0<=COUNT0+1;
ENDIF;
ENDIF;
ENDPROCESS;
COM1:
PROCESS(COUNT0,AUTO,INDEX2)
BEGIN
IFAUTO='0'THEN--键盘输入为0
CASECOUNT0IS--由计数器从0到47的取值判断音符信号的8位二进制数
WHEN0=>INDEX0<="0001";--1
WHEN1=>INDEX0<="0010";--2
WHEN2=>INDEX0<="0011";--3
WHEN3=>INDEX0<="0100";--4
WHEN4=>INDEX0<="0101";--5
WHEN5=>INDEX0<="0101";--5
WHEN6=>INDEX0<="0011";--3
WHEN7=>INDEX0<="0001";--1
WHEN8=>INDEX0<="1000";--8
WHEN9=>INDEX0<="1000";--8
WHEN10=>INDEX0<="0110";--6
WHEN11=>INDEX0<="0100";--4
WHEN12=>INDEX0<="0101";--5
WHEN13=>INDEX0<="0101";--5
WHEN14=>INDEX0<="0011";--3
WHEN15=>INDEX0<="0011";--3
WHEN16=>INDEX0<="0001";--1
WHEN17=>INDEX0<="0010";--2
WHEN18=>INDEX0<="0011";--3
WHEN19=>INDEX0<="0100";--4
WHEN20=>INDEX0<="0101";--5
WHEN21=>INDEX0<="0011";--3
WHEN22=>INDEX0<="0010";--2
WHEN23=>INDEX0<="0001";--1
WHEN24=>INDEX0<="0010";--2
WHEN25=>INDEX0<="0010";--2
WHEN26=>INDEX0<="0011";--3
WHEN27=>INDEX0<="0011";--3
WHEN28=>INDEX0<="0010";--2
WHEN29=>INDEX0<="0010";--2
WHEN30=>INDEX0<="0101";--5
WHEN31=>INDEX0<="0101";--5
WHEN32=>INDEX0<="0001";--1
WHEN33=>INDEX0<="0010";--2
WHEN34=>INDEX0<="0011";--3
WHEN35=>INDEX0<="0100";--4
WHEN36=>INDEX0<="0101";--5
WHEN37=>INDEX0<="0101";--5
WHEN38=>INDEX0<="0011";--3
WHEN39=>INDEX0<="0001";--1
WHEN40=>INDEX0<="1000";--8
WHEN41=>INDEX0<="1000";--8
WHEN42=>INDEX0<="0110";--6
WHEN43=>INDEX0<="0100";--4
WHEN44=>INDEX0<="0101";--5
WHEN45=>INDEX0<="0101";--5
WHEN46=>INDEX0<="0011";--3
WHEN47=>INDEX0<="0011";--3
WHENOTHERS=>NULL;
ENDCASE;
ELSEINDEX0<=INDEX2;--将音符信号0的值赋给音符信号2
ENDIF;
ENDPROCESS;
ENDBEHAVIORAL;
附录2
-----------------此处为发音模块的详细代码;
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYTONEIS
PORT(INDEX:
INSTD_LOGIC_VECTOR(3DOWNTO0);--音符输入信号
CODE:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);--音符显示信号
HIGH:
OUTSTD_LOGIC;--高低音显示信号
TONE0:
OUTINTEGERRANGE0TO2047);--音符的分频系数
ENDTONE;
ARCHITECTUREARTOFTONEIS
BEGIN
SEARCH:
PROCESS(INDEX)
BEGIN
CASEINDEXIS--译码电路,查表方式,控制音调的预置数
WHEN"0001"=>TONE0<=773;CODE<="0001";HIGH<='0';
WHEN"0010"=>TONE0<=912;CODE<="0010";HIGH<='0';
WHEN"0011"=>TONE0<=1036;CODE<="0011";HIGH<='0';
WHEN"0100"=>TONE0<=1116;CODE<="0100";HIGH<='0';
WHEN"0101"=>TONE0<=1197;CODE<="0101";HIGH<='0';
WHEN"0110"=>TONE0<=1290;CODE<="0110";HIGH<='0';
WHEN"0111"=>TONE0<=1372;CODE<="0111";HIGH<='0';
WHEN"1000"=>TONE0<=1410;CODE<="1000";HIGH<='1';
WHENOTHERS=>TONE0<=2047;CODE<="0000";HIGH<='0';
ENDCASE;
ENDPROCESS;
ENDART;
附录3
-----------------此处为分频模块的详细代码;
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYFENPINIS
PORT(CLK1:
INSTD_LOGIC;--系统时钟信号
TONE1:
ININTEGERRANGE0TO2047;--音符分频系数
SPKS:
OUTSTD_LOGIC);--驱动扬声器音频信号
ENDENTITYFENPIN;
ARCHITECTUREARTOFFENPINIS
SIGNALPRECLK:
STD_LOGIC;--定义时基脉冲信号
SIGNALFULLSPKS:
STD_LOGIC;
BEGIN
PROCESS(CLK1)
VARIABLECOUNT:
INTEGERRANGE0TO8;
BEGIN
IF(CLK1'EVENTANDCLK1='1')THEN--时钟信号为1
COUNT:
=COUNT+1;--计数器取值为1
IFCOUNT=2THEN
PRECLK<='1';
ELSIFCOUNT=4THEN--计数器为4
PRECLK<='0';COUNT:
=0;--时基脉冲为0,计数器清0
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(PRECLK,TONE1)
VAR