简易音乐播放器数电实验.docx
《简易音乐播放器数电实验.docx》由会员分享,可在线阅读,更多相关《简易音乐播放器数电实验.docx(31页珍藏版)》请在冰豆网上搜索。
简易音乐播放器数电实验
数字电路与逻辑设计综合设计实验报告
实验名称:
简易音乐播放器
姓名:
班级:
班
班内序号:
27
一、设计任务要求
设计制作一个简易乐曲播放器。
1)播放器内预存3首乐曲;
2)播放模式:
顺序播放、随机播放,并用数码管或LED显示当前播放模式;
3)顺序播放:
按内部给定的顺序依次播放3首乐曲;
4)随机播放:
随机产生一个顺序播放3首乐曲;
5)用数码管显示当前播放乐曲的顺序号;
6)设置开始/暂停键,乐曲播放过程中按该键则暂停播放,再按则继续播放;
7)设置Next和Previous键,按Next键可以听下一首,按Previous键回到本首开始;
8)选做:
用户可以自行设定播放顺序,设置完成后,播放器按该顺序依次播放乐曲;
9)选做:
自拟其它功能。
二、系统设计
1)设计思路
首先音乐有音高和节拍两个因素。
音高可以通过对时钟信号不同的分频得到不同频率的信号进而发出不同的音,节拍可以定义一个音符计数器,计数器的每一个值对应一个音高。
对播放的控制包括播放/暂停、复位、上一首、下一首、本首重放、顺序播放/随机播放,用一个状态机,共播放和暂停两个状态,另外歌曲的切换以及暂停都是利用音符计数器赋不同的值或保持不变来实现。
音高的显示是通过不同的音符对应不同的点阵row和col的值来实现的。
歌曲号是通过音符计数器的值来得出并送到数码管显示的。
播放、暂停、顺序、随机这些的显示是通过对状态和模式变量的判别进而送到LED显示的。
2)总体框图
3)分块设计
共分为9个模块。
Div1,div2,div3都是用来分频的,分别是将50mhz变为1mhz,将1mhz变为4hz,将1mhz变为2hz。
Rand模块用来产生随机数,用于随机播放模式。
Keycontrol是核心模块,用来实现顺序播放、随机播放、播放/暂停、上一首、下一首、本首重放、复位、显示顺序或随机播放状态、显示播放/暂停态。
Melody模块是将音符计数器的每一个值与一个音高相对应,即记录曲谱。
Index模块是用melody模块传来的音高信号通过查表得到它所对应的音高的分频数,然后将这个分频数送给speaker模块,以发出不同的音,另外对应不同的音它还对点阵进行不同的输出,进而显示出音高。
Speaker模块接收index模块送来的分频数,利用分频数对时钟信号进行分频,进而发出不同的音,另外它还接收keycontrol模块送来的暂停态的标志,以保证在暂停态的时候不发出声音。
Shownumber模块通过对音符计数器值的判断确定现在播放的是哪首歌,进而输出不同的歌曲号。
3、仿真波形及波形分析
1)div1模块
由仿真结果可看出,它将50mhz的时钟信号变换为1mhz。
Div2和div3模块分别是将1mhz变为4hz,将1mhz变为2hz,原理相同,因而不再列出仿真结果。
2)Rand模块
由仿真结果可以看出在每一个时钟周期内,randnumber改变一次,randnumber可作为随机数的产生信号。
3)Keycontrol模块:
(时钟用的是未经分频的)
Ø顺序播放:
可以看出,在mode=0,即顺序播放模式下,在没有按任何键时,音符计数器counter随时钟自动加1从而进入下一个音。
Sequential表示顺序播放,random表示随机播放,由图可见此时sequential为高电平,random为低电平,可知此时为顺序播放状态。
Øcounter由144自动变到145是第一首播完自动到第二首
Ø下一首:
当按一下一首键时,即nextone变为高电平,音符计数器counter由第一首歌的14变到了第二首歌开始音符所对应的数145,实现了切换到下一首的功能。
Ø本首重放:
当播放到第二首歌的152时,按下了本首重放键,即previous变为高电平,这时counter变为第二首歌起始音对应的数145,进而实现了本首重放的功能。
Ø上一首:
当播放到第二首对应counter为151时,按下了上一首键,即lastone变为高电平,counter变为第一首歌起始音符所对应的值1,从而实现了切换到上一首的功能。
Ø暂停:
当按下暂停键后,即pp变为高电平,暂停状态的标志ppsymbol就变为高电平,用于送给LED显示播放/暂停态的ppout变为周期信号,实际中周期为1s,即LED会在1s内一亮一灭进行闪烁,表示进入了暂停状态。
Ø暂停后再按“播放/暂停”键:
在暂停态再按一次播放/暂停键后,即pp再次变为高电平,ppout变为低电平,对应的LED会熄灭表示进入了播放状态,ppsymbol也变为低电平。
Ø暂停后按下一首:
按了暂停键之后,即pp变为高电平之后,又按了下一首键,即nextone变为高电平,这时进入播放状态,同时counter变成了下一首歌的第一个音符对应的值,实现了通过按下一首退出暂停状态,同时进行歌曲的切换。
Ø暂停后按上一首:
暂停后按上一首,即pp变为高电平后lastone也变为高电平,则进入播放状态,并且开始播上一首。
(信号counter中158对应的是第二首的音符,1对应的是第一首的音符)
Ø暂停后按本首重放:
暂停后按本首重放,即pp变为高电平后previous也变为高电平,这时进入播放状态,另外counter变为本首歌第一个音对应的数,实现了本首重放。
Ø复位:
复位所要实现的是不管是在顺序播放还是随机播放状态下,只要一按下复位键,就从第一首歌开始播放。
如图,counter等于272时reset变为高电平,counter变为1。
Ø随机播放:
在随机播放状态,即mode=1时,在第一首歌的最后一个音(counter为144时)时程序会检测随机数randnumber的值,查到是3,于是下一次counter就变为第三首歌第一个音对应的数213,从而实现了随机播放。
此时random为高电平,sequential为低电平,表示此时为随机播放状态。
Ø随机播放状态下按上一首:
按了上一首(lastone变为高电平)后,据随机数randnumber的值3,于是转入播放第三首。
Ø按下一首:
和按上一首是一样的,也是根据当前randnumber值来确定下一首要播的是哪一首。
Randnumber等于1、2、3、4分别对应第一、二、三、四首歌。
Ø按本首重放:
随机播放模式下按本首重放,即previous变为高电平,实现的功能与在顺序播放模式是一样的。
由图可见,播放到第一首的10时,counter变为1,即回到第一首的第一个音开始播。
3)Melody模块:
根据不同的音符计数器counter的值,指示音高的值toneindex也在变化,其中1到7代表中音1到7,8代表高音1,9到13代表低音3到7。
4)Index模块:
由仿真结果可看出,当音高toneindex为不同的值时,分频数tonefreq的值也不同,将它送给speaker模块对时钟进行分频,即可得到不同的音高。
另外不同的toneindex值对应的点阵的row和col的值也不一样,进而可以利用点阵显示音高。
5)Speaker模块:
Ø根据分频数tonefreq的不同,对时钟产生的分频也不同,如图可见为tonefreq在0和2时输出声音信号sound的两种频率,进而会发出不同的音。
Ø如下图,分频数tonefreq的值并没有变,但表暂停的标志ppsymbol变为了高电平,暂停状态不允许发声,因而输出的声音信号sound变为低电平,当ppsymbol回到低电平时,sound才又变回tonefreq所对应频率的信号。
6)Shownumber模块:
Ø第一首:
在音符计数器counter的值是第一首歌时,控制数码管显示歌曲号的段选码number一直是01100000,于是在数码管上显示1。
而位选码则一直保持01111111不变,只让固定的一个数码管来显示。
Ø第二首
Counter现在对应的是第二首歌的音符,number的值为11011010,数码管显示2。
四、主要部分源程序
1)外围模块player
libraryieee;
useieee.std_logic_1164.all;
entityplayeris
Port--整个系统对外的输入输出端口
(
clk50mhz,reset,lastone,previous,nextone,pp,mode:
instd_logic;
sequential,random,ppout,sound:
outstd_logic;
col,row,number:
outstd_logic_vector(7downto0);
enable:
outstd_logic_vector(5downto0)
);
endplayer;
architectureoneofplayeris--子模块定义
componentdiv1
port(
clk50mhz:
instd_logic;
clk1mhz:
outstd_logic
);
endcomponent;
componentdiv2
port(
clk1mhz:
instd_logic;
clk4hz:
outstd_logic
);
endcomponent;
componentdiv3
port(
clk1mhz:
instd_logic;
clk2hz:
outstd_logic
);
endcomponent;
componentrand
port(
clk4hz:
instd_logic;
randnumber:
outintegerrange1to4
);
endcomponent;
componentkeycontrol
port(
lastone,previous,nextone,pp,mode,reset,clk2hz,clk4hz:
instd_logic;
randnumber:
inintegerrange1to4;
sequential,random,ppout,ppsymbol:
outstd_logic;
counter:
outintegerrange1to400
);
endcomponent;
componentmelody
port(
counter:
inintegerrange1to400;
toneindex:
outintegerrange0to13
);
endcomponent;
componentindex
port(
toneindex:
inintegerrange0to13;
tonefreq:
outintegerrange0to1516;
row:
outstd_logic_vector(7downto0);
col:
outstd_logic_vector(7downto0)
);
endcomponent;
componentspeaker
port(
clk1mhz,ppsymbol:
instd_logic;
tonefreq:
inintegerrange0to1516;
sound:
outstd_logic
);
endcomponent;
componentshownumber
port(
counter:
inintegerrange1to400;
enable:
outstd_logic_vector(5downto0);
number:
outstd_logic_vector(7downto0)
);
endcomponent;
signalclk1mhz,clk4hz,clk2hz,ppsymbol:
std_logic;
signalrandnumber:
integerrange1to4;
signalcounter:
integerrange1to400;
signaltoneindex:
integerrange0to13;
signaltonefreq:
integerrange0to1516;
Begin--各模块间端口的连接
u1:
div1portmap(clk50mhz=>clk50mhz,clk1mhz=>clk1mhz);
u2:
div2portmap(clk1mhz=>clk1mhz,clk4hz=>clk4hz);
u3:
div3portmap(clk1mhz=>clk1mhz,clk2hz=>clk2hz);
u4:
randportmap(clk4hz=>clk4hz,randnumber=>randnumber);
u5:
keycontrolportmap(lastone=>lastone,previous=>previous,nextone=>nextone,pp=>pp,mode=>mode,reset=>reset,clk2hz=>clk2hz,clk4hz=>clk4hz,
randnumber=>randnumber,sequential=>sequential,random=>random,ppout=>ppout,ppsymbol=>ppsymbol,counter=>counter);
u6:
melodyportmap(counter=>counter,toneindex=>toneindex);
u7:
indexportmap(toneindex=>toneindex,tonefreq=>tonefreq,row=>row,col=>col);
u8:
speakerportmap(clk1mhz=>clk1mhz,tonefreq=>tonefreq,sound=>sound,ppsymbol=>ppsymbol);
u9:
shownumberportmap(counter=>counter,enable=>enable,number=>number);
endone;
2)分频模块div1(div2、div3与div1类似,不再重复)
这个模块将50mhz时钟分频成1mhz
libraryieee;
useieee.std_logic_1164.all;
entitydiv1is
port(
clk50mhz:
instd_logic;
clk1mhz:
outstd_logic
);
enddiv1;
architectureoneofdiv1is
signalt:
std_logic:
='0';
begin
clk1mhz<=t;
p1:
process(clk50mhz)
variablec:
integerrange0to24;
begin
if(clk50mhz'eventandclk50mhz='1')then
if(c=24)then
c:
=0;
t<=nott;
else
c:
=c+1;
endif;
endif;
endprocessp1;
endone;
3)产生随机数的rand模块:
libraryieee;
useieee.std_logic_1164.all;
entityrandis
port(
clk4hz:
instd_logic;
randnumber:
outintegerrange1to4
);
endrand;
architectureoneofrandis
signaltemp:
std_logic_vector(3downto0);
begin
process(clk4hz,temp)
begin
if(temp="0000")thentemp<="0001";
elsif(clk4hz'eventandclk4hz='1')then--利用M序列发生器产生伪随机序列
temp(0)<=temp(0)xortemp(3);
temp
(1)<=temp(0);
temp
(2)<=temp
(1);
temp(3)<=temp
(2);
endif;
if(temp="0001"ortemp="0111"ortemp="1011"ortemp="0010")then
randnumber<=1;
elsif(temp="0011"ortemp="1100"ortemp="1001"ortemp="1000")then
randnumber<=2;
elsif(temp="1111"ortemp="1101"ortemp="0101"ortemp="0110")then
randnumber<=3;
elsif(temp="1110"ortemp="1010"ortemp="0100")then
randnumber<=4;
endif;
endprocess;
endone;
4)核心模块keycontrol:
libraryieee;
useieee.std_logic_1164.all;
entitykeycontrolis
port(
lastone,previous,nextone,pp,mode,reset,clk2hz,clk4hz:
instd_logic;
randnumber:
inintegerrange1to4;
sequential,random,ppout,ppsymbol:
outstd_logic;
counter:
outintegerrange1to400:
=1
);
endkeycontrol;
architectureoneofkeycontrolis
typestatetypeis(play,pause,nothing);
signalstate:
statetype:
=play;--状态定义,有播放和暂停两种状态
signalcount:
integerrange1to400:
=1;
signalt:
std_logic;
begin
counter<=count;
ppout<=t;
p1:
process(clk4hz)
begin
if(clk4hz'eventandclk4hz='1')then
if(reset='1')then--复位
state<=play;
count<=1;
elsif(pp='1')then--按下播放/暂停键
casestateis
whenpause=>
state<=play;
whenplay=>
state<=pause;
count<=count;
whennothing=>null;
endcase;
else
if(previous='0'andlastone='0'andnextone='0')then
casestateis
whenpause=>count<=count;--什么键也没按,而当前处于暂停态
whenplay=>
if(mode='0')then--为顺序播放模式时
if(count=400)thencount<=1;
elsecount<=count+1;
endif;
Else--为随机播放模式时
if(count=144orcount=212orcount=344orcount=400)then
if(randnumber=1)then--据随机数不同确定下一首歌曲
count<=1;
elsif(randnumber=2)then
count<=145;
elsif(randnumber=3)then
count<=213;
else
count<=345;
endif;
else
count<=count+1;
endif;
endif;
whenothers=>null;
endcase;
Else--当有键按下时
casestateis
whenpause=>--当为暂停态时
if(lastone='0'andprevious='1'andnextone='0')then--按下了本首重放键
state<=play;
if(count>=1andcount<=144)then
count<=1;
elsif(count>=145andcount<=212)then
count<=145;
elsif(count>=213andcount<=344)then
count<=213;
else
count<=345;
endif;
else
if(mode='0')then--顺序播放模式
if(lastone='1'andprevious='0'andnextone='0')then--上一首
state<=play;
if(count>=1andcount<=144)then
count<=345;
elsif(count>=145andcount<=212)then
count<=1;
elsif(count>=213andcount<=344)then
count<=145;
else
count<=213;
endif;
elsif(lastone='0'andprevious='0'andnextone='1')then--下一首
state<=play;
if(count>=1andcount<=144)then
count<=145;
elsif(count>=145andcount<=212)then
count<=213;
elsif(count>=213andcount<=344)then
count<=345;
else
count<=1;
endif;
endif;
Else--随机播放模式
if(lastone='1'ornextone='1')then--按下了上一首或下一首
state<=play;
if(randnumber=1)then
count<=1;
elsif(randnumber=2)then
count<=145;
elsif(randnumber=3)then
count<=213;
else
count<=345;
endif;
endif;
endif;
endif;
whenplay=>--播放状态
if(lastone='0'andprevious='1'andnextone='0')then--本首重放
if(count>=1andcount<=144)th