????????本次設(shè)計是基于FPGA的電子琴,設(shè)計要求如下:
?????????本次我采用modelsim仿真的方式驗證設(shè)計功能的正確性。工作時鐘選擇50MHZ。
????????所謂電子琴,本質(zhì)就是用按鍵控制蜂鳴器發(fā)出不同頻率的聲音。我們平時所接觸的音樂,從低音到高音,從哆瑞咪發(fā)到嗦啦西,都有相應(yīng)的頻率與之對應(yīng)。音符與頻率對應(yīng)關(guān)系如下:
?????????所以整個設(shè)計的思路就是,按下按鍵,控制蜂鳴器的管腳產(chǎn)生相應(yīng)頻率的方波即可。下面首先給出整個設(shè)計的總體rtl視圖,然后再根據(jù)此圖講解各個模塊
????????
?????????首先,clock_gen模塊的作用就是對系統(tǒng)時鐘進行分頻,系統(tǒng)時鐘是50M,分頻產(chǎn)生兩個時鐘,一個1M,一個1K。具體代碼如下所示,分頻細節(jié)不做具體介紹。
????????
module clock_gen(
input clk, //50M時鐘
input rst_n,
output reg clk_1M,
output reg clk_1k
);
parameter div_factor_1MHz = 6'd25; //1MHz 分頻系數(shù)
parameter div_factor_1K = 9'd500; //1K 分頻系數(shù)
reg [15:0] cnt1;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)begin
cnt1 <= 0;
clk_1M <= 0;
end else
if(cnt1 == div_factor_1MHz-1)begin
cnt1 <= 1'b0;
clk_1M <= ~ clk_1M;
end else
cnt1 <= cnt1 + 1'b1;
end
reg [8:0] cnt2;
always @ (posedge clk_1M or negedge rst_n)
begin
if (!rst_n)begin
cnt2 <= 0;
clk_1k <= 0;
end else
if(cnt2 == div_factor_1K-1)begin
cnt2 <= 1'b0;
clk_1k <= ~clk_1k;
end else
cnt2 <= cnt2 + 1'b1;
end
endmodule
????????Key_input模塊,以1KHZ信號為驅(qū)動時鐘,處理按鍵信息,將按鍵輸入的信息經(jīng)過延時消抖以后,再編碼輸出。按鍵默認電平為高電平(1),也就是說,按鍵不按下為1,按下為0其中,按鍵為十位寬。最高三位代表的是音高,即決定低音,中音,高音。低七位代表的是音符。實現(xiàn)代碼如下:
????????
module key_input(
input clk_1k,
input rst_n,
input [9:0] key_in,
output reg [9:0] key_val
);
parameter delay_time = 8'd20; //delay20ms
reg [7:0] cnt;
reg [1:0] state;
always @(posedge clk_1k or negedge rst_n)
begin
if(!rst_n)begin
key_val <= 10'b0000000000;
cnt <= 0;
state <= 0;
end else
case(state)
2'd0 : begin//check
key_val <= 10'b0000000000;
if(key_in==10'b1111111111)
state <= 0;
else
state <= 1;
end
2'd1 : //delay
if(cnt < delay_time-1)begin
cnt <= cnt + 1'b1;
state <= 1;
end else begin
cnt <= 8'd0;
state <= 2;
end
2'd2 :begin //check again
case(key_in)
10'b1111111110 : key_val <= 10'b0000000001;
10'b1111111101 : key_val <= 10'b0000000010;
10'b1111111011 : key_val <= 10'b0000000100;
10'b1111110111 : key_val <= 10'b0000001000;
10'b1111101111 : key_val <= 10'b0000010000;
10'b1111011111 : key_val <= 10'b0000100000;
10'b1110111111 : key_val <= 10'b0001000000;
10'b1101111111 : key_val <= 10'b0010000000;
10'b1011111111 : key_val <= 10'b0100000000;
10'b0111111111 : key_val <= 10'b1000000000;
default : key_val <= 10'b0000000000;
endcase
state <= 3;
end
2'd3 : begin //waiting key up
if(key_in==10'b1111111111)
state <= 0;
else
state <= 3;
end
endcase
end
endmodule
????????Key_process模塊,主要是從編碼好的按鍵信息中,提取出音高、音符信息。并將兩種信息合并,組合成為一個變量TN,將其傳遞后后面的模塊,用于蜂鳴器發(fā)聲。
????????
module key_processor(
input clk,
input rst_n,
input [9:0] key,
output [4:0] TN
);
reg[2:0] notes;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
notes <= 3'b000;
else
if(key[0] == 1'b1)
notes <= 3'b001;
else if(key[1] == 1'b1)
notes <= 3'b010;
else if(key[2] == 1'b1)
notes <= 3'b011;
else if(key[3] == 1'b1)
notes <= 3'b100;
else if(key[4] == 1'b1)
notes <= 3'b101;
else if(key[5] == 1'b1)
notes <= 3'b110;
else if(key[6] == 1'b1)
notes <= 3'b111;
else
notes <= 3'b000;
end
reg[1:0] register;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
register <= 2'b00;
else
if(key[7] == 1'b1)
register <= 2'b00;
else if(key[8] == 1'b1)
register <= 2'b01;
else if(key[9] == 1'b1)
register <= 2'b10;
else
register <= register;
end
assign TN = {register,notes};
endmodule
????????Speaker模塊是電子琴發(fā)聲的關(guān)鍵模塊,它根據(jù)音高、音符信息,決定電子琴具體產(chǎn)生多少頻率的聲音。
//蜂鳴器驅(qū)動
module speaker(
input clk ,
input rst_n ,
input [4:0] TN ,
output spks
);
reg [10:0] temp;
always@(posedge clk)
begin
case(TN)
//
5'b00001 : temp <= 11'd1908; //低音 1
5'b00010 : temp <= 11'd1701; //低音 2
5'b00011 : temp <= 11'd1515; //低音 3
5'b00100 : temp <= 11'd1433; //低音 4
5'b00101 : temp <= 11'd1276; //低音 5
5'b00110 : temp <= 11'd1136; //低音 6
5'b00111 : temp <= 11'd1012; //低音 7
//
5'b01001 : temp <= 11'd956; //中音 1
5'b01010 : temp <= 11'd852; //中音 2
5'b01011 : temp <= 11'd759; //中音 3
5'b01100 : temp <= 11'd716; //中音 4
5'b01101 : temp <= 11'd638; //中音 5
5'b01110 : temp <= 11'd568; //中音 6
5'b01111 : temp <= 11'd506; //中音 7
//
5'b10001 : temp <= 11'd478; //高音 1
5'b10010 : temp <= 11'd426; //高音 2
5'b10011 : temp <= 11'd379; //高音 3
5'b10100 : temp <= 11'd358; //高音 4
5'b10101 : temp <= 11'd319; //高音 5
5'b10110 : temp <= 11'd284; //高音 6
5'b10111 : temp <= 11'd253; //高音 7
default : temp <= 0; //靜音
endcase
end
reg [10:0] cnt;
reg wave;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
cnt <= 11'd0;
wave <= 0;
end else begin
if(temp != 0)begin
if(cnt >= temp-1)begin
cnt <= 11'd0;
wave <= ~ wave;
end else
cnt <= cnt + 1'b1;
end else
wave <= 0;
end
end
assign spks = wave;
endmodule
????????這里最關(guān)鍵的是延遲變量temp如何選擇的問題。以低音1為例,它的頻率為262,speaker模塊的驅(qū)動時鐘是1M,而方波又是由等寬的高電平和低電平共同組成。所以要讓spks取反,應(yīng)該延遲的時間是1M/(262*2)=1908
? ?????????接下來就是進行modelsim仿真。仿真分析:
? ??
?????????低音 5,對應(yīng)程序內(nèi)的編碼(TN)為 00101,輸出方波頻率(spks)為392,與上表對照可知,結(jié)果正確
? ? ? ?
?????????中音4,對應(yīng)程序內(nèi)的編碼(TN)為 01100,輸出方波頻率(spks)為698,與上表對照可知,結(jié)果正確
?????????高音7,對應(yīng)程序內(nèi)的編碼(TN)為 10111,輸出方波頻率(spks)為1.97k,與上表對照可知,結(jié)果正確
? ? ? ??
? ? ? ? 完整的工程文件如下:(私我,便宜拿)文章來源:http://www.zghlxwxcb.cn/news/detail-759884.html
基于FPGA的電子琴設(shè)計仿真資源-CSDN文庫https://download.csdn.net/download/guangali/88640298? ? ?文章來源地址http://www.zghlxwxcb.cn/news/detail-759884.html
到了這里,關(guān)于FPGA項目(4)--基于FPGA的電子琴的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!