FPGA学习系列:38. 电子琴的设计

描述

设计背景:

FPGA的学习也算是是一种日积月累才能有成就的过程,前面我们学习了各个模块,各个芯片的配置等等,之后笔者通过两个简单的例子来让大家去系统的学习和认识FPGA。所学习的电子琴设计也算是一次简单的各个模块的联系调用的一个过程,对以后工作中的学习有很好的帮助。

 

设计原理: 

本次的设计主要是通过控制ps2键盘来使蜂鸣器发出哆来咪法嗦拉西7种音来,音符主要又高低音等等,本设计只选择发出高音的多来咪发嗦啦西。本设计中还用到了VGA的设计,通过VGA来在显示屏上画出如下图的黑白的电子琴键:

       


当按下多来咪发嗦啦西时,对应的键值变颜色表示按下,不变色表示不按下,颜色自己可以调节,但是琴的按键必须为黑白色来显示出来。

当按下按键的时候,蜂鸣器来鸣响对应时间的音符,本设计蜂鸣器响的时间为0.25S一个音符持续的时间。

本次设计用到的PS2和VGA的设计原理笔者在这里就不过多的介绍了,不明白的可以翻看前面发的文档内容。

在本设计中介绍蜂鸣器的使用和各音符发声的频率大小。本设计用的是无源蜂鸣器,原理图如下:

FPGA

 由于FPGA的驱动能力不够,我们添加了一个三极管来驱动这个无源蜂鸣器,而无源蜂鸣器的主要特点是内部不带振荡源,所以如果使用直流信号是无法使无源蜂鸣器鸣叫的,必须使用方波去驱动它。

 

 现在我们明白了,只要往蜂鸣器发送一定频率的方波,就可以使得蜂鸣器发出声音,然后现在的问题是,我们究竟要往蜂鸣器发送什么频率的方波信号呢?具体的频率可以查看下图:

 

 现在我们知道了如何让蜂鸣器响起,又知道发送什么频率可以让蜂鸣器响起什么的声音,所以我相信我们已经有能力让蜂鸣器响起我们需要的音乐了。

FPGA


设计架构图:

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 

 

 

代码验证正确无误,笔者在这边就不过多的验证,大家可以自主的补全代码,后续代码会在论坛中发出来供大家参考个学习。


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分