xxxx211122班李济汉1021073720号简易电子琴演奏器doc.docx
《xxxx211122班李济汉1021073720号简易电子琴演奏器doc.docx》由会员分享,可在线阅读,更多相关《xxxx211122班李济汉1021073720号简易电子琴演奏器doc.docx(32页珍藏版)》请在冰豆网上搜索。
xxxx211122班李济汉1021073720号简易电子琴演奏器doc
2012年数字电路与逻辑设计实验报告
题目:
简易电子琴演奏器
学院:
信息与通信工程学院
班级:
2010211122
******
学号:
********
班内序号:
20
指导教师:
袁东明老师
一、实验任务要求
1、基本要求:
用8×8点阵显示“1234567”七个音符构成的电子琴键盘。
其中点阵的第一列用一个LED点亮表示音符“1”,第二列用二个LED点亮表示音符“2”,依此类推。
用BTN1~BTN7七个按键模拟电子琴手动演奏时的“1234567”七个音符。
当某个按键按下时,数码管显示相应的音符,点阵上与之对应的音符显示列全灭,同时蜂鸣器演奏相应的声音;当按键弹开时数码管显示的音符灭掉,点阵显示恢复,蜂鸣器停止声音的输出。
下图所示为按下BTN3按键时点阵的显示情况。
由拨码开关切换选择高、中、低音,并用数码管进行相应的显示。
通过按键BTN0进行复位,控制点阵显示初始状态。
2、提高要求:
可通过一个拨码开关进行手动/自动演奏的切换,并与点阵显示配合增加自动演奏乐曲的功能。
增加手动演奏的音符存储、播放功能。
3、创新功能:
实现了升降音。
实现了多首歌曲的播放选择与切换。
实现了歌曲暂停以及录音清空。
二、功能说明
本实验利用开发板模拟电子琴演奏,总体上实现了通过按键弹奏电子琴,发音并输出音符与键盘的状态,另一方面实现了自动选择播放歌曲、暂停、复位、录音与录音播放的新功能。
①发音:
利用开发板的扬声器模块进行输出,在手动弹奏、自动播放、录音播放等状态下发出不同音调的音符以及不同的歌曲。
②音符显示:
利用开发板的数码管模块进行输出,在不同按键情况下输出该按键对应的音调值,如弹奏高音1时,输出“H1”。
③键盘显示:
利用开发板的点阵模块进行输出,在不同按键情况下将该按键对应的点阵列不显示,以此模仿琴键的按下,当按键抬起时,键盘又恢复原状。
④自动播放:
利用编程逻辑综合协调以上三个模块,首先通过按键选择歌曲(本实验存储了3首原创歌曲),然后播放相应的歌曲,并显示音符与键盘状态。
当暂停开关被置位时,歌曲播放暂停,当此开关恢复原位时,从暂停点继续播放歌曲。
当在播放歌曲时按下复位键,歌曲停止播放,等待重新选择歌曲。
⑤录音:
当录音开关打开时,使表示处于录音状态的LED灯点亮,同时记录此段时间内按键的状态变化,将这些状态变化转化为数组里的值进行存储。
⑥录音播放:
当录音播放开关打开时,使表示处于录音播放状态的LED灯点亮,同时输出记录在录音数组里的音符值,利用扬声器、数码管与点阵进行综合输出。
三、系统设计
1、设计思路
本系统分为四大模块:
主调用模块、状态切换模块、输出控制模块(控制音阶音调以及显示)、输出模块(发音)。
模块设计逐层深入,主调用模块为接口层,负责综合各个分模块component,使得分模块间以及分模块与外部输入输出间建立联系。
状态切换模块为核心控制层,它是最为重要的一层,通过从接口层获得不同信号,控制着状态机不同状态的切换。
此处设置了五个状态:
手动播放状态、自动播放状态、录音状态、录音播放状态、复位状态。
输出控制模块为辅助控制层,它主要实现了输出的同步,通过接收状态机的状态信息,进而将信号统一传送至输出接口,使得点阵、数码管显示以及不同音调的分频发音同时进行。
输出模块为单独提取出来的发音模块,由于本实验中每个模块都需要发音的实现,因此将其单独作为一个模块,便于输出控制层对其的控制。
在此,输出控制层只需将已配置好的音调信号传送给发音模块,便可实现不同音调的发声。
因此,发音模块的内部实现了分频以及输出防抖。
整体思路以状态转移为基础,在不同状态下传给输出控制不同信号,进而产生不同输出。
模块之间存在松耦合,即可以下一层的功能调用需要上一层的信号输入,但具体逻辑实现上并不会相互影响。
2、系统总体框图
(1)系统结构框图
(2)模块划分图
(3)模块之间信息传递关系
(4)ASM图
(5)MDS图
3、分模块设计(具体代码见“源程序”)
--文件名:
music.vhd
--功能:
主调用模块
在主调用模块中,我将分模块以component的形式进行声明,并利用portmap地址映射将相关联的接口参数映射在一起。
--文件名:
statechange.vhd
--功能:
状态切换模块
此模块用于各个状态的切换与逻辑实现。
首先针对不同状态的转移条件进行了设置,即在当何种事件触发时,状态发生转移。
其次,由于自动播放、录音、录音播放状态都需要使用计数器,因此通过时钟进行不同分频来计数(clktmp1控制自动播放、clktmp2控制录音、clktmp3控制录音播放),使得三种状态都能够正常输出。
接下来,根据不同状态下各自的逻辑需要,进行如下设计:
①手动状态:
此状态下直接将按键输入信号传递给输出控制模块的按键检测信号(虚按键),输出模块即根据不同按键输入进行不同输出;
②自动状态:
首先要检测此时是否有复位信号或暂停信号发出,若复位则应使由clktmp1控制的计数器count1归零,若暂停则需要将暂停点所处的歌曲及音符位置量count1传递给暂存变量,直至检测到暂停结束,再释放暂存信号,从而继续从暂停点开始播放。
接下来,根据按键不同给歌曲选择信号song赋以不同的值,并开始计数,每种case下都按count1的计数顺序给按键检测信号赋予相应的音调值,从而产生不同音乐。
扬声器的连音可由相同音调的连续输出来实现,这样直接由clktmp1便可以进行不同音长的控制;
③录音状态:
首先定义数组类型作为存储录音音调的信号,在录音时只需根据时钟clktmp2的计数count2使数组下标递增,并向数组元素赋由按键输入信号编码而成的整型数值,这样做使得数组空间占用的逻辑单元减小,提高存储效率。
当无按键输入时,相应数组元素赋值为0,即无发音需要;
④录音播放状态:
根据时钟clktmp3控制的计数器count3的递增读出录音数组里的音乐,首先将录音数组里存储的整数解码为音调信号,再输出给按键检测信号,使输出模块根据检测到所存储的按键输入信号进行不同的输出;
⑤复位状态:
复位状态利用循环清空录音数组,并将有关信号均归零。
--文件名:
tone.vhd
--功能:
输出控制模块
此模块用于控制输出,将状态切换模块传送的按键检测信号转化为具体的输出行为。
首先,由于数码管与点阵是通过扫描进行输出的,因此要进行分别分频,利用视觉暂留效应实现音阶音调与键盘的显示。
其中,按键检测信号(虚按键)并不是按键输入信号的真实反映,因为在自动播放与录音播放状态下,并没有真实的按键输入,但是依然需要发音,因此,基于虚按键的输出控制才是有效的,而在手动与录音状态只需将真实按键输入赋予按键检测信号即可。
具体输出行为分为以下三种:
①音调频率:
通过查资料可得不同音调的不同频率值,根据计算所得给分频基准值信号freq_tone赋值,传递给输出模块,使其针对每一种音调进行不同的分频,从而发出不同的音调,同时要在检测到按键时使监测信号call_tone置1,使得在输出模块中输出同时与时钟信号、按键信号同步;
②数码管显示:
数码管用于输出音阶音调,当检测到按键信号为高音1(即“111000000”,前两位代表音阶,后七位代表音调)时,便按照分频进行扫描数字显示(输出“H1”),每次计数变化显示数字,并只选通当前位置的数码管即可;
③点阵显示:
点阵用于显示模拟键盘,当检测到按键信号为3(即后七位为“0010000”)时,便按照分频进行按行扫描点阵显示(列赋1、行赋0为点亮,仅在第三列不输出)即可,程序里要穷举所有可能输出的情况。
--文件名:
speaker.vhd
--功能:
输出模块
输出模块用于音乐的输出,仅仅对扬声器进行控制。
不同音调通过输出控制模块传入的不同的分频基值来确定其真实分频。
根据资料,每个音调的频率如下表所示:
音阶
Do
Re
Me
Fa
So
La
Si
高音(Hz)
1046
1175
1318
1397
1568
1760
1976
中音(Hz)
523
587
659
698
784
880
988
低音(Hz)
262
294
330
349
392
440
494
音阶
Do#
Re#
Me#
Fa#
So#
La#
Si#
中音
554
622
678
740
831
932
1017
由于分频后对于每个音调的频率都需满足上值,而分频器是由计数原理进行实现的,因此要将频率与计数之间的关系进行推导,得到如下公式,可求出各个音调的分频基准值:
(其中
为分频基准值)
首先我先统一对所有音调进行12分频,即将50MHz的频率化归到4MHz左右,然后再除以每个音调传入的分频基准值freq_speaker(由输出控制模块传入),便可得到相应的音调频率。
例如高音1的实际频率为1045.59Hz(约为1046Hz),那么我的分频基值便设置为3985,这样便可得到一秒输出1045.59个周期的信号,将其赋给扬声器接口即可,输出时还要监测call_speaker是否为1,这样便保证了时钟与按键信号对于输出的同步控制。
由于发音的时长是依据按键时间以及播放歌曲的连续相同的音调进行实现的,因此不存在单独控制时钟进行音长变量计数的问题。
例如,要播放3拍的高音1,则只需按照自动播放固定的计数时长连续计三次1即可。
这种设计的优点在于不用为音长这一变量进行单独计数,但也存在缺点:
即不能根据需要发出任意长短的音符以及断音。
这也是需要改进的地方。
四、仿真波形及波形分析
--文件名:
music.vhd
--功能:
主调用模块
波形分析:
上图前半部分mainswitch信号为1代表切换到自动状态,后半部分mainswitch信号为0代表切换到手动状态。
在自动状态下,可以看出mainfigure、maincats、mainrow、maincol、mainout都将自动按歌曲音乐改变输出。
在手动状态下,mainfigure、maincats、mainrow、maincol、mainout则根据mainbutton按键的键值改变输出。
mainfigure一开始在“U”与“1”之间来回切换,表示发出的音是中音1,同时maincats也在后两个数码管之间往复选通,使得两个数码管分别输出“U”与“1”。
mainrow与maincol通过扫描产生不同状态的点阵,“1”的时候第一列不显示。
mainout针对播放的音符和手动按键发出相应的音调,发音间隔基于不同的音调情况。
--文件名:
statechange.vhd
--功能:
状态切换模块
波形分析:
上图演示的是手动、录音与录音播放三种状态的波形(自动播放见上一张图)。
当reco_statechange为1时,处于录音状态,按键(buttonin)输入一些音符,发音(buttonout)便输出相应音符,录完音后当splay_statechange置为1时,处于录音播放状态,此时发音(buttonout)便输出上一次输入的音符,当清零信号clear_statechange置1后,发音数组清零,再将splay_statechange置1,则不再输出音符。
当处于录音状态时,led1_statechange变为1,表示led灯1发亮,同理当处于录音播放状态时,led灯2发亮。
手动状态直接根据按键(buttonin)输入的音符发出(buttonout)相应的音符。
--文件名:
tone.vhd
--功能:
输出控制模块
波形分析:
上图通过设置不同的按键button_tone输入进行各种输出信号的对应输出。
当按键输入高音2时,figure_tone在“H”与“2”之间切换扫描,cats_tone则在后两个数码管之间往复选通。
同时row_tone与col_tone均按规定(第2列不输出)进行扫描输出。
call_tone是检测按键输入信号,若有按键button_tone输入则为输出1。
--文件名:
speaker.vhd
--功能:
输出模块
波形分析:
上图中检测到按键信号call_speaker为1时,便使得out_speaker发音,若没有call_speaker信号,则不发音。
五、源程序
--文件名:
music.vhd
--功能:
主调用模块
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
entitymusicis
Port(mainclk:
instd_logic;--50MHz系统时钟
mainswitch:
instd_logic;--手动自动演奏切换
mainrst:
instd_logic;--复位信号
mainreco:
instd_logic;--录音信号
mainsplay:
instd_logic;--播放信号
mainpause:
instd_logic;--暂停信号
mainclear:
instd_logic;--清零信号
mainfigure:
outstd_logic_vector(6downto0);--音符显示信号
maincats:
outstd_logic_vector(5downto0);--数码管接地信号
mainrow:
outstd_logic_vector(7downto0);--点阵行输出
maincol:
outstd_logic_vector(7downto0);--点阵列输出
mainbutton:
instd_logic_vector(8downto0);--键盘输入信号
mainled1:
outstd_logic;--录音标志信号
mainled2:
outstd_logic;--播放标志信号
mainout:
outstd_logic);--扬声器发音信号
endmusic;
architecturepiano1ofmusicis
componentstatechangeis--状态切换模块
Port(clk_statechange:
instd_logic;
switch_statechange:
instd_logic;
reco_statechange:
instd_logic;
rst_statechange:
instd_logic;
splay_statechange:
instd_logic;
pause_statechange:
instd_logic;
clear_statechange:
instd_logic;
buttonin_statechange:
instd_logic_vector(8downto0);
buttonout_statechange:
outstd_logic_vector(8downto0);
led1_statechange:
outstd_logic;
led2_statechange:
outstd_logic);
endcomponent;
componenttone--输出控制模块
Port(clk_tone:
instd_logic;
button_tone:
instd_logic_vector(8downto0);
figure_tone:
outstd_logic_vector(6downto0);
cats_tone:
outstd_logic_vector(5downto0);
row_tone:
outstd_logic_vector(7downto0);
col_tone:
outstd_logic_vector(7downto0);
call_tone:
outstd_logic;
freq_tone:
outintegerrange0to50000000);
endcomponent;
componentspeaker--输出模块
Port(clk_speaker:
instd_logic;
freq_speaker:
inintegerrange0to50000000;
call_speaker:
instd_logic;
out_speaker:
outstd_logic);
endcomponent;
signalmainfreq:
integerrange0to50000000;
signalbutton:
std_logic_vector(8downto0);
signalmaincall:
std_logic;
begin--各模块与主调用模块的映射
u1:
statechangeportmap(clk_statechange=>mainclk,switch_statechange=>mainswitch,reco_statechange=>mainreco,rst_statechange=>mainrst,splay_statechange=>mainsplay,pause_statechange=>mainpause,clear_statechange=>mainclear,buttonin_statechange=>mainbutton,buttonout_statechange=>button,led1_statechange=>mainled1,led2_statechange=>mainled2);
u2:
toneportmap(clk_tone=>mainclk,button_tone=>button,freq_tone=>mainfreq,figure_tone=>mainfigure,cats_tone=>maincats,row_tone=>mainrow,col_tone=>maincol,call_tone=>maincall);
u3:
speakerportmap(clk_speaker=>mainclk,freq_speaker=>mainfreq,out_speaker=>mainout,call_speaker=>maincall);
endpiano1;
--文件名:
statechange.vhd
--功能:
状态切换模块
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
entitystatechangeis
Port(clk_statechange:
instd_logic;--50MHz系统时钟
switch_statechange:
instd_logic;--手动自动演奏切换
reco_statechange:
instd_logic;--录音信号
rst_statechange:
instd_logic;--复位信号
splay_statechange:
instd_logic;--播放信号
pause_statechange:
instd_logic;--暂停信号
clear_statechange:
instd_logic;--清零信号
buttonin_statechange:
instd_logic_vector(8downto0);--键盘输入信号
buttonout_statechange:
outstd_logic_vector(8downto0);--音符输入信号
led1_statechange:
outstd_logic;--录音标志信号
led2_statechange:
outstd_logic);--播放标志信号
endstatechange;
architecturepiano2ofstatechangeis
typewordisarray(1to50)ofintegerrange0to28;
signalstate:
integerrange0to5;--状态信息
signalclktmp1:
std_logic;--控制自动歌曲播放
signalclktmp2:
std_logic;--控制录音
signalclktmp3:
std_logic;--控制录音播放
signalsong:
integerrange0to3;--歌曲选择
signalsongtemp:
integerrange0to3;--记录暂停歌曲
signalsound:
word;--录音数组
signalreco:
std_logic;--录音控制标志
signalplay:
std_logic;--播放录音控制标志
signalcount1:
integerrange0to95;--歌曲音符递增计数
signalcount2:
integerrange1to50;--录音数组下标递增计数
signalcount3:
integerrange1to50;--录音播放数组下标递增计数
signalcountemp:
integerrange0to95;--记录暂停位置
begin
select_state:
process(switch_autoplay,reco_autoplay,splay_autoplay,clear_autoplay)
begin
ifswitch_autoplay='0'andreco_autoplay='0'andsplay_autoplay='0'andclear_autoplay='0‘then
state<=1;--手动播放状态
elsifswitch_autoplay='1'andreco_autoplay='0'andsplay_autoplay='0'andclear_autoplay='0'then
state<=2;--自动播放状态
elsifswitch_autoplay='0'andreco_autoplay='1'andsplay_autoplay='0'andclear_autoplay='0'then
state<=3;--录音状态
elsifswitch_autoplay='0'andreco_autoplay='0'andsplay_autoplay='1'andclear_autoplay='0'then
state<=4;--录音播放状态
elsifsw