zclv

 1 设计要求

       以蜂鸣器演奏《世上只有妈妈好》的片段为例,用FPGA设计一个乐曲演奏系统。

2 设计原理

2.1 蜂鸣器的结构原理

                                            

   蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。

  按照内部有无振荡源可以为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器内部带振荡源,所以只要一通电就会发生声音;而无源内部不带振荡源,所以如果用直流信号无法令其鸣叫。必须用一定频率的方波去驱动它,如下图所示。

     蜂鸣器“鸣叫”需要的电流较大,故而采用三极管进行驱动, FPGA 控制三极管是否导通。

 2.2 简谱分析

        乐曲能连续演奏所需要的两个基本数据是:组成乐曲的每个音符的频率值(音调)和每个音符持续的时间(音长)。要演奏乐曲必须考虑两个方面,一个音符或音调,另一个是音长或节拍。本项目研究如何利用蜂鸣器演奏歌曲《世上只有妈妈好》。下图为《世上只有妈妈好》的简谱。

  简谱用来记录、传播音乐的工具。在简谱中,用以表示音的高低及相互关系的基本符号为七个阿拉伯数字,即1、2、3、4、5、6、7,唱作do、re、mi、fa、sol、la、si,称为唱名。

(1)音的高低(音调)

       单用以上七个音是无法表现众多的音乐形象的。在实际作品中,还有一些更高或更低的音,如在基本音符上方加记一个"·",表示该音升高一个八度,称为高音;加记两个" :",则表示该音升高两个八度,称为倍高音。在基本音符下方加记一个"·",表示该音降低一个八度,称为低音;加记两个" :",则表示该音降低两个八度,称为倍低音。在一般歌曲中,无论是在基本音符上方或下方加记两个以上的"·"的音符都是很少见的。

(2)音的长短(音长)

  在简谱中,1、2、3、4、5、6、7这七个基本音符,不仅表示音的高低,而且还是表示时值长短的基本单位,称为四分音符,其他音符均是在四分音符的基础上,用加记短横线"-"和附点"·"表示。简谱中用线(减时线、增时线、连音线)、点(符点音符)休止符来表示音的长短。

  在基本音符右侧加记一条短横线,表示增长一个四分音符的时值。这类加记在音符右侧、使音符时值增长的短横线,称为增时线。增时线越多,音符的时值越长。

  在基本音符下方加记一条短横线,表示缩短原音符时值的一半。这类加记在音符下方、使音符时值缩短的短横线,称为减时线。减时线越多,音符的时值越短。

在简谱中,加记在单纯音符的右侧的、使音符时值增长的小圆点"·",称为附点。加记附点的音符称为附点音符。附点本身并无一定的长短,其长短由前面的单纯音符来决定。附点的意义在于增长原音符时值的一半,常用于四分音符和小于四分音符的各种音符之后。

休止符,用来表示音乐停顿的符号。

                

(3)音的强弱

    曲谱中有规则的竖线,称小节线。作用是划分小节内的拍数,明确节拍音的强弱规律。 拍子是节拍的时值单位,如2/4、3/4、3/8、6/8 等,表示每小节有几拍/几分音符为一拍。如二拍子:   强、弱 | 强、弱 |……,三拍子:   (强、弱、弱 | 强、弱、弱|),四拍子:   (强、弱、次强、弱);等等。

(4)调号与定调

    1234567是do、re、mi、fa、so、la、xi。这是音的唱名。那么音名是,1是C,2是D,3是E,4是F,5是G,6是A,7是B。比如说D调,就会表明,1=D,而D是do re mi的re的音名。所以1=D的意思就是这个调的do就是re的位置。以此类推,所有的音符都会随着do的变化而变化。C调就是没有升降号 12345671。 那G调为一个升号升4 为567123#45 1=G. D调两个#号为23#4567#12 1=D 其它调类似推出。

      

(5)各个音符对应的频率

      在音乐中有十二平均律的规定:每两个八度音之间的频率相差一倍,在两个八度音之间又分为十二个半音,

2.3  架构设计

此设计共分4各模块:

addr_ctrl模块(地址控制模块):每1/4秒让地址进行加1,共有64个音符,故而输出地址采用6位即可。本模块中首先设计1/4秒的计时器。当到1/4秒时,让输出的addr进行变化:小于63时,进行加1操作;等于63时,进行清零操作。此时蜂鸣器将不断的重复播放这个音乐。

