koorio.com
海量文库 文档专家
当前位置:首页 >> >>

数字系统设计音乐播放器

一、实验目的和要求(必填)

二、实验内容和原理(必填)

三、主要仪器设备(必填)

四、操作方法和实验步骤

五、实验数据记录和处理

六、实验结果与分析(必填)

七、 讨论、心得

一、实验目的和要求:

实验目的:

(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模块代码如下:

module mcu(clk, reset, play_button, next, play, reset_play, song, song_done );

parameter RESET=0, WAIT=1, END=2, NEXT=3, PLAY=4;

input reset, play_button,song_done,clk,next;

output reg [1:0] song; output reg play, reset_play;

reg state; always @( posedge clk )

begin

if (reset)

begin play<=0; song<=2'b00;reset_play<=1; state<=RESET; end

else

case (state)

RESET: begin reset_play<=0; state<=WAIT; end

WAIT: if (song_done)

begin state <=END; play<=0; reset_play<=1; end

else if (next)

begin state <=NEXT; play<=1; reset_play<=1; song<=song+1; end

else if (~play_button)

begin state <=PLAY; play<=1; reset_play<=0; end

else

begin state <=WAIT; reset_play<=0; end

END, NEXT, PLAY: begin state <=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代码如下: module song_reader(clk,reset,play,song,note_done,song_done,note,duration, new_note ); input clk,reset,play,note_done; input [1:0] song; output song_done, new_note; output [5:0] note, duration; parameter RESET=0, NEW_NOTE=1, WAIT=2, NEXT_NOTE=4; reg [1:0] STATE; reg new_note; always @( posedge clk ) begin
if (reset==1) begin new_note<=0; STATE<=RESET; end else case (STATE) RESET: if (play==1)
begin new_note<=1; STATE<=NEW_NOTE; end else
begin new_note<=0; STATE<=RESET; end NEW_NOTE:
begin new_note<=0; STATE<=WAIT; end WAIT:
if (play==1) if (note_done==1)
begin new_note<=0; STATE<=NEXT_NOTE; end else
begin new_note<=0; STATE<=WAIT; end else begin new_note<=0; STATE<=RESET; end NEXT_NOTE:
begin new_note<=1; STATE<=NEW_NOTE; end endcase end wire [4:0] q; wire co; song_rom song_rom1(.clk(clk),.dout({note,duration}),.addr({song,q})); addr_counter addr_counter1(.clk(clk),.reset(reset),.note_done(note_done),.q(q),.co(co)) ; end_judging

end_judging1(.co(co),.duration(duration),.clk(clk),.song_done(song_done)); (返回给主控制器一个应答信号,即框图中的结束判断模块) endmodule
其中模块 end_judging 的代码如下: module end_judging(co, duration, clk, song_done); parameter N=6; input co; input [N-1:0] duration; input clk; output song_done; wire [N-1:0] dd; wire qq; assign song_done = ~qq & dd; assign dd = co | (duration==6'b00000); D_FF dff1(.d(dd), .clk(clk), .q(qq)); endmodule 其中模块 counter 的代码如下: module addr_counter(clk,q,co,reset,note_done); input clk,reset,note_done; output reg [4:0] q; output co; assign co=note_done&&(&q); always @ (posedge clk) begin if(reset) begin q<=0; end else
begin if(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速率从Sine ROM取出正弦样品送给AC97接口模块; (4)当一个音符播放完毕,向song_reader模块索取新的音符。 根据note_player模块的任务,进一步划分功能单元,为简化设计,可将产生正弦样品 的DDS模块设计一个独立子模块sine_reader。 note_player控制器负责与song_reader模块接口,读取音符信息,并根据音符信息从 Frequency ROM中读取相位增量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 模块代码:
module note_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); input clk; input reset; // When high we play, when low we don't. input play_enable; // The note to play input [5:0] note_to_load; // The duration of the note to play input [5:0] duration_to_load; // Tells us when we have a new note to load input load_new_note; // When we are done with the note this stays high. output done_with_note; //reg done_with_note; // This is our 1/48th second beat input beat; // Tells us when the codec wants a new sample input generate_next_sample; // Our sample output output [15:0] sample_out; // Tells the codec when we've got a sample output new_sample_ready; wire[19:0] step_size; sine_reader
sine_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 控制器一段式描述代码) parameter RESET=0,PLAY=1,LOAD=2,DONE=3; reg [1:0] state; reg done_with_note; reg timer_clear; wire timer_done; reg[5:0] note; always @( posedge clk)

if (reset) begin state<=RESET; note<=6'b0; done_with_note<=0; timer_clear<=1; end
else case (state)
RESET,LOAD,DONE: if (~play_enable) begin state<=RESET; note<=6'b0;
done_with_note<=0; timer_clear<=1; end
else if(~load_new_note) begin state<=PLAY; done_with_note<=0; timer_clear<=0; end

else

begin state<=LOAD; note<=note_to_load; done_with_note<=0;

timer_clear<=1;

end

PLAY:

if(timer_done)

begin state<=DONE; note<=note_to_load; done_with_note<=1;

timer_clear<=1;

end

else if (~play_enable)

begin state<=RESET;

note<=6'b0;

done_with_note<=0;

timer_clear<=1; end

else if(~load_new_note)

begin

state<=PLAY; done_with_note<=0; timer_clear<=0; end

else

begin

state<=LOAD; note<=note_to_load;

done_with_note<=0;

timer_clear<=1; end

default: begin state<=RESET; note<=6'b0; done_with_note<=0;

timer_clear<=1;

end

endcase

frequency_rom

frequency_rom_inst(.clk(clk)

,.dout(step_size),.addr(note));

note_timer note_timer(.cin(duration_to_load),.en(beat),

.clk(clk),.r(timer_clear),.cout(timer_done));

endmodule

其中模块 note_timer 音符定时器代码如下:

module note_timer (cout, cin , r, clk, en);

parameter n=6;

reg[n-1:0] q;

output cout;

input[n-1:0] cin;

input r, clk, en;

assign cout=en&&(q==(cin-1));

always @(posedge clk) if (r) q=0; else if(en) q =q + 1; else q = 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])

