蜂鳴器是一種一體化結構的電子訊響器,采用直流電壓供電,廣泛應用於計算機、打印機、復印機、報警器、電子玩具、汽車電子設備、電話機、定時器等電子產品中作發聲器件。
圖1 :蜂鳴器實物圖
蜂鳴器主要分為壓電式蜂鳴器和電磁式蜂鳴器兩種類型。
壓電式蜂鳴器 壓電式蜂鳴器主要由多諧振盪器、壓電蜂鳴片、阻抗匹配器及共鳴箱、外殼等組成。有的壓電式蜂鳴器外殼上還裝有發光二極管。多諧振盪器由晶體管或集成電路構成。當接通電源后(1.5~15V直流工作電壓),多諧振盪器起振,輸出1.5~2.5kHZ的音頻信號,阻抗匹配器推動壓電蜂鳴片發聲。
電磁式蜂鳴器電磁式蜂鳴器由振盪器、電磁線圈、磁鐵、振動膜片及外殼等組成。接通電源后,振盪器產生的音頻信號電流通過電磁線圈,使電磁線圈產生磁場。振動膜片在電磁線圈和磁鐵的相互作用下,周期性地振動發聲。
按照內部有無震盪源可以分為有源蜂鳴器和無源蜂鳴器。有源蜂鳴器內部帶震盪源,所以只要一通電就會發出聲音;而無源內部不帶震盪源,所以如果用直流信號無法令其鳴叫。必須用一定頻率的方波去驅動它。
首先設計分頻器,設計一個1KHz的方波,驅動蜂鳴器,觀測蜂鳴器是否會有聲音產生。
本小節研究如何利用蜂鳴器演唱一首曲子《世上只有媽媽好》。
下圖為《世上只有媽媽好》的簡譜。
圖2:世上只有媽媽好的簡譜
簡譜是一種比較簡單易學的音樂記譜法。據說簡譜是由法國思想家盧梭於1742年發明的。而最早把簡譜引進我國的是我國近代音樂教育家沈心工。簡譜應該說是一種比較簡單易學的音樂記譜法。它的最大好處是僅用7個阿拉伯數字----1234567,就能將萬千變化的音樂曲子記錄並表示出來.
在簡譜中,用以表示音的高低及相互關系的基本符號為七個阿拉伯數字,即1、2、3、4、5、6、7,唱作do、re、mi、fa、sol、la、si,稱為唱名。
音符:1234567
唱名:do re mi fa sol la si
漢字:哆來米發梭拉西
顯然,單用以上七個音是無法表現眾多的音樂形象的。在實際作品中,還有一些更高或更低的音,如在基本音符上方加記一個"·",表示該音升高一個八度,稱為高音;加記兩個" :",則表示該音升高兩個八度,稱為倍高音。在基本音符下方加記一個"·",表示該音降低一個八度,稱為低音;加記兩個" :",則表示該音降低兩個八度,稱為倍低音。
在一般歌曲中,無論是在基本音符上方或下方加記兩個以上的"·"的音符都是很少見的。
在簡譜中,1、2、3、4、5、6、7這七個基本音符,不僅表示音的高低,而且還是表示時值長短的基本單位,稱為四分音符,其他音符均是在四分音符的基礎上,用加記短橫線"-"和附點"·"表示。
在基本音符右側加記一條短橫線,表示增長一個四分音符的時值。這類加記在音符右側、使音符時值增長的短橫線,稱為增時線。增時線越多,音符的時值越長。
在基本音符下方加記一條短橫線,表示縮短原音符時值的一半。這類加記在音符下方、使音符時值縮短的短橫線,稱為減時線。減時線越多,音符的時值越短。
在簡譜中,加記在單純音符的右側的、使音符時值增長的小圓點"·",稱為附點。加記附點的音符稱為附點音符。附點本身並無一定的長短,其長短由前面的單純音符來決定。附點的意義在於增長原音符時值的一半,常用於四分音符和小於四分音符的各種音符之后。
在《世上只有媽媽好》的簡譜中,每兩個豎線之間為2秒鍾的時長。每兩個豎線之間有4個音符時長,但是其中有較多半個音符的長,本設計采用1/4秒為基本單位。
蜂鳴器給予不同的頻率是可以發出近似1、2、3、4、5、6、7這七個基本音符。
圖3 :各個音符所對應的頻率
此模塊命名為music_beep,clk為50MHz的時鍾,rst_n為低電平有效的復位,beep為蜂鳴器的驅動信號。
圖4 :music_beep的模型
在設計時,首先將簡譜中的音符存起來;利用計數器產生1/4秒為周期的脈沖,在此脈沖驅動下,將事先存好的音符一個個輸出;根據音符的值,計算出分頻比;根據分頻比,產生對應頻率的波形。將此波形輸出即可。
圖5 :架構圖
在進行多模塊設計時,可以對每個模塊只設計端口,將架構完成后。再分別設計每個模塊。
《世上只有媽媽好》的簡譜中共有8個四拍,每個四拍我們用8個音符來表示,合計共64個音符。在speed_ctrl中,輸出的cnt為6位,正好可以表示64個狀態。
在speed_ctrl中,每1/8秒讓cnt增加1即可。
module speed_ctrl (
input wire clk, input wire rst_n,
output reg [5:0] cnt );
parameter T_250ms = 12_500_000;
reg [25:0] count; wire flag_250ms;
always @ (posedge clk, negedge rst_n) begin if (rst_n == 1'b0) count <= 26'd0; else if (count < T_250ms - 1'b1) count <= count + 1'b1; else count <= 26'd0; end
assign flag_250ms = (count == T_250ms - 1'b1) ? 1'b1 : 1'b0;
always @ (posedge clk, negedge rst_n) begin if (rst_n == 1'b0) cnt <= 6'd0; else if (flag_250ms == 1'b1) cnt <= cnt + 1'b1; else cnt <= cnt; end
endmodule |
圖6:speed_ctrl的設計代碼
在music_mem中存儲音符,存儲方式為低音用1到7表示,中音用8到14表示,高音用15到21表示,music為5bit位寬。
module music_mem (
input wire clk, input wire rst_n,
input wire [5:0] cnt,
output reg [4:0] music ); // 1 2 3 4 5 6 7 // 8 9 10 11 12 13 14 // 15 16 17 18 19 20 21
always @ (posedge clk, negedge rst_n) begin if (rst_n == 1'b0) music <= 5'd0; else case (cnt) 6'd0 : music <= 5'd13; 6'd1 : music <= 5'd13; 6'd2 : music <= 5'd13; 6'd3 : music <= 5'd12; 6'd4 : music <= 5'd10; 6'd5 : music <= 5'd10; 6'd6 : music <= 5'd12; 6'd7 : music <= 5'd12;
6'd8 : music <= 5'd15; 6'd9 : music <= 5'd15; 6'd10 : music <= 5'd13; 6'd11 : music <= 5'd12; 6'd12 : music <= 5'd13; 6'd13 : music <= 5'd13; 6'd14 : music <= 5'd13; 6'd15 : music <= 5'd13;
6'd16 : music <= 5'd10; 6'd17 : music <= 5'd10; 6'd18 : music <= 5'd12; 6'd19 : music <= 5'd13; 6'd20 : music <= 5'd12; 6'd21 : music <= 5'd12; 6'd22 : music <= 5'd10; 6'd23 : music <= 5'd10;
6'd24 : music <= 5'd8; 6'd25 : music <= 5'd6; 6'd26 : music <= 5'd12; 6'd27 : music <= 5'd10; 6'd28 : music <= 5'd9; 6'd29 : music <= 5'd9; 6'd30 : music <= 5'd9; 6'd31 : music <= 5'd9;
6'd32 : music <= 5'd9; 6'd33 : music <= 5'd9; 6'd34 : music <= 5'd9; 6'd35 : music <= 5'd10; 6'd36 : music <= 5'd12; 6'd37 : music <= 5'd12; 6'd38 : music <= 5'd13; 6'd39 : music <= 5'd13;
6'd40 : music <= 5'd10; 6'd41 : music <= 5'd10; 6'd42 : music <= 5'd10; 6'd43 : music <= 5'd9; 6'd44 : music <= 5'd8; 6'd45 : music <= 5'd8; 6'd46 : music <= 5'd8; 6'd47 : music <= 5'd8;
6'd48 : music <= 5'd12; 6'd49 : music <= 5'd12; 6'd50 : music <= 5'd12; 6'd51 : music <= 5'd10; 6'd52 : music <= 5'd9; 6'd53 : music <= 5'd8; 6'd54 : music <= 5'd6; 6'd55 : music <= 5'd8;
6'd56 : music <= 5'd5; 6'd57 : music <= 5'd5; 6'd58 : music <= 5'd5; 6'd59 : music <= 5'd5; 6'd60 : music <= 5'd5; 6'd61 : music <= 5'd5; 6'd62 : music <= 5'd5; 6'd63 : music <= 5'd5; default : music <= 5'd0; endcase end
endmodule |
圖7 :music_mem的設計代碼
根據頻率和音符的關系,將音符對應的頻率值取出來,根據頻率值算出分頻比。驅動時鍾為50MHz,所以分頻比為50M除以頻率。
module cal_divnum (
input wire clk, input wire rst_n,
input wire [4:0] music,
output reg [31:0] divnum );
reg [31:0] freq;
always @ * begin case (music) 5'd1 : freq = 32'd262; 5'd2 : freq = 32'd294; 5'd3 : freq = 32'd330; 5'd4 : freq = 32'd349; 5'd5 : freq = 32'd392; 5'd6 : freq = 32'd440; 5'd7 : freq = 32'd494;
5'd8 : freq = 32'd523; 5'd9 : freq = 32'd587; 5'd10 : freq = 32'd659; 5'd11 : freq = 32'd699; 5'd12 : freq = 32'd784; 5'd13 : freq = 32'd880; 5'd14 : freq = 32'd988;
5'd15 : freq = 32'd1050; 5'd16 : freq = 32'd1175; 5'd17 : freq = 32'd1319; 5'd18 : freq = 32'd1397; 5'd19 : freq = 32'd1568; 5'd20 : freq = 32'd1760; 5'd21 : freq = 32'd1976; default : freq = 32'd1; endcase end
always @ (posedge clk, negedge rst_n) begin if (rst_n == 1'b0) divnum <= 32'd50_000_000; else divnum <= 50_000_000/freq; end
endmodule |
圖8 :cal_divmum的設計代碼
知道分頻數后,利用任意分頻的方式,產生對的波形即可。
module wave_gen (
input wire clk, input wire rst_n,
input wire [31:0] divnum,
output reg beep );
reg [31:0] cnt;
always @ (posedge clk, negedge rst_n) begin if (rst_n == 1'b0) cnt <= 32'd0; else if (cnt < divnum - 1'b1) cnt <= cnt + 1'b1; else cnt <= 32'd0; end
always @ (posedge clk, negedge rst_n) begin if (rst_n == 1'b0) beep <= 1'b0; else if (cnt < divnum[31:1]) beep <= 1'b0; else beep <= 1'b1; end
endmodule |
圖9 :wave_gen的設計代碼
設計好上述四個模塊后,將它們之前設計架構的連接方式,連接起來。
module music_beep (
input wire clk, input wire rst_n,
output wire beep );
wire [5:0] cnt; wire [4:0] music; wire [31:0] divnum;
speed_ctrl speed_ctrl_inst(
.clk (clk), .rst_n (rst_n),
.cnt (cnt) );
music_mem music_mem_inst(
.clk (clk), .rst_n (rst_n),
.cnt (cnt),
.music (music) );
cal_divnum cal_divnum_inst(
.clk (clk), .rst_n (rst_n),
.music (music),
.divnum (divnum) );
wave_gen wave_gen_inst(
.clk (clk), .rst_n (rst_n),
.divnum (divnum),
.beep (beep) );
endmodule |
圖10 :music_beep的設計代碼
RTL視圖如下,和所設計架構相同。
圖11 :RTL視圖
在testbench中,將speed_ctrl_inst模塊中的T_250ms改成10。
defparam可以重新定義參數。
`timescale 1ns/1ps
module music_beep_tb;
reg clk; reg rst_n;
wire beep;
defparam music_beep_inst.speed_ctrl_inst.T_250ms = 10;
music_beep music_beep_inst(
.clk (clk), .rst_n (rst_n),
.beep (beep) );
initial clk = 1'b0; always # 10 clk = ~clk;
initial begin rst_n = 1'b0; # 200 @ (posedge clk); # 2; rst_n = 1'b1;
# 20000; $stop; end
endmodule |
圖12 :testbench代碼
由於輸出的頻率都較低,所以仿真時間都很長。
將參數改小,也只是加快切換輸出音符的頻率。由於wave_gen模塊和分頻模塊相同,故而不在驗證。只看RTL視圖中,分頻數是不是正確即可。
圖13 :RTL視圖
在RTL視圖中,也看到cnt每10個周期增長1,然后對應輸出音符。音符得出頻率,根據頻率得出分頻數。經過驗證,數據都是正確的。
分配管腳,全編譯形成下載文件,下板后就可以聽到《世上只有媽媽好》的歌曲了。
通過更改speed_crtl中的控制音符前進的速度,可以控制播放的速度。如果將速度控制到1/2秒的話,那么聽到的歌曲將會變慢。如果將速度控制到1/8秒的話,那么聽到的歌曲將會變快。
設計者:郝旭帥 QQ:746833924 QQ交流群: 173560979