設(shè)計(jì)規(guī)劃
驅(qū)動(dòng)無(wú)源蜂鳴器進(jìn)行七個(gè)基本音調(diào)“哆來(lái)咪發(fā)梭拉西”的循環(huán)鳴叫,每個(gè)音階持續(xù)鳴叫0.5s后鳴叫下一個(gè)音階。
對(duì)于無(wú)源蜂鳴器,輸入不同的PWM方波就能發(fā)出不同的聲音。方波的頻率影響音調(diào),占空比影響音量。音調(diào)頻率對(duì)應(yīng)表格如下,占空比保持為50%。因此這個(gè)實(shí)驗(yàn)我們只要循環(huán)產(chǎn)生占空比為50%的七個(gè)音調(diào)頻率即可。
Do | Re | Mi | Fa | So | La | Si |
---|---|---|---|---|---|---|
262 | 294 | 330 | 349 | 392 | 440 | 494 |
現(xiàn)在我們考慮,除了時(shí)鐘和復(fù)位,需要幾個(gè)計(jì)數(shù)器:
1、蜂鳴維持0.5s,(50MHz對(duì)應(yīng)20ns)計(jì)數(shù)從0-24999999,計(jì)數(shù)器名稱cnt。
2、需要蜂鳴7個(gè)調(diào),狀態(tài)計(jì)數(shù)從0-6,cnt計(jì)滿一次就+1,計(jì)數(shù)器名稱cnt_500ms。
3、不同的調(diào)對(duì)應(yīng)不同頻率,需要一個(gè)頻率計(jì)數(shù)器freq_cnt。
以Do為例,頻率為262,周期為1/262=3.816794ms。時(shí)鐘頻率50MHz,對(duì)應(yīng)周期是20ns,即計(jì)數(shù)個(gè)數(shù)為190840個(gè),對(duì)應(yīng)do的freq_cnt計(jì)數(shù)從0-190839。占空比為50%,即高電平和低電平的時(shí)長(zhǎng)一樣,高電平持續(xù)時(shí)鐘脈沖個(gè)數(shù)為95420。
頻率 | 262 | 294 | 330 | 349 | 392 | 440 | 494 |
---|---|---|---|---|---|---|---|
頻率數(shù)值 | 190840 | 170068 | 151515 | 143266 | 127551 | 113636 | 101214 |
占空比數(shù)值 | 95420 | 85034 | 75757 | 71633 | 63775 | 56818 | 50607 |
以Re為例的波形圖:
改變頻率數(shù)值freq_data和占空比計(jì)數(shù)duty_data,就可以得到不同頻率的波形。
編寫代碼
module beep
#(
parameter TIME_500MS = 25'd24999, //0.5s計(jì)數(shù)值
parameter DO = 18'd190 , //Do頻率262
parameter RE = 18'd170 , //Re頻率294
parameter MI = 18'd151 , //Mi頻率330
parameter FA = 18'd143 , //Fa頻率349
parameter SO = 18'd127 , //So頻率392
parameter LA = 18'd113 , //La頻率440
parameter XI = 18'd101 //Si頻率494
)
(
input wire sys_clk ,
input wire sys_rst_n ,
output reg beep
);
//reg define
reg [24:0] cnt ; //0.5s計(jì)數(shù)器
reg [17:0] freq_cnt ; //音調(diào)計(jì)數(shù)器
reg [2:0] cnt_500ms ; //0.5s個(gè)數(shù)計(jì)數(shù)
reg [17:0] freq_data ; //音調(diào)分頻計(jì)數(shù)值,取不同的DO,RE...可以得到不同頻率的波形
//wire define
wire [16:0] duty_data ; //占空比計(jì)數(shù)值,即DO,RE...的一半
assign duty_data = freq_data > > 1'b1; //二進(jìn)制右移一位就是原值的1/2
//cnt:0.5s循環(huán)計(jì)數(shù)器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 25'd0;
else if(cnt == TIME_500MS )
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
//cnt_500ms:對(duì)500ms個(gè)數(shù)進(jìn)行計(jì)數(shù),每個(gè)音階鳴叫時(shí)間0.5s,7個(gè)音節(jié)一循環(huán)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_500ms <= 3'd0;
else if(cnt == TIME_500MS && cnt_500ms == 6)
cnt_500ms <= 3'd0;
else if(cnt == TIME_500MS)
cnt_500ms <= cnt_500ms + 1'b1;
//不同時(shí)間鳴叫不同的音階
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
freq_data <= DO;
else case(cnt_500ms)
0: freq_data <= DO;
1: freq_data <= RE;
2: freq_data <= MI;
3: freq_data <= FA;
4: freq_data <= SO;
5: freq_data <= LA;
6: freq_data <= XI;
default: freq_data <= DO;
endcase
//freq_cnt:當(dāng)計(jì)數(shù)到音階計(jì)數(shù)值或跳轉(zhuǎn)到下一音階時(shí),開(kāi)始重新計(jì)數(shù)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
freq_cnt <= 18'd0;
else if(freq_cnt == freq_data || cnt == TIME_500MS)
freq_cnt <= 18'd0;
else
freq_cnt <= freq_cnt + 1'b1;
//beep:輸出蜂鳴器波形
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
beep <= 1'b0;
else if(freq_cnt >= duty_data)
beep <= 1'b1;
else
beep <= 1'b0;
endmodule