Sine Rom地址(rom_addr)

Sample

00

raw_addr[19:10]

raw_data[15:0]

01

当raw_addr[20:10]=1024时,

raw_data[15:0]

rom_addr取1023;其余取

~raw_addr[19:10]+1

10

raw_addr[19:10]

~raw_data[15:0]+1

11

当raw_addr[20:10]=1024时,

~raw_data[15:0]+1

rom_addr取1023;其余取

~raw_addr[19:10]+1
由以上sine_reader原理框图以及sine_rom的地址和数据处理方法可得sine_reader模块代

码。

module sine_reader( step_size, clk, generate_next_sample, reset, sample_out,

new_sample_ready);

input [19:0] step_size;

input clk, generate_next_sample, reset;

output [15:0] sample_out;

output new_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)模块的代码如下: module addr_processor(in_addr, out_addr); input [10:0] in_addr; output [9:0] out_addr; assign out_addr[9:0]=(in_addr[10])?((in_addr[10:0]==1024)?1023:(~in_addr[9:0]+1)):in_addr[9:0]; endmodule 其中数据处理模块(data_processor)的代码如下: module data_processor (flag, in_data, out_data); parameter N=1; input flag; input [N-1:0] in_data; output [N-1:0] out_data; assign out_data=(flag)?(~in_data+1):in_data; endmodule 其中加法器(full_addr)的代码如下: module full_adder(a, b, s, ci, co); parameter N=1; input [N-1:0] a, b; input ci; output [N-1:0] s; output co; assign {co, s}=a+b+ci; endmodule 此外在music_player模块下还要求编写beat_generator模块代码: module beat_generator(clk,ci,co);
parameter N=1000; parameter CounterBits=10; output co; input ci,clk; reg[CounterBits:1] qout=0; assign co=(qout==(N-1))&ci;

