FPGA学习之蜂鸣器演奏乐曲
参考链接:http://www.cnblogs.com/kongtiao/archive/2011/07/20/2111581.html
一、实验目的:学习驱动FPGA之IO引脚来控制蜂鸣器演奏音乐。
二、实验环境:FPGA开发板AX301,Quartus ii
三、实验介绍:
我们都知道,乐曲由音调和音长组成,只要将音调和音长控制好就能演奏出动听的乐曲。下面将用Verilog HDL 硬件描述语言完成乐曲演奏的设计。
1、音调的控制
频率的高低决定了音调的高低。图1.1是音调和音律之间的关系。
图1.1 音调和音律之间的关系
所有不同频率的信号都是从同一个基准频率分频得来的。由于音阶频率多为非整数,而分频系数又不能为小数,故必须将计算得到的分频数四舍五入取整。若基准频率过低,则由于分频比太小,四舍五入取证后的误差较大。若基准频率过高,虽然误差变小,但分频数将变大。实际的设计应综合考虑两方面的因素,在尽量减小频率误差的前提下去合适的基准频率。
本例中需要演奏的是梁祝,该乐曲各音阶频率及相应的分频比如图1.2所示。
图1.2 乐曲各音阶频率及相应的分频比
在表中除了给出分频比外,还给出了对应与各个音阶频率时计数器不同的预置数。对于不同的分频系数,只要加载不同的预置数即可。采用加载预置数实现分频的方法比采用反馈复零法节省资源,实现起来更容易。
2、音长的控制
音符的持续时间须根据乐曲的速度及每个音符的节拍数来确定。
本实验中演奏梁祝片断,最短的音符为四分音符。
3、乐曲演奏电路的原理框图
图1.3 乐曲演奏电路的原理框图
其中,乐谱产生电路用来控制音乐的音调和音长。控制音调通过设置计数器的预置数来实现,预置不同的数值可以使计数器产生不同频率的信号,从而产生不同的音调。控制音长是通过控制计数器预置数停留时间来实现,每个音符的演奏时间是0.25S的整数倍,对于节拍较长的音符,如二分音符。在记谱时将分别连续记录两次即可。
4、实验实现:
详细实现步骤请参考 【连载】 FPGA Verilog HDL 系列实例--------8-3编码器
(1)在设计文件中输入Verilog代码。
1 //--------------------------------------------------------------------------------------------------
2 //
3 // Title : play
4 // Author : wangliang
5 //
6 //-------------------------------------------------------------------------------------------------
7 //-------------------------------------------------------------------------------------------------
8 //
9 // Description :
10 //
11 //-------------------------------------------------------------------------------------------------
12 `timescale 1 ns / 1 ps
13
14 module play ( audio , sys_CLK , button);
15
16 output audio;
17 input sys_CLK;
18 input button;
19
20 reg [23:0] counter4Hz,
21 counter6MHz;
22 reg [13:0] count,origin;
23 reg audiof;
24
25 reg clk_6MHz,
26 clk_4Hz;
27
28 reg [4:0] j;
29 reg [7:0] len;
30
31
32 assign audio= button? audiof : 1'b1 ; //控制开关
33
34 always @(posedge sys_CLK) //6MHz分频
35 begin
36 if(counter6MHz==4)
37 begin
38 counter6MHz=0;
39 clk_6MHz=~clk_6MHz;
40 end
41 else
42 begin
43 counter6MHz=counter6MHz+1;
44 end
45 end
46
47 always @(posedge sys_CLK) //4Hz分频
48 begin
49 if(counter4Hz==6250000)
50 begin
51 counter4Hz=0;
52 clk_4Hz=~clk_4Hz;
53 end
54 else
55 begin
56 counter4Hz=counter4Hz+1;
57 end
58 end
59
60
61 always @(posedge clk_6MHz)
62 begin
63 if(count==16383)
64 begin
65 count=origin;
66 audiof=~audiof;
67 end
68 else
69 count=count+1;
70 end
71
72
73 always @(posedge clk_4Hz)
74 begin
75 case(j)
76 'd1:origin='d4916; //low
77 'd2:origin='d6168;
78 'd3:origin='d7281;
79 'd4:origin='d7791;
80 'd5:origin='d8730;
81 'd6:origin='d9565;
82 'd7:origin='d10310;
83 'd8:origin='d010647; //middle
84 'd9:origin='d011272;
85 'd10:origin='d011831;
86 'd11:origin='d012087;
87 'd12:origin='d012556;
88 'd13:origin='d012974;
89 'd14:origin='d013346;
90 'd15:origin='d13516; //high
91 'd16:origin='d13829;
92 'd17:origin='d14108;
93 'd18:origin='d11535;
94 'd19:origin='d14470;
95 'd20:origin='d14678;
96 'd21:origin='d14864;
97 default:origin='d011111;
98 endcase
99 end
100
101 always @(posedge clk_4Hz) //乐谱
102 begin
103 if(len==63)
104 len=0;
105 else
106 len=len+1;
107 case(len)
108 0:j=3;
109 1:j=3;
110 2:j=3;
111 3:j=3;
112 4:j=5;
113 5:j=5;
114 6:j=5;
115 7:j=6;
116 8:j=8;
117 9:j=8;
118 10:j=8;
119 11:j=6;
120 12:j=6;
121 13:j=6;
122 14:j=6;
123 15:j=12;
124 16:j=12;
125 17:j=12;
126 18:j=15;
127 19:j=15;
128 20:j=15;
129 21:j=15;
130 22:j=15;
131 23:j=9;
132 24:j=9;
133 25:j=9;
134 26:j=9;
135 27:j=9;
136 28:j=9;
137 29:j=9;
138 30:j=9;
139 31:j=9;
140 32:j=9;
141 33:j=9;
142 34:j=10;
143 35:j=7;
144 36:j=7;
145 37:j=6;
146 38:j=6;
147 39:j=5;
148 40:j=5;
149 41:j=5;
150 42:j=6;
151 43:j=8;
152 44:j=8;
153 45:j=9;
154 46:j=9;
155 47:j=3;
156 48:j=3;
157 49:j=8;
158 50:j=8;
159 51:j=8;
160 52:j=5;
161 53:j=5;
162 54:j=8;
163 55:j=5;
164 56:j=5;
165 57:j=5;
166 58:j=5;
167 59:j=5;
168 60:j=5;
169 61:j=5;
170 62:j=5;
171 63:j=5;
172 endcase
173
174 end
175 endmodule
(2)由设计文件生成的.bsf文件,乐曲演奏的外接接口如图1.4所示。
图1.4 乐曲演奏的外接接口
(3)分配引脚:
将sys_CLK信号接时钟,button接按键,audio接蜂鸣器,这里就不贴出具体的引脚图了,大家可以根据自己的开发板对应起来。
(4)实验结果:
当打开按键时,就能听到完整的梁祝乐曲了。但是总感觉音乐有点变味了,不知道是蜂鸣器的原因还是程序的bug!