数字系统设计音乐播放器.docx
- 文档编号:29608654
- 上传时间:2023-07-25
- 格式:DOCX
- 页数:24
- 大小:392.40KB
数字系统设计音乐播放器.docx
《数字系统设计音乐播放器.docx》由会员分享,可在线阅读,更多相关《数字系统设计音乐播放器.docx(24页珍藏版)》请在冰豆网上搜索。
数字系统设计音乐播放器
一、实验目的和要求(必填)二、实验内容和原理(必填)
三、主要仪器设备(必填)四、操作方法和实验步骤
五、实验数据记录和处理六、实验结果与分析(必填)
七、讨论、心得
装订线
一、实验目的和要求:
实验目的:
(1)掌握音符产生的方法,了解DDS技术的应用。
(2)了解AC97音频接口电路的应用。
(3)掌握系统“自顶而下”的设计方法。
实验任务:
设计一个音乐播放器。
(1)可以播放四首乐曲,设置play、next、reset三个按键。
按play键播放当前乐曲,按next键播放下一首乐曲。
(2)LED0指示播放情况(播放时点亮)、LED2和LED3指示当前乐曲序号。
二、实验内容和原理
(1)音乐播放器的设计原理
根据实验任务可将系统分为主控制器(mcu)、乐曲读取(song_reader)、音符播放(note_player)、AC97音频接口(codec_conditioner)和ac97_if五个子模块,系统的总体框图如下:
各个模块的功能如下:
1.mcu模块接收按键信息,通知song_reader模块是否要播放(play)及播放哪首乐曲(song),若一曲播放结束则进入播放结束END状态。
2.song_reader模块根据mcu模块的要求,逐个取出音符{note,duration}送给note_player模块播放,当一首乐曲播放完毕,回复mcu模块乐曲播放结束信号(song_done)。
3.note_player模块接收到需播放的音符,在音符的持续时间内,以48kHz速率送出该音符的正弦波样品给AC97音频接口模块。
当一个音符播放结束,向song_reader模块发送一个note_done脉冲索取新的音符。
4.codec_conditiner、ac97_if模块负责与AC97音频系统接口工作,本实验已提供了这两个模块的代码。
另外,按键处理模块完成输入同步化、防颤动和脉宽变换等功能。
1、主控制模块mcu的设计
mcu模块是主控制模块,有响应按键信息、控制系统播放两大任务,工作流程如下面的流程图所示。
要求系统复位后经RESET状态初始化后进入WAIT状态等待按键输入或乐曲播放结束应答,若有按键输入则转入相应的按键处理状态(NEXT或PLAY),若一曲播放结束则进入结束播放END状态。
mcu的控制器算法流程图如下图:
以下为mcu的端口含义
引脚名称
I/O
引脚说明
clk
Input
100MHz时钟信号
reset
Input
复位信号,高电平有效
play_button
Input
“播放”按键,低电平有效
next_button
Input
“下一曲”按键,一个时钟周期宽度的高电平脉冲
play
Output
高电平表示播放
song_done
Output
当播放下一曲时,输出一个时钟周期宽度的高电平复位脉冲reset_play,并复位note_player模块
song_done
Input
note_player模块的应答信号一个时钟周期宽度的高电平脉冲表示一曲播放结束
song[1:
0]
Output
当前乐曲的序号
结合以上算法流程图和端口定义,mcu模块代码如下:
modulemcu(clk,reset,play_button,next,play,reset_play,song,song_done);
parameterRESET=0,WAIT=1,END=2,NEXT=3,PLAY=4;
inputreset,play_button,song_done,clk,next;
outputreg[1:
0]song;
outputregplay,reset_play;
regstate;
always@(posedgeclk)
begin
if(reset)
beginplay<=0;song<=2'b00;reset_play<=1;state<=RESET;end
else
case(state)
RESET:
beginreset_play<=0;state<=WAIT;end
WAIT:
if(song_done)
beginstate<=END;play<=0;reset_play<=1;end
elseif(next)
beginstate<=NEXT;play<=1;reset_play<=1;song<=song+1;end
elseif(~play_button)
beginstate<=PLAY;play<=1;reset_play<=0;end
else
beginstate<=WAIT;reset_play<=0;end
END,NEXT,PLAY:
beginstate<=WAIT;reset_play<=0;end
endcase
end
endmodule
2、乐曲读取模块song_reader的设计
乐曲读取模块song_reader的功能有:
(1)根据mcu模块的要求,选择播放乐曲;
(2)相应note_player模块请求,从song_rom中逐个取出音符{note,duration}送给note_player模块播放;
(3)判断乐曲是否播放完毕,若播放完毕,则回复mcu模块应答信号。
根据设计要求,以下是song_reader模块的结构框图
根据设计要求,以下是song_reader模块的端口含义
引脚名称
I/O
引脚说明
clk
Input
100MH时钟信号
reset
Input
复位信号,高电平有效
play
Input
来自mcu的控制信号,高电平播放
song[1:
0]
Input
来自mcu的控制信号,当前播放乐曲的序号
note_done
Input
来自模块note_player应答信号,一个时钟周期宽度的高电平脉冲表示一个音符播放结束
song_done
0utput
给mcu的应答信号,当乐曲播放结束,输出一个时钟周期宽度的高电平脉冲
note[5:
0]
Output
音符标记
duration[5:
0]
Output
音符的持续时间
new_note
Output
给note_player的控制信号,一个时钟周期宽度的高电平脉冲表示新的音符需播放
以下是song_reader的算法流程图
地址计数器为5位二进制计数器,其中note_done为计数允许输入,状态q为song_rom的低5位地址,song[1:
0]为song_rom高两位地址。
当地址计数器出现进位或duration为0时,表示乐曲结束,应输出一个时钟周期宽度的高电平脉冲信号song_done。
结束判断模块应调用提供的模块one_pulse,使输出为一个时钟周期宽度的高电平脉冲。
结合上图以及模块要求,编写song_reader代码如下:
modulesong_reader(clk,reset,play,song,note_done,song_done,note,duration,new_note);
inputclk,reset,play,note_done;
input[1:
0]song;
outputsong_done,new_note;
output[5:
0]note,duration;
parameterRESET=0,NEW_NOTE=1,WAIT=2,NEXT_NOTE=4;
reg[1:
0]STATE;
regnew_note;
always@(posedgeclk)
begin
if(reset==1)beginnew_note<=0;STATE<=RESET;end
else
case(STATE)
RESET:
if(play==1)
beginnew_note<=1;STATE<=NEW_NOTE;end
else
beginnew_note<=0;STATE<=RESET;end
NEW_NOTE:
beginnew_note<=0;STATE<=WAIT;end
WAIT:
if(play==1)
if(note_done==1)
beginnew_note<=0;STATE<=NEXT_NOTE;end
else
beginnew_note<=0;STATE<=WAIT;end
elsebeginnew_note<=0;STATE<=RESET;end
NEXT_NOTE:
beginnew_note<=1;STATE<=NEW_NOTE;end
endcase
end
wire[4:
0]q;
wireco;
song_romsong_rom1(.clk(clk),.dout({note,duration}),.addr({song,q}));
addr_counteraddr_counter1(.clk(clk),.reset(reset),.note_done(note_done),.q(q),.co(co));
end_judgingend_judging1(.co(co),.duration(duration),.clk(clk),.song_done(song_done));
(返回给主控制器一个应答信号,即框图中的结束判断模块)
endmodule
其中模块end_judging的代码如下:
moduleend_judging(co,duration,clk,song_done);
parameterN=6;
inputco;
input[N-1:
0]duration;
inputclk;
outputsong_done;
wire[N-1:
0]dd;
wireqq;
assignsong_done=~qqⅆ
assigndd=co|(duration==6'b00000);
D_FFdff1(.d(dd),.clk(clk),.q(qq));
endmodule
其中模块counter的代码如下:
moduleaddr_counter(clk,q,co,reset,note_done);
inputclk,reset,note_done;
outputreg[4:
0]q;
outputco;
assignco=note_done&&(&q);
always@(posedgeclk)
begin
if(reset)beginq<=0;end
else
beginif(note_done)q<=q+1;
else
q<=q;
end
end
endmodule
3、音符播放模块note_player的设计
音符播放模块note_player是本实验的核心模块,它的主要功能有:
(1)从送song_reader模块接收所需播放的音符信息{note,duration};
(2)根据note值找出DDS的相位增量step_size;
(3)以48kHz速率从SineROM取出正弦样品送给AC97接口模块;
(4)当一个音符播放完毕,向song_reader模块索取新的音符。
根据note_player模块的任务,进一步划分功能单元,为简化设计,可将产生正弦样品的DDS模块设计一个独立子模块sine_reader。
note_player控制器负责与song_reader模块接口,读取音符信息,并根据音符信息从FrequencyROM中读取相位增量step_size送给DDS子模块sine_reader。
另外,note_player控制器还需要控制音符播放时间。
note_player控制器的算法流程如下。
在复位或未播放时,控制器处于RESET状态,PLAY为音符播放状态,当一个音符播放结束时,控制器进入DONE状态,PLAY为音符播放状态,当一个音符播放结束时,控制器进入DONE状态,置位done_with_note,向song_reader模块索取新的音符,然后进入LOAD状态,读取新的音符后进入PLAY状态播放下一个音符。
note_player模块的结构框图如下:
note_player控制器的算法流程图如下:
音符定时器为6位二进制计数器,beat、time_clear分别为使能、清0信号,均为高电平有效。
定时时间为音符的长短(duration_to_load个beat周期),timer_done为定时结束标志。
根据实验要求以下是note_player模块代码:
modulenote_player(clk,reset,play_enable,note_to_load,duration_to_load,
done_with_note,load_new_note,beat,generate_next_sample,sample_out,new_sample_ready);
inputclk;
inputreset;
//Whenhighweplay,whenlowwedon't.
inputplay_enable;
//Thenotetoplay
input[5:
0]note_to_load;
//Thedurationofthenotetoplay
input[5:
0]duration_to_load;
//Tellsuswhenwehaveanewnotetoload
inputload_new_note;
//Whenwearedonewiththenotethisstayshigh.
outputdone_with_note;
//regdone_with_note;
//Thisisour1/48thsecondbeat
inputbeat;
//Tellsuswhenthecodecwantsanewsample
inputgenerate_next_sample;
//Oursampleoutput
output[15:
0]sample_out;
//Tellsthecodecwhenwe'vegotasample
outputnew_sample_ready;
wire[19:
0]step_size;
sine_readersine_reader_inst(.clk(clk),.reset(reset),.step_size({10'd18,10'd791}),
.step_size(step_size),.generate_next_sample(generate_next_sample),
.new_sample_ready(new_sample_ready),.sample_out(sample_out));
(note_player控制器一段式描述代码)
parameterRESET=0,PLAY=1,LOAD=2,DONE=3;
reg[1:
0]state;
regdone_with_note;
regtimer_clear;
wiretimer_done;
reg[5:
0]note;
always@(posedgeclk)
if(reset)beginstate<=RESET;note<=6'b0;done_with_note<=0;timer_clear<=1;end
else
case(state)
RESET,LOAD,DONE:
if(~play_enable)beginstate<=RESET;note<=6'b0;done_with_note<=0;timer_clear<=1;
end
elseif(~load_new_note)
beginstate<=PLAY;done_with_note<=0;timer_clear<=0;end
else
beginstate<=LOAD;note<=note_to_load;done_with_note<=0;timer_clear<=1;
end
PLAY:
if(timer_done)
beginstate<=DONE;note<=note_to_load;done_with_note<=1;timer_clear<=1;end
elseif(~play_enable)
beginstate<=RESET;note<=6'b0;done_with_note<=0;timer_clear<=1;end
elseif(~load_new_note)
begin
state<=PLAY;done_with_note<=0;timer_clear<=0;end
elsebeginstate<=LOAD;note<=note_to_load;done_with_note<=0;
timer_clear<=1;end
default:
beginstate<=RESET;note<=6'b0;done_with_note<=0;timer_clear<=1;
end
endcase
frequency_romfrequency_rom_inst(.clk(clk),.dout(step_size),.addr(note));
note_timernote_timer(.cin(duration_to_load),.en(beat),
.clk(clk),.r(timer_clear),.cout(timer_done));
endmodule
其中模块note_timer音符定时器代码如下:
modulenote_timer(cout,cin,r,clk,en);
parametern=6;
reg[n-1:
0]q;
outputcout;
input[n-1:
0]cin;
inputr,clk,en;
assigncout=en&&(q==(cin-1));
always@(posedgeclk)
if(r)q=0;
elseif(en)q=q+1;
elseq=q;
endmodule
子模块sine_reader的功能就是利用DDS技术产生正弦样品。
在本实验中,系统时钟clk与取样脉冲generate_next_sample为两个不同信号;
实验中相位增量为22位,其中小数部分为10位。
对于step_size本身为20位二进制数的问题,可通过对其进行{2’b00,step_size}处理使其扩展至22位。
sine_reader原理框图:
sine_rom的地址和数据处理方法:
区域(raw_addr[21:
20])
SineRom地址(rom_addr)
Sample
00
raw_addr[19:
10]
raw_data[15:
0]
01
当raw_addr[20:
10]=1024时,rom_addr取1023;其余取~raw_addr[19:
10]+1
raw_data[15:
0]
10
raw_addr[19:
10]
~raw_data[15:
0]+1
11
当raw_addr[20:
10]=1024时,rom_addr取1023;其余取~raw_addr[19:
10]+1
~raw_data[15:
0]+1
由以上sine_reader原理框图以及sine_rom的地址和数据处理方法可得sine_reader模块代码。
modulesine_reader(step_size,clk,generate_next_sample,reset,sample_out,new_sample_ready);
input[19:
0]step_size;
inputclk,generate_next_sample,reset;
output[15:
0]sample_out;
outputnew_sample_ready;
wire[21:
0]raw_addr;
wire[21:
0]sum;
wire[9:
0]rom_addr;
wire[15:
0]sample;
wire[15:
0]raw_data;
full_adder#(22)
adder(.a(raw_addr),.b({2'b00,step_size}),.s(sum),.ci(1'b0),.co());
D_FFRE#(22)
dffr1(.d(sum),.en(generate_next_sample),.r(reset),.clk(clk),.q(raw_addr));
addr_processor
addr_pro(.in_addr(raw_addr[20:
10]),.out_addr(rom_addr));
sine_rom
sine_rom1(.clk(clk),.dout(raw_data),.addr(rom_addr));
data_processor#(16)
data_pro(.flag(raw_addr[21]),.in_data(raw_data),.out_data(sample));
D_FFRE#(16)dffr2(.d(sample),.en(generate_next_sample),.r(reset),.clk(clk),.q(sample_out));
D_FF
dffr3(.d(generate_next_sample),.clk(clk),.q(new_sample_ready));
endmodule
其中地址处理(addr_processor)模块的代码如下:
moduleaddr_processor(in_addr,out_addr);
input[10:
0]in_addr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数字 系统 设计 音乐 播放
![提示](https://static.bdocx.com/images/bang_tan.gif)