music_mem模块(音符存储模块):根据简谱将64个音符存储起来,然后根据外部的地址,将储存的音符进行输出。

music_freq模块(音符转换频率模块):根据输入的音符以及不同音符所对应的频率,输出对应的频率值。

wave_gen模块(产生对应频率的方波):根据输入的频率值,产生对应频率的方波。产生方波的方法采用计时器计时半个周期,然后进行取反。利用时钟的频率(50MHz)除以想要的波形的频率,得出分频比,将分频比除以2,得到半个周期的计数值。

信号

说明

端口/连线

FPGA引脚

clk

系统时钟,50MHz;

输入端口

 

rst_n

复位信号,低电平有效;

输入端口

 

Addr[5:0]

查找音符的地址,存储器存有64个字符,地址线为2^6;

内部连线

 

Music[8:0]

音符,[8:6]为高音,[5:3]为中音,[2:0]为低音;如中音1,编码为000_001_000;

内部连线

 

Freq[10:0]

音符所对应的频率

内部连线

 

beep

对应频率的方波

输出端口

 

3 设计与实现

3.1 地址控制模块

 1 module addr_ctrl(
 2     input     wire                     clk,
 3     input     wire                     rst_n,
 4     output     reg         [5:0]        addr
 5 );
 6 
 7     parameter     T_1S         =     26\'d50_000_000;
 8     localparam    SEC_1_4     =    T_1S/4;
 9     