always@(posedge clk) begin if(ci) begin if(qout==(N-1))qout=0; else qout=qout+1; end end endmodule 三、主要仪器设备 1.装有ISE、Modelsim SE和ChipScope Pro软件的计算机。 2.XUP Virtex-ⅡPro开发系统一套。
3.耳机一副。
四、操作方法和实验步骤 1.编写mcu、song_reader和note_player三个模块的Verilog HDL代码及其测试代码,并用Modelsim仿真。 2.将光盘中的ISE文件夹复制到硬盘中,打开music_player.ise工程文件。添加已设计的mcu、song_reader 和note_player三个模块。
3.对工程进行综合、约束、实现,并下载工程文件到XUP Virtex-ⅡPro 开发实验板中。
4.将耳机接入实验开发音频输出插座,操作play、reset、next 三个按键,试听耳机中乐曲并观察实验板上 指示灯变化情况,验证设计结果是否正确。
五、实验数据记录和处理 1.mcu 仿真波形
从图中可以看出,play_button按下后(play_button=0),待到下一个clk上升沿到来时,play=1, reset_player=0,乐曲开始播放;一首乐曲播放完后(song_done=1),在下一时钟周期reset_player=1,play=0, 乐曲复位; 按下一首(next_button=1),则play=1,reset_player=1,song加1(由0变成了1),即开始播 放下一首乐曲。
综上所述,仿真结果满足 mcu 的算法流程图。
2.song_reader模块仿真波形 此图为波形开始时 由图可知,当play跳变到高电平(播放开始)后,new_note立即变为高电平,开始播放音符。每个音符 结束时note_done输出一个高电平,在下一个时钟上升沿,new_note变为高电平,开始播放新的音符。 此图为结束时 duration=0时(一首歌结束),由于采用了脉冲变宽电路,输出song_done信号宽度为一个时钟周期。 sine_reader模块仿真波形
局部放大图 如上图所示,sine_reader 根据 step_size 的相位增量能够实现正弦波形频率的变化, sample_ready信号总在generate_next的下一个时钟上升沿产生,同时sample输出信号,符合sine_reader 的原理框图。 4.note_player仿真波形 在load_new_note前没有音符播放,当load_new_note产生一个高电平信号,则一个{note,duration}的音符 载入,开始播放。 5. 音乐播放器(music_player)模块整体波形 可从上面note_player中观察到sample_out输出一串正弦信号,说明系统可以工作。 六、实验结果与分析
仿真完成后下载到 ISE 上,对工程进行综合、约束、实现,并下载工程文件到 XUPVirtex-Pro 开发实验板中。将耳机接入实验开发板音频输出插座,操作 play、reset、 next 三个按键,试听耳机中的乐曲并观察实验板上指示灯变化情况,

当按动 reset 按键时,所有状态复位,乐曲序号为 00。进入准备状态。 当按动 play 按键时,进入播放状态,指示灯 LED0 点亮,当前乐曲播放。 当按动 next 按键时,乐曲序号+1,乐曲序号指示灯变化,进入下一曲状态,播放指示 灯点亮,同时播放乐曲。 综上所述,实验结果符合设计要求。 七、讨论,心得 理论课上很少有讲到 VerlilogHDL 语言的实际应用,所以大多数该语言的学习还是在 实验课上自学而成。VerlilogHDL 语言与以前学习的 C 语言还是有很大的不同的,它很直观, 可以直接模拟电路。 在本实验课上我们还学习了 ModelSim 软件的仿真和 ISE 工程的建立和在电路板上的操 作,这对我们以后的学习和工作是有非常大的帮助的。整个实验课程就是自己动手动脑解 决一个个问题,凭借自己的努力将各个模块代码一一仿真成功,这种巅峰享受让我在实验 中渐渐对数字系统的产生了浓厚兴趣,因此大三时,我还是决定继续学习数字系统设计Ⅱ 以及实验课程,对数字系统有更进一步的了解。 本次实验还让我掌握音符产生的方法,了解 DDS 技术的应用、了解 AC97 音频接口电路 的应用、掌握系统“自顶而下”的设计方法。


网站首页 | 网站地图
All rights reserved Powered by 酷我资料网 koorio.com
copyright ©right 2014-2019。
文档资料库内容来自网络,如有侵犯请联系客服。3088529994@qq.com