设计背景:
FPGA的学习也算是是一种日积月累才能有成就的过程,前面我们学习了各个模块,各个芯片的配置等等,之后笔者通过两个简单的例子来让大家去系统的学习和认识FPGA。所学习的电子琴设计也算是一次简单的各个模块的联系调用的一个过程,对以后工作中的学习有很好的帮助。
设计原理:
本次的设计主要是通过控制ps2键盘来使蜂鸣器发出哆来咪法嗦拉西7种音来,音符主要又高低音等等,本设计只选择发出高音的多来咪发嗦啦西。本设计中还用到了VGA的设计,通过VGA来在显示屏上画出如下图的黑白的电子琴键:
当按下多来咪发嗦啦西时,对应的键值变颜色表示按下,不变色表示不按下,颜色自己可以调节,但是琴的按键必须为黑白色来显示出来。
当按下按键的时候,蜂鸣器来鸣响对应时间的音符,本设计蜂鸣器响的时间为0.25S一个音符持续的时间。
本次设计用到的PS2和VGA的设计原理笔者在这里就不过多的介绍了,不明白的可以翻看前面发的文档内容。
在本设计中介绍蜂鸣器的使用和各音符发声的频率大小。本设计用的是无源蜂鸣器,原理图如下:
由于FPGA的驱动能力不够,我们添加了一个三极管来驱动这个无源蜂鸣器,而无源蜂鸣器的主要特点是内部不带振荡源,所以如果使用直流信号是无法使无源蜂鸣器鸣叫的,必须使用方波去驱动它。
现在我们明白了,只要往蜂鸣器发送一定频率的方波,就可以使得蜂鸣器发出声音,然后现在的问题是,我们究竟要往蜂鸣器发送什么频率的方波信号呢?具体的频率可以查看下图:
现在我们知道了如何让蜂鸣器响起,又知道发送什么频率可以让蜂鸣器响起什么的声音,所以我相信我们已经有能力让蜂鸣器响起我们需要的音乐了。
设计架构图:
设计代码:
顶层模块
0 module music_ps2(clk, rst_n, hs, vs, r_g_b, ps2_clk, ps2_data, beep);
1
2 input clk;
3 input rst_n;
4
5 output hs;
6 output vs;
7 output [7:0]r_g_b;
8 output beep;
9
10 input ps2_clk;
11 input ps2_data;
12
13 wire flag;
14 wire [7:0] data, data_n;
15 wire clk_1M;
16
17
18 frenp frep_dut(
19 .clk(clk),
20 .rst_n(rst_n),
21 .clk_1M(clk_1M)
22 );
23
24 ps2_rec rec_dut(
25 .clk(clk_1M),
26 .rst_n(rst_n),
27 .ps2_clk(ps2_clk),
28 .ps2_data(ps2_data),
29 .flag(flag),
30 .data(data)
31 );
32
33 decode decode_dut(
34 .clk(clk_1M),
35 .rst_n(rst_n),
36 .flag(flag),
37 .data(data),
38 .data_n(data_n)
39 );
40
41 music music_dut(
42 .clk(clk_1M),
43 .rst_n(rst_n),
44 .data_n(data_n),
45 .beep(beep)
46 );
47
48 vga vga_dut(
49 .clk(clk),
50 .rst_n(rst_n),
51 .hs(hs),
52 .vs(vs),
53 .r_g_b(r_g_b),
54 .data_n(data_n)
55 );
56
57 endmodule
蜂鸣器模块
0 module music(clk, rst_n, data_n, beep); 端口列表
1
2 input clk;
3 input rst_n;
4 input [7:0] data_n; //输入的键值
5 output reg beep; //蜂鸣器
6
7 reg [10:0] music_data;
8 wire [10:0] data;
9
10 always @ (posedge clk)
11 if(!rst_n)
12 begin
13 music_data <= 0;
14 end
15 else
16 case (data_n)
17 1 : music_data <= 478; //蜂鸣器的高音1
18 2 : music_data <= 425; //蜂鸣器的高音2
19 3 : music_data <= 379; //蜂鸣器的高音3
20 4 : music_data <= 358; //蜂鸣器的高音4
21
22 5 : music_data <= 319; //蜂鸣器的高音5
23 6 : music_data <= 284; //蜂鸣器的高音6
24 7 : music_data <= 253; //蜂鸣器的高音7
25 default: music_data <= 0;
26 endcase
27
28
29 reg [20:0] count, cnt;
30
31 always @ (posedge clk)
32 if(!rst_n && !data_n)
33 begin
34 count <= 0;
35 end
36 else
37 if(count < 250_000 - 1)
38 begin
39 count <= count + 1;
40 end
41 else
42 begin
43 count <= 0;
44 end
45
46 //计数0.25S的时间
47 assign data = (count == 250_000 - 1) ? music_data : data;
48
49 always @ (posedge clk)
50 if(!rst_n)
51 begin
52 cnt <= 1;
53 beep <= 0;
54 end
55 else
56 if(data == 0) //控制蜂鸣器不响
57 begin
58 cnt <= 1;
59 beep <= 0;
60 end
61 else if(cnt < data) //计数对应的频率
62 begin
63 cnt <= cnt + 1;
64 end
65 else
66 begin
67 cnt <= 1; //蜂鸣器响
68 beep <= ~beep;
69 end
70
71
72
73 endmodule
代码验证正确无误,笔者在这边就不过多的验证,大家可以自主的补全代码,后续代码会在论坛中发出来供大家参考个学习。
全部0条评论
快来发表一下你的评论吧 !