10     reg         [25:0]    cnt;
11     
12     always@(posedge clk or negedge rst_n)begin
13         if(rst_n == 1\'b0)
14             cnt <= 26\'d0;
15         else begin
16             if(cnt < SEC_1_4 - 1\'b1)
17                 cnt <= cnt + 1\'b1;
18             else
19                 cnt <= 26\'d0;
20         end
21     end
22     
23     always@(posedge clk or negedge rst_n)begin
24         if(rst_n == 1\'b0)
25             addr <= 6\'d0;
26         else if(cnt == SEC_1_4 - 1\'b1)begin
27             if(addr < 6\'d63)
28                 addr <= addr + 1\'b1;
29             else
30                 addr <= 6\'d0;
31         end
32         else
33             addr <= addr;
34     end
35 
36 endmodule 

3.2 音符存储模块

 1 module music_mem(
 2     input     wire                     clk,
 3     input     wire                     rst_n,
 4     input     wire     [5:0]            addr,
 5     output     reg     [8:0]            music
 6 );
 7 
 8     always@(posedge clk or negedge rst_n)begin
 9         if(rst_n == 1\'b0)
10             music <= 9\'b000_000_000;
11         else 
12             case(addr)
13                 6\'d0:     music <= 9\'b000_110_000;
14                 6\'d1:     music <= 9\'b000_110_000;
15                 6\'d2:     music <= 9\'b000_110_000;
16                 6\'d3:     music <= 9\'b000_101_000;
17                 6\'d4:     music <= 9\'b000_011_000;
18                 6\'d5:     music <= 9\'b000_011_000;
19                 6\'d6:     music <= 9\'b000_101_000;
20                 6\'d7:     music <= 9\'b000_101_000;
21                     
22                 6\'d8:     music <= 9\'b001_000_000;
23                 6\'d9:     music <= 9\'b001_000_000;
24                 6\'d10:     music <= 9\'b000_110_000;
25                 6\'d11:     music <= 9\'b000_101_000;
26                 6\'d12:     music <= 9\'b000_110_000;
27                 6\'d13:     music <= 9\'b000_110_000;
28                 6\'d14:     music <= 9\'b000_110_000;
29                 6\'d15:     music <= 9\'b000_110_000;
30                     
31                 6\'d16:     music <= 9\'b000_011_000;
32                 6\'d17:     music <= 9\'b000_011_000;
33                 6\'d18:     music <= 9\'b000_101_000;
34                 6\'d19:     music <= 9\'b000_110_000;
35                 6\'d20:     music <= 9\'b000_101_000;
36                 6\'d21:     music <= 9\'b000_101_000;
37                 6\'d22:     music <= 9\'b000_011_000;
38                 6\'d23:     music <= 9\'b000_011_000;
39                     
40                 6\'d24:     music <= 9\'b000_001_000;
41                 6\'d25:     music <= 9\'b000_000_110;
42                 6\'d26:     music <= 9\'b000_101_000;
43                 6\'d27:     music <= 9\'b000_011_000;
44                 6\'d28:     music <= 9\'b000_010_000;
45                 6\'d29:     music <= 9\'b000_010_000;
46                 6\'d30:     music <= 9\'b000_010_000;
47                 6\'d31:     music <= 9\'b000_010_000;
48                     
49                 6\'d32:     music <= 9\'b000_010_000;
50                 6\'d33:     music <= 9\'b000_010_000;
51                 6\'d34:     music <= 9\'b000_010_000;
52                 6\'d35:     music <= 9\'b000_101_000;
53                 6\'d36:     music <= 9\'b000_110_000;
54                 6\'d37:     music <= 9\'b000_110_000;
55                 6\'d38:     music <= 9\'b000_110_000;
56                 6\'d39:     music <= 9\'b000_110_000;
57                     
58                 6\'d40:     music <= 9\'b000_011_000;
59                 6\'d41:     music <= 9\'b000_011_000;
60                 6\'d42:     music <= 9\'b000_011_000;
61                 6\'d43:     music <= 9\'b000_010_000;
62                 6\'d44:     music <= 9\'b000_001_000;
63                 6\'d45:     music <= 9\'b000_001_000;
64                 6\'d46:     music <= 9\'b000_001_000;
65                 6\'d47:     music <= 9\'b000_001_000;
66                     
67                 6\'d48:     music <= 9\'b000_101_000;
68                 6\'d49:     music <= 9\'b000_101_000;
69                 6\'d50:     music <= 9\'b000_101_000;
70                 6\'d51:     music <= 9\'b000_011_000;
71                 6\'d52:     music <= 9\'b000_010_000;
72                 6\'d53:     music <= 9\'b000_001_000;
73                 6\'d54:     music <= 9\'b000_000_110;
74                 6\'d55:     music <= 9\'b000_001_000;
75                     
76                 6\'d56:     music <= 9\'b000_000_101;
77                 6\'d57:     music <= 9\'b000_000_101;
78                 6\'d58:     music <= 9\'b000_000_101;
79                 6\'d59:     music <= 9\'b000_000_101;
80                 6\'d60:     music <= 9\'b000_000_101;
81                 6\'d61:     music <= 9\'b000_000_101;
82                 6\'d62:     music <= 9\'b000_000_101;
83                 6\'d63:     music <= 9\'b000_000_101;
84                 default: music <= 9\'b000_000_101;
85             endcase
86     end
87 
88 endmodule 

3.3 音符转换频率模块

 1 module music_freq(
 2     input     wire                     clk,
 3     input     wire                     rst_n,
 4     input     wire     [8:0]            music,
 5     output     reg  [10:0]        freq
 6 );
 7 
 8     always@(posedge clk or negedge rst_n)begin
 9         if(rst_n == 1\'b0)
10             freq <= 11\'d1;        //div_freq=sys_clk/(2*freq),freq != 0
11         else
12             case(music)
13                 9\'b000_000_001 :    freq <= 11\'d262;
14                 9\'b000_000_010 :    freq <= 11\'d294;
15                 9\'b000_000_011 :    freq <= 11\'d330;
16                 9\'b000_000_100 :    freq <= 11\'d349;
17                 9\'b000_000_101 :    freq <= 11\'d392;
18                 9\'b000_000_110 :    freq <= 11\'d440;
19                 9\'b000_000_111 :    freq <= 11\'d494;
20                 
21                 9\'b000_001_000 :    freq <= 11\'d523;
22                 9\'b000_010_000 :    freq <= 11\'d587;
23                 9\'b000_011_000 :    freq <= 11\'d659;
24                 9\'b000_100_000 :    freq <= 11\'d699;
25                 9\'b000_101_000 :    freq <= 11\'d784;
26                 9\'b000_110_000 :    freq <= 11\'d880;
27                 9\'b000_111_000 :    freq <= 11\'d988;
28                 
29                 9\'b001_000_000 :    freq <= 11\'d1050;
30                 9\'b010_000_000 :    freq <= 11\'d1175;
31                 9\'b011_000_000 :    freq <= 11\'d1319;
32                 9\'b100_000_000 :    freq <= 11\'d1397;
33                 9\'b101_000_000 :    freq <= 11\'d1568;
34                 9\'b110_000_000 :    freq <= 11\'d1760;
35                 9\'b111_000_000 :    freq <= 11\'d1976;                    
36                 default:                freq <= 11\'d1;
37             endcase
38     end
39     
40 endmodule 

3.4 波形产生模块

 1 module wave_gen(
 2     input     wire                     clk,
 3     input     wire                     rst_n,
 4     input     wire  [10:0]        freq,
 5     output     reg                     beep
 6 );
 7     
 8     parameter         F_CLK     = 50_000_000;
 9     
10     wire         [25:0]            half;
11     reg         [25:0]            cnt;
12     
13     assign half = F_CLK /(2*freq);
14     
15     always@(posedge clk or negedge rst_n)begin
16         if(rst_n == 1\'b0)
17             cnt <= 26\'d0;
18         else
19             if(cnt < half - 1\'b1)
20                 cnt <= cnt + 1\'b1;
21             else
22                 cnt <= 26\'d0;
23     end
24     
25     always@(posedge clk or negedge rst_n)begin
26         if(rst_n == 1\'b0)
27             beep <= 1\'b0;
28         else
29             if(cnt == half - 1\'b1)
30                 beep <= ~beep;
31             else
32                 beep <= beep;
33     end
34 
35 endmodule 

3.5 顶层模块

 1 module music_beep(
 2     input     wire                 clk,
 3     input     wire                 rst_n,
 4     output     wire                 beep
 5 );
 6     
 7     wire        [5:0]        addr;
 8     wire         [8:0]        music;
 9     wire         [10:0]    freq;
10     
11     addr_ctrl addr_ctrl_inst(
12         .clk                (clk),
13         .rst_n            (rst_n),
14         .addr                (addr)
15     );
16     
17     music_mem music_mem_inst(
18         .clk                (clk),
19         .rst_n            (rst_n),
20         .addr                (addr),
21         .music            (music)
22     );
23     
24     music_freq music_freq_inst(
25         .clk                (clk),
26         .rst_n            (rst_n),
27         .music            (music),
28         .freq                (freq)
29     );
30     
31     wave_gen wave_gen_inst(
32         .clk                (clk),
33         .rst_n            (rst_n),
34         .freq                (freq),
35         .beep                (beep)
36     );
37     
38 endmodule 

4 仿真与验证

4.1 地址控制模块的仿真

 1 `timescale 1ns/1ps
 2 
 3 module addr_ctrl_tb();
 4 
 5     reg                         clk;
 6     reg                         rst_n;
 7     wire            [5:0]        addr;
 8 
 9     addr_ctrl addr_ctrl_inst(
10         .clk                (clk),
11         .rst_n            (rst_n),
12         .addr                (addr)
13     );
14     
15     defparam addr_ctrl_inst.T_1S = 20;
16     
17     initial clk = 1\'b0;
18     always #10 clk = ~clk;
19     
20     initial begin
21         rst_n = 1\'b0; #51;
22         rst_n = 1\'b1;
23         #(20*4*200);
24         $stop;    
25     end
26 
27 endmodule 

4.2 顶层模块仿真测试

 1 `timescale 1ns/1ps
 2 
 3 module music_beep_tb();
 4 
 5     reg                     clk;
 6     reg                     rst_n;
 7     wire                     beep;
 8     
 9     music_beep music_beep_inst(
10         .clk                (clk),
11         .rst_n            (rst_n),
12         .beep                (beep)
13     );
14     
15     initial clk = 1\'b0;
16     always #10 clk = ~clk;
17     
18     initial begin
19         rst_n = 1\'b0;
20         #21; rst_n = 1\'b1;
21         #1_000_000_000;
22         $stop;
23     end
24 
25 endmodule 

 

5 参考文献

(1)FPGA零基础学习:基于FPGA的音乐蜂鸣器设计(附代码) - 知乎 (zhihu.com)

(2)怎样识简谱分析 - 百度文库 (baidu.com)

分类:

技术点:

相关文章: