VHdl乐曲演奏实验.docx
- 文档编号:30225660
- 上传时间:2023-08-07
- 格式:DOCX
- 页数:16
- 大小:694.65KB
VHdl乐曲演奏实验.docx
《VHdl乐曲演奏实验.docx》由会员分享,可在线阅读,更多相关《VHdl乐曲演奏实验.docx(16页珍藏版)》请在冰豆网上搜索。
VHdl乐曲演奏实验
EDA课程设计
实验报告
专业:
班级:
姓名:
LSC
学号:
指导教员:
一、试验名称:
乐曲自动演奏器
二、试验目的:
1.使用FPGA控制蜂鸣器演奏乐曲梁祝中的一段;
2.初步学会利用结构建模方法设计程序。
三、试验内容:
1.利用时钟分频进行音调和音长的设定;
2.利用整个程序,播放梁祝乐曲;
3.让LED灯随着音乐的节拍显示,分高、中、低三种频率显示。
四、试验要求:
1.将时钟频率分别分成6MHz和4Hz两种;
2.利用功能框图建立整个程序,清晰的播放出梁祝乐曲。
五、试验背景及基本原理:
5.1乐曲演奏基本原理:
乐曲演奏的原理是这样的:
组成乐曲的每个音符的频率值(音调)及其持续的时间(音长)是乐曲能连续演奏所需的两个基本数据,因此只要控制输出到扬声器的激励信号频率的高低和持续的时间,就可以使扬声器发出连续的乐曲声。
5.2音调的控制
频率的高低决定了音调的高低。
音乐的十二平均率规定:
每两个8度音(如简谱中的中音1与高音1)之间的频率相差一倍。
在两个8度音之间,又可分为12个半音,每两个半音的频率比为12√2。
另外,音名A(简谱中的低音6)的频率为440Hz,音名B到C之间、E到F之间为半音,其余为全音[4]。
由此可以计算出简谱中从低音1至高音1之间每个音名对应的频率,如表所示:
5.3音名与频率的关系
所有不同频率的信号都是从同一个基准频率分频得到的。
由于音阶频率多为非整数,而分频系数又不能为小数,故必须将计算得到的分频数四舍五入取整。
若基准频率过低,则由于分频比太小,四舍五入取整后的误差较大;若基准频率过高,虽然误差变小,但分频数将变大。
实际的设计综合考虑这两方面的因素,在尽量减小频率误差的前提下取合适的基准频率。
本试验中选取6MHz为基准频率。
若无6MHz的基准频率,则可以先分频得到6MHz,或换一个新的基准频率。
实际上,只要各个音名间的相对频率关系不变,演奏出的乐曲听起来都不会"走调"。
本试验需要演奏的是梁祝乐曲,该乐曲各音阶频率及相应的分频比如表2所示。
为了减小输出的偶次谐波分量,最后输出到扬声器的波形应为对称方波,因此在到达扬声器之前,有一个二分频的分频器。
表2中的分频比就是从6MHz频率二分频得到的3MHz频率基础上计算得出的。
由于最大的分频系数为9102,故采用14位二进制计数器分频可满足需要。
在表中,除给出了分频比以外,还给出了对应于各个音阶频率时计数器不同的预置数。
对于不同的分频系数,只要加载不同的预置数即可。
各音节频率对应的分频比及预置数表
此外,对于乐曲中的休止符,只要将分频系数设为0,即初始值为2141=16383即可,此时扬声器将不会发声。
5.4音长的控制
音符的持续时间必须根据乐曲的速度及每个音符的节拍数来确定。
本例演奏的梁祝片段,最短的音符为4分音符,如果将全音符的持续时间设为1s的话,则只需要再提供一个4Hz的时钟频率即可产生4分音符的时长。
由乐谱产生电路控制音乐的音调和音长。
控制音调通过设置计数器的预置数来实现,预置不同的数值可以使计数器产生不同频率的信号,从而产生不同的音调。
控制音长是通过控制计数器预置数的停留时间来实现的,预置数停留的时间越长,则该音符演奏的时间越长。
每个音符的演奏时间都是0.25s的整数倍,对于节拍较长的音符,如2分音符,在记谱时将该音名连续记录两次即可。
5.4音名显示
音名显示电路用来显示乐曲演奏时对应的音符。
可以用3个数码管,分别显示高、中、低音的音名,实现演奏的动态显示,十分直观。
在本试验中,high[3:
0]、med[3:
0]、low[3:
0]等信号分别用于显示高音、中音、低音音符。
为了使演奏能循环进行,需另外设置一个时长计数器,当乐曲演奏完成时,保证能自动从头开始演奏。
六、程序基本流程及实现
6.1程序基本流程:
6.2程序实现
由系统框图(见附录)可以看到本方案分成8个模块。
1)48MHz分频成12MHz波形分频器,源代码和顶层模块如下
//48mhz分成12mhz的分频模块
modulediv_clk12mhz(clk_48mhz,clk_12mhz);
inputclk_48mhz;
outputclk_12mhz;
regclk_12mhz;
reg[21:
0]cnt;
always@(posedgeclk_48mhz)
if(cnt<1)cnt=cnt+1;//(48mhz/12mhz=4,cnt<[4/2-1=1])
elsebegincnt=0;clk_12mhz=!
clk_12mhz;end
Endmodule
2)12MHz分频成6MHz波形分频器,源代码和顶层模块如下:
//12mhz分成6mhz的分频模块,提供给song模块
modulediv_clk6mhz(clk_12mhz,clk_6mhz);
inputclk_12mhz;
outputclk_6mhz;
regclk_6mhz;
regcnt;
always@(posedgeclk_12mhz)
clk_6mhz=!
clk_6mhz;
Endmodule
3)12MHz分频成4Hz波形分频器,源代码和顶层模块如下:
//12mhz分成4hz的分频模块,提供给song模块
modulediv_clk4hz(clk_12mhz,clk_4hz);
inputclk_12mhz;
outputclk_4hz;
regclk_4hz;
reg[21:
0]cnt;
always@(posedgeclk_12mhz)
if(cnt<1499999)cnt=cnt+1;//(12mhz/4hz=3000000,cnt<[3000000/2-1=1499999])
elsebegincnt=0;clk_4hz=!
clk_4hz;end
Endmodule
4)12MHz分频成1mhz波形分频器,源代码和顶层模块如下:
//12mhz分成1mhz的分频模块,提供给quma模块
modulediv_clk1mhz(clk_12mhz,clk_1mhz);
inputclk_12mhz;
outputclk_1mhz;
regclk_1mhz;
reg[21:
0]cnt;
always@(posedgeclk_12mhz)
if(cnt<5)cnt=cnt+1;//(12mhz/1mhz=12,cnt<[12/2-1=5])
elsebegincnt=0;clk_1mhz=!
clk_1mhz;end
Endmodule
5)12MHz分频成1khz波形分频器,源代码和顶层模块如下:
//12mhz分成1khz的分频模块,提供给quma模块
modulediv_clk1khz(clk_12mhz,clk_1khz);
inputclk_12mhz;
outputclk_1khz;
regclk_1khz;
reg[21:
0]cnt;
always@(posedgeclk_12mhz)
if(cnt<5999)cnt=cnt+1;//(12mhz/1khz=12000,cnt<[12000/2-1=5999])
elsebegincnt=0;clk_1khz=!
clk_1khz;end
Endmodule
6)song模块源代码和顶层模块如下:
//音乐产生模块
song(clk_6mhz,clk_4hmodulez,speaker,high,med,low);//模块名为song(端口列表)
inputclk_6mhz,clk_4hz;//定义两个输入端口
outputspeaker;//定义一个输出端口
output[3:
0]high,med,low;
reg[3:
0]high,med,low;//定义了3个4位寄存器
reg[13:
0]divider,origin;//定义了2个14位寄存器
reg[9:
0]counter;//定义了1个10位寄存器
regspeaker;
wirecarry;
assigncarry=(divider==16383);//连续赋值语句
always@(posedgeclk_6mhz)
beginif(carry)divider<=origin;
elsedivider<=divider+1;
end
always@(posedgecarry)
beginspeaker<=~speaker;end//二分频产生方波信号
always@(posedgeclk_4hz)
begin
case({high,med,low})//分频比预置
'b000000000011:
origin<=7281;//低音3
'b000000000101:
origin<=8730;//低音5
'b000000000110:
origin<=9565;//低音6
'b000000000111:
origin<=10310;//低音7
'b000000010000:
origin<=10647;//中音1
'b000000100000:
origin<=11272;//中音2
'b000000110000:
origin<=11831;//中音3
'b000001010000:
origin<=12556;//中音5
'b000001100000:
origin<=12974;//中音6
'b000100000000:
origin<=13516;//高音1
'b000000000000:
origin<=16383;//休止符
endcase
end
always@(posedgeclk_4hz)
begin
if(counter==151)counter<=0;//计时,以实现循环演奏
elsecounter<=counter+1;
case(counter)//记谱
0:
{high,med,low}<='b000000000011;//低音"3"
1:
{high,med,low}<='b000000000011;//持续4个时钟节拍
2:
{high,med,low}<='b000000000011;
3:
{high,med,low}<='b000000000011;
4:
{high,med,low}<='b000000000101;//低音"5"
5:
{high,med,low}<='b000000000101;//发3个时钟节拍
6:
{high,med,low}<='b000000000101;
7:
{high,med,low}<='b000000000110;//低音"6"
8:
{high,med,low}<='b000000010000;//中音"1"
9:
{high,med,low}<='b000000010000;//发3个时钟节拍
10:
{high,med,low}<='b000000010000;
11:
{high,med,low}<='b000000100000;//中音"2"
12:
{high,med,low}<='b000000000110;//低音"6"
13:
{high,med,low}<='b000000010000;//中音"1"
14:
{high,med,low}<='b000000000101;//低音"5"
15:
{high,med,low}<='b000000000101;
16:
{high,med,low}<='b000001010000;//中音"5"
17:
{high,med,low}<='b000001010000;//发3个时钟节拍
18:
{high,med,low}<='b000001010000;
19:
{high,med,low}<='b000100000000;//高音"1"
20:
{high,med,low}<='b000001100000;//中音"6"
case(counter)//记谱
0:
{high,med,low}<='b000000000011;//低音"3"
1:
{high,med,low}<='b000000000011;//持续4个时钟节拍
2:
{high,med,low}<='b000000000011;
3:
{high,med,low}<='b000000000011;
4:
{high,med,low}<='b000000000101;//低音"5"
5:
{high,med,low}<='b000000000101;//发3个时钟节拍
6:
{high,med,low}<='b000000000101;
7:
{high,med,low}<='b000000000110;//低音"6"
8:
{high,med,low}<='b000000010000;//中音"1"
9:
{high,med,low}<='b000000010000;//发3个时钟节拍
10:
{high,med,low}<='b000000010000;
11:
{high,med,low}<='b000000100000;//中音"2"
12:
{high,med,low}<='b000000000110;//低音"6"
13:
{high,med,low}<='b000000010000;//中音"1"
14:
{high,med,low}<='b000000000101;//低音"5"
15:
{high,med,low}<='b000000000101;
16:
{high,med,low}<='b000001010000;//中音"5"
17:
{high,med,low}<='b000001010000;//发3个时钟节拍
18:
{high,med,low}<='b000001010000;
19:
{high,med,low}<='b000100000000;//高音"1"
20:
{high,med,low}<='b000001100000;//中音"6“
endcase
end
endmodule
7)取码模块源代码和顶层模块如下:
//取码模块,从song模块取得数码管显示部分的位码和段码
modulequma(high,med,low,clk_1mhz,dig,duan);
input[3:
0]high,med,low;
inputclk_1mhz;
reg[7:
0]dig;
output[7:
0]dig;//定义输出八位位码
reg[7:
0]duan;
output[7:
0]duan;//定义用于输出的段码的代码
always@(posedgeclk_1mhz)//扫描high,med,low三个寄存器的值,取出位码和段码的代码
begin
if(high!
=0)//如果high的值不为0,则只输出high的值
begindig<=8'b11111011;
case(high)
1:
duan<=8'b00000001;
2:
duan<=8'b00000010;
3:
duan<=8'b00000011;
4:
duan<=8'b00000100;
5:
duan<=8'b00000101;
6:
duan<=8'b00000110;
7:
duan<=8'b00000111;
endcase
end
case(low)
1:
duan<=8'b00000001;
2:
duan<=8'b00000010;
3:
duan<=8'b00000011;
4:
duan<=8'b00000100;
5:
duan<=8'b00000101;
6:
duan<=8'b00000110;
7:
duan<=8'b00000111;
endcase
end
end
endmodule
8)disp:
显示模块,每位输出转换为七段数码管显示。
源代码和顶层模块如下:
//动态数码管显示模块
moduledisp(duan,clk_1khz,seg);
input[7:
0]duan;
inputclk_1khz;
output[7:
0]seg;
reg[7:
0]seg;
always@(posedgeclk_1khz)
begin
case(duan)
1:
seg=8'b11111001;
2:
seg=8'b10100100;
3:
seg=8'b10110000;
4:
seg=8'b10011001;
5:
seg=8'b10010010;
6:
seg=8'b10000010;
7:
seg=8'b11111000;
default:
seg=8'b11111001;
endcase
end
endmodule
七、方案测试
顶层图形文件建立后,对系统进行仿真,由于仿真时对输入输出信号的频率有要求,所以先对每个模块进行仿真
7.148MHz分频成12MHz波形模块,仿真波形如下:
7.2音乐发生器模块,仿真波形如下:
7.3取码模块,仿真波形如下:
7.4显示模块,仿真波形如下:
八、引脚锁定:
待各个功能模块波形仿真通过后,画出原理图,仿真完毕,接下来开始引脚锁定:
引脚锁定列表如下表所示:
附录:
乐曲演奏电路设计原理图及其生成的顶层文件
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VHdl 乐曲 演奏 实验