基於FPGA的音樂蜂鳴器設計與實現


 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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM