本次设计是基于FPGA的电子琴,设计要求如下:
本次我采用modelsim仿真的方式验证设计功能的正确性。工作时钟选择50MHZ。
所谓电子琴,本质就是用按键控制蜂鸣器发出不同频率的声音。我们平时所接触的音乐,从低音到高音,从哆瑞咪发到嗦啦西,都有相应的频率与之对应。音符与频率对应关系如下:
所以整个设计的思路就是,按下按键,控制蜂鸣器的管脚产生相应频率的方波即可。下面首先给出整个设计的总体rtl视图,然后再根据此图讲解各个模块
首先,clock_gen模块的作用就是对系统时钟进行分频,系统时钟是50M,分频产生两个时钟,一个1M,一个1K。具体代码如下所示,分频细节不做具体介绍。
module clock_gen(
input clk, //50M时钟
input rst_n,
output reg clk_1M,
output reg clk_1k
);
parameter div_factor_1MHz = 6'd25; //1MHz 分频系数
parameter div_factor_1K = 9'd500; //1K 分频系数
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信号为驱动时钟,处理按键信息,将按键输入的信息经过延时消抖以后,再编码输出。按键默认电平为高电平(1),也就是说,按键不按下为1,按下为0其中,按键为十位宽。最高三位代表的是音高,即决定低音,中音,高音。低七位代表的是音符。实现代码如下:
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,将其传递后后面的模块,用于蜂鸣器发声。
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模块是电子琴发声的关键模块,它根据音高、音符信息,决定电子琴具体产生多少频率的声音。
//蜂鸣器驱动
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
这里最关键的是延迟变量temp如何选择的问题。以低音1为例,它的频率为262,speaker模块的驱动时钟是1M,而方波又是由等宽的高电平和低电平共同组成。所以要让spks取反,应该延迟的时间是1M/(262*2)=1908
接下来就是进行modelsim仿真。仿真分析:
低音 5,对应程序内的编码(TN)为 00101,输出方波频率(spks)为392,与上表对照可知,结果正确
中音4,对应程序内的编码(TN)为 01100,输出方波频率(spks)为698,与上表对照可知,结果正确
高音7,对应程序内的编码(TN)为 10111,输出方波频率(spks)为1.97k,与上表对照可知,结果正确
完整的工程文件如下:(私我,便宜拿)文章来源:https://www.toymoban.com/news/detail-759884.html
基于FPGA的电子琴设计仿真资源-CSDN文库https://download.csdn.net/download/guangali/88640298 文章来源地址https://www.toymoban.com/news/detail-759884.html
到了这里,关于FPGA项目(4)--基于FPGA的电子琴的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!