文章目錄
前言
一、蜂鳴器簡(jiǎn)介
二、音頻音符簡(jiǎn)介
三、任務(wù)要求
四、程序設(shè)計(jì)
1、設(shè)計(jì)思路
?2、程序代碼? ?
總結(jié)
前言
? ? ? ? 蜂鳴器(Buzzer)是現(xiàn)代常用的一種電子發(fā)聲器,主要用于產(chǎn)生聲音信號(hào)。它是一種一體化結(jié)構(gòu)的電子訊響器,采用直流電壓供電,被廣泛用于計(jì)算機(jī)、報(bào)警器、電子玩具、定時(shí)器等一些列電子產(chǎn)品中。
一、蜂鳴器簡(jiǎn)介
? ? ? ? 蜂鳴器按照其驅(qū)動(dòng)方式不同主要分為有源蜂鳴器和無(wú)源蜂鳴器,兩者的主要區(qū)別為蜂鳴器內(nèi)部是否還有振蕩源。一般有源蜂鳴器內(nèi)部自帶振蕩源,通電就會(huì)發(fā)聲,而無(wú)源蜂鳴器內(nèi)部不含振蕩源,需要外接振蕩信號(hào)才能發(fā)聲。
? ? ? ? 相較于有源蜂鳴器,無(wú)源蜂鳴器的成本較低,而我們FPGA開發(fā)板上的蜂鳴器一般都是無(wú)源蜂鳴器,需要我們對(duì)其進(jìn)行編程配置,我們利用不同的頻率變化,控制蜂鳴器發(fā)出不同音調(diào)的聲音。
二、音頻音符簡(jiǎn)介
? ? ? ? 我們是通過(guò)不同的頻率去控制蜂鳴器的音調(diào)變化的,所以我們想要使蜂鳴器播放音樂,首先我們要直到不同音符所對(duì)應(yīng)的頻率,下面是低、中、高音下不同音符的頻率對(duì)應(yīng)表:
?????????根據(jù)上圖可以計(jì)算出不同音符振動(dòng)的周期,我所采用的Cyclong IV開發(fā)板上的晶振時(shí)鐘為50MHZ,每一個(gè)周期就是20ns。那么每個(gè)音調(diào)的分頻系數(shù)為:50 000 000 / 音調(diào)頻率(可四舍五入)。
三、任務(wù)要求
? ? ? ? 本次設(shè)計(jì)的要求就是利用FPGA開發(fā)板上的無(wú)源蜂鳴器,通過(guò)不同振動(dòng)頻率播放歌曲兩只老虎。
?
四、程序設(shè)計(jì)
1、設(shè)計(jì)思路
? ? ? ? ① 首先我們需要計(jì)算出每個(gè)不同的音符對(duì)應(yīng)的分頻系數(shù),由此產(chǎn)生不同的音調(diào),我們需要設(shè)計(jì)一個(gè)分頻計(jì)數(shù)器,來(lái)計(jì)數(shù)當(dāng)前發(fā)出音調(diào)的分頻系數(shù)。
? ? ? ? ② 然后我們需要一個(gè)節(jié)拍計(jì)數(shù)器,我們定義為半拍300ms,一拍500ms。
? ? ? ? ③ 利用組合邏輯case語(yǔ)句進(jìn)行設(shè)計(jì),將需要的節(jié)拍和要發(fā)出的音調(diào)寫入case語(yǔ)句中。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-502444.html
?2、程序代碼? ?
/*========================================*
filename : beep_music.v
description : 無(wú)源蜂鳴器播放音樂實(shí)驗(yàn)
time : 2022-11-010
author : 卡夫卡與海
*========================================*/
module beep_music(
input clk ,//系統(tǒng)時(shí)鐘 50MHZ
input rst_n ,//系統(tǒng)復(fù)位
output reg beep //蜂鳴器控制信號(hào)
);
//參數(shù)定義
//每個(gè)音符震動(dòng)一次所占用的時(shí)鐘周期
//低音
parameter MIN_DO = 18'd190800,//(50_000_000/262)
MIN_RE = 18'd170050,//(50_000_000/294)
MIN_MI = 18'd151500,//(50_000_000/330)
MIN_FA = 18'd143250,//(50_000_000/349)
MIN_SO = 18'd127550,//(50_000_000/392)
MIN_LA = 18'd113600,//(50_000_000/440)
MIN_XI = 18'd101200;//(50_000_000/494)
//中音
parameter MID_DO = 17'd95600,//(50_000_000/523)
MID_RE = 17'd85150,//(50_000_000/587)
MID_MI = 17'd75850,//(50_000_000/659)
MID_FA = 17'd71600,//(50_000_000/698)
MID_SO = 17'd63750,//(50_000_000/784)
MID_LA = 17'd56800,//(50_000_000/880)
MID_XI = 17'd50600;//(50_000_000/988)
//高音
parameter MAX_DO = 16'd47755,//(50_000_000/1047)
MAX_RE = 16'd42553,//(50_000_000/1175)
MAX_MI = 16'd37907,//(50_000_000/1319)
MAX_FA = 16'd35790,//(50_000_000/1397)
MAX_SO = 16'd31887,//(50_000_000/1568)
MAX_LA = 16'd28409,//(50_000_000/1760)
MAX_XI = 16'd25419;//(50_000_000/1967)
parameter TIME_300ms = 24'd14_999_999,//300ms,半拍
TIME_500ms = 25'd24_999_999;//500ms,一拍
parameter NOTE_NUM = 6'd33;//音符個(gè)數(shù) 34個(gè)
//信號(hào)定義
reg [24:0] cnt_delay ;//300ms或500ms計(jì)數(shù)器
reg [5:0] cnt_note ;//音符計(jì)數(shù)器
reg [18:0] cnt_freq ;//音符播放計(jì)數(shù)器
reg [18:0] freq_data ;//音符數(shù)據(jù)寄存器
wire [17:0] duty_data ;//占空比
wire end_note ;//單個(gè)音符播放結(jié)束標(biāo)志
wire end_flag ;//所有音符結(jié)束標(biāo)志
reg [24:0] cnt_delay_r ;
reg flag ;//蜂鳴器輸出標(biāo)志
//300ms計(jì)數(shù)器 cnt_delay
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_delay <= 25'd0;
end
else if(cnt_delay == cnt_delay_r)begin
cnt_delay <= 25'd0;
end
else begin
cnt_delay <= cnt_delay + 1'b1;
end
end
//音符計(jì)數(shù)器 cnt_note
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_note <= 6'd0;
end
else if(end_flag)begin
cnt_note <= 6'd0;
end
else if(cnt_delay == cnt_delay_r)begin
cnt_note <= cnt_note + 1'b1;
end
else begin
cnt_note <= cnt_note;
end
end
//所有音符結(jié)束標(biāo)志 end_flag
assign end_flag = cnt_note == NOTE_NUM && cnt_delay == cnt_delay_r;
//單個(gè)音符振動(dòng)周期 cnt_freq
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_freq <= 19'd1;
end
else if(end_note)begin
cnt_freq <= 19'd1;
end
else begin
cnt_freq <= cnt_freq + 1'b1;
end
end
//單個(gè)音符結(jié)束標(biāo)志 end_note
assign end_note = (cnt_freq == freq_data);
//音符數(shù)據(jù)選擇 freq_data
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
freq_data <= MAX_DO;
end
else begin
case(cnt_note)
6'd0:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
6'd1:begin
freq_data <= MID_RE;
cnt_delay_r <= TIME_300ms;
end
6'd2:begin
freq_data <= MID_MI;
cnt_delay_r <= TIME_300ms;
end
6'd3:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
6'd4:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
6'd5:begin
freq_data <= MID_RE;
cnt_delay_r <= TIME_300ms;
end
6'd6:begin
freq_data <= MID_MI;
cnt_delay_r <= TIME_300ms;
end
6'd7:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
6'd8:begin
freq_data <= MID_MI;
cnt_delay_r <= TIME_300ms;
end
6'd9:begin
freq_data <= MID_FA;
cnt_delay_r <= TIME_300ms;
end
6'd10:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_500ms;
end
6'd11:begin
freq_data <= MID_MI;
cnt_delay_r <= TIME_300ms;
end
6'd12:begin
freq_data <= MID_FA;
cnt_delay_r <= TIME_300ms;
end
6'd13:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_500ms;
end
6'd14:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_300ms;
end
6'd15:begin
freq_data <= MID_LA;
cnt_delay_r <= TIME_300ms;
end
6'd16:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_300ms;
end
6'd17:begin
freq_data <= MID_FA;
cnt_delay_r <= TIME_500ms;
end
6'd18:begin
freq_data <= MID_MI;
cnt_delay_r <= TIME_500ms;
end
6'd19:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
6'd20:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_300ms;
end
6'd21:begin
freq_data <= MID_LA;
cnt_delay_r <= TIME_300ms;
end
6'd22:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_300ms;
end
6'd23:begin
freq_data <= MID_FA;
cnt_delay_r <= TIME_500ms;
end
6'd24:begin
freq_data <= MID_MI;
cnt_delay_r <= TIME_500ms;
end
6'd25:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
6'd26:begin
freq_data <= MID_RE;
cnt_delay_r <= TIME_500ms;
end
6'd27:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_500ms;
end
6'd28:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_500ms;
end
6'd29:begin
freq_data <= 1'b0;
cnt_delay_r <= TIME_500ms;
end
6'd30:begin
freq_data <= MID_RE;
cnt_delay_r <= TIME_500ms;
end
6'd31:begin
freq_data <= MID_SO;
cnt_delay_r <= TIME_500ms;
end
6'd32:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_500ms;
end
6'd33:begin
freq_data <= 1'b0;
cnt_delay_r <= TIME_500ms;
end
default:begin
freq_data <= MID_DO;
cnt_delay_r <= TIME_300ms;
end
endcase
end
end
//占空比 duty_data
assign duty_data = freq_data >> 3;//移位越多,占空比越高
// flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag <= 1'b0;
end
else begin
flag <= (cnt_freq >= duty_data) ? 1'b1 : 1'b0;
end
end
//輸出 beep
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
beep <= 1'b0;
end
else if(flag)begin
beep <= 1'b1;
end
else begin
beep <= 1'b0;
end
end
endmodule
總結(jié)
? ? ? ? 這個(gè)原理還是挺簡(jiǎn)單的,如果感興趣的話還可以嘗試這去寫更復(fù)雜的音樂,但是這個(gè)蜂鳴器的聲音真正不是很友好,如果能加一個(gè)音頻轉(zhuǎn)換器效果應(yīng)該會(huì)好很多。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-502444.html
到了這里,關(guān)于【FPGA】五、蜂鳴器播放音樂的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!