設(shè)計規(guī)劃
驅(qū)動無源蜂鳴器進行七個基本音調(diào)“哆來咪發(fā)梭拉西”的循環(huán)鳴叫,每個音階持續(xù)鳴叫0.5s后鳴叫下一個音階。
對于無源蜂鳴器,輸入不同的PWM方波就能發(fā)出不同的聲音。方波的頻率影響音調(diào),占空比影響音量。音調(diào)頻率對應表格如下,占空比保持為50%。因此這個實驗我們只要循環(huán)產(chǎn)生占空比為50%的七個音調(diào)頻率即可。
Do | Re | Mi | Fa | So | La | Si |
---|---|---|---|---|---|---|
262 | 294 | 330 | 349 | 392 | 440 | 494 |
現(xiàn)在我們考慮,除了時鐘和復位,需要幾個計數(shù)器:
1、蜂鳴維持0.5s,(50MHz對應20ns)計數(shù)從0-24999999,計數(shù)器名稱cnt。
2、需要蜂鳴7個調(diào),狀態(tài)計數(shù)從0-6,cnt計滿一次就+1,計數(shù)器名稱cnt_500ms。
3、不同的調(diào)對應不同頻率,需要一個頻率計數(shù)器freq_cnt。
以Do為例,頻率為262,周期為1/262=3.816794ms。時鐘頻率50MHz,對應周期是20ns,即計數(shù)個數(shù)為190840個,對應do的freq_cnt計數(shù)從0-190839。占空比為50%,即高電平和低電平的時長一樣,高電平持續(xù)時鐘脈沖個數(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和占空比計數(shù)duty_data,就可以得到不同頻率的波形。
編寫代碼
module beep
#(
parameter TIME_500MS = 25'd24999, //0.5s計數(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計數(shù)器
reg [17:0] freq_cnt ; //音調(diào)計數(shù)器
reg [2:0] cnt_500ms ; //0.5s個數(shù)計數(shù)
reg [17:0] freq_data ; //音調(diào)分頻計數(shù)值,取不同的DO,RE...可以得到不同頻率的波形
//wire define
wire [16:0] duty_data ; //占空比計數(shù)值,即DO,RE...的一半
assign duty_data = freq_data > > 1'b1; //二進制右移一位就是原值的1/2
//cnt:0.5s循環(huán)計數(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:對500ms個數(shù)進行計數(shù),每個音階鳴叫時間0.5s,7個音節(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;
//不同時間鳴叫不同的音階
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:當計數(shù)到音階計數(shù)值或跳轉(zhuǎn)到下一音階時,開始重新計數(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