赞
踩
本次设计是基于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,与上表对照可知,结果正确
完整的工程文件如下:(私我,便宜拿)
基于FPGA的电子琴设计仿真资源-CSDN文库https://download.csdn.net/download/guangali/88640298
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。