一、实现了按键控制蜂鸣器发出不同的频率声音
二、源码
module divider(//32bit除法器
input wire rst_n,
input wire clk,
input wire [31:0] dividend,
input wire [11:0] divisor,
output wire [31:0] quotient,
output wire [31:0] remainder
);
reg signed [63:0] dividend_reg;
reg signed [11:0] divisor_reg;
reg signed [31:0] quotient_reg;
reg [5:0] i;
initial begin
i = 0;
dividend_reg = 0;
divisor_reg = 0;
quotient_reg = 0;
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
i = 0;
dividend_reg = 0;
divisor_reg = 0;
quotient_reg = 0;
end else if(divisor_reg[11:0] != divisor) begin//被除数在这份需求里不会变
dividend_reg[63:32] = 32'b0;
dividend_reg[31:0] = dividend;
divisor_reg[11:0] = divisor;
i = 5'b0;
end else if(i < 32) begin
if(dividend_reg[63:32] >= divisor_reg[11:0]) begin
quotient_reg[0] = 1'b1;
dividend_reg[63:32] = dividend_reg[63:32] - divisor_reg[11:0];
dividend_reg = dividend_reg << 1;
quotient_reg = quotient_reg << 1;
end else begin
quotient_reg[0] = 1'b0;
dividend_reg = dividend_reg << 1;
quotient_reg = quotient_reg << 1;
end
i = i + 1'b1;
end else begin
i = 6'd32;
end
end
assign quotient = quotient_reg;
assign remainder = dividend_reg[63:32];//不需要余数
endmodule
module buzzer (
input wire rst_n,
input wire clk,
input wire [3:0]key,
output reg buz
);
parameter sclk = 32'd50000000;//时钟
wire [31:0] quotient; //商
wire [31:0] remainder; //余数
reg [31:0] count;
reg [11:0]frequency;//希望获得的频率
reg flag;
initial begin
buz = 1'b0;
end
always @(posedge clk) begin
case(~key)
4'b0000: frequency = 12'd1; //idle
4'b0001: frequency = 12'd261 *2'd2; //do
4'b0010: frequency = 12'd293 *2'd2; //re
4'b0100: frequency = 12'd329 *2'd2; //mi
4'b1000: frequency = 12'd349 *2'd2; //fa
4'b0011: frequency = 12'd392 *2'd2; //so
4'b0110: frequency = 12'd440 *2'd2; //la
4'b1100: frequency = 12'd493 *2'd2; //si
4'b0101: frequency = 12'd512 *2'd2;
4'b1010: frequency = 12'd535 *2'd2;
4'b0111: frequency = 12'd578 *2'd2;
4'b1110: frequency = 12'd598 *2'd2;
4'b1111: frequency = 12'd622 *2'd2;
4'b1001: frequency = 12'd655 *2'd2;
4'b1011: frequency = 12'd689 *2'd2;
4'b1101: frequency = 12'd712 *2'd2;
default: frequency = 12'd1; //idle
endcase
end
divider div1(//给出时钟,计算给定频率下的对应的值
.rst_n (rst_n),
.clk (clk),
.dividend (sclk),
.divisor (frequency),
.quotient (quotient),
.remainder (remainder)
);
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
flag = 1'b0;
count = 25'b0;
end else if(count < quotient) begin
count <= count + 1'b1;
flag = 1'b0;
end else begin
count <= 25'b0;
flag = 1'b1;
end
end
always @(posedge flag or negedge rst_n) begin
if(rst_n == 1'b0) begin
buz = 1'b0;
end else begin
if(frequency != 12'd1)begin
buz = !buz;
end else begin
buz = buz;
end
end
end
endmodule
三、测试文件
`timescale 1ns/1ns
//`include "../rtl/buzzer.v"
module tb_buzzer();
reg clk;
reg [63:0]key;
reg rst_n;
wire buz[15:0];
buzzer jki0 (
.rst_n (rst_n),
.key (key[3:0]),
.clk (clk),
.buz (buz[0])
);
buzzer jki1 (
.rst_n (rst_n),
.key (key[7:4]),
.clk (clk),
.buz (buz[1])
);
buzzer jki2 (
.rst_n (rst_n),
.key (key[11:8]),
.clk (clk),
.buz (buz[2])
);
buzzer jki3 (
.rst_n (rst_n),
.key (key[15:12]),
.clk (clk),
.buz (buz[3])
);
buzzer jki4 (
.rst_n (rst_n),
.key (key[19:16]),
.clk (clk),
.buz (buz[4])
);
buzzer jki5 (
.rst_n (rst_n),
.key (key[23:20]),
.clk (clk),
.buz (buz[5])
);
buzzer jki6 (
.rst_n (rst_n),
.key (key[27:24]),
.clk (clk),
.buz (buz[6])
);
buzzer jki7 (
.rst_n (rst_n),
.key (key[31:28]),
.clk (clk),
.buz (buz[7])
);
buzzer jki8 (
.rst_n (rst_n),
.key (key[35:32]),
.clk (clk),
.buz (buz[8])
);
buzzer jki9 (
.rst_n (rst_n),
.key (key[39:36]),
.clk (clk),
.buz (buz[9])
);
buzzer jki10 (
.rst_n (rst_n),
.key (key[43:40]),
.clk (clk),
.buz (buz[10])
);
buzzer jki11 (
.rst_n (rst_n),
.key (key[47:44]),
.clk (clk),
.buz (buz[11])
);
buzzer jki12 (
.rst_n (rst_n),
.key (key[51:48]),
.clk (clk),
.buz (buz[12])
);
buzzer jki13 (
.rst_n (rst_n),
.key (key[55:52]),
.clk (clk),
.buz (buz[13])
);
buzzer jki14 (
.rst_n (rst_n),
.key (key[59:56]),
.clk (clk),
.buz (buz[14])
);
buzzer jki15 (
.rst_n (rst_n),
.key (key[63:60]),
.clk (clk),
.buz (buz[15])
);
// parameter sclk = 25'd27000000;//时钟
// wire [24:0] quotient; //商
// wire [24:0] remainder; //余数
// reg [9:0]frequency;//希望获得的频率
// divider div1(//给出时钟,计算给定频率下的对应的值
// .rst_n (rst_n),
// .clk (clk),
// .dividend (sclk),
// .divisor (frequency),
// .quotient (quotient),
// .remainder (remainder)
// );
localparam CLK_PERIOD = 20;
always #(CLK_PERIOD/2) clk=~clk;
initial begin
$dumpfile("tb_buzzer.vcd");
$dumpvars(0, tb_buzzer);
end
initial begin
#1 clk = 1'b0;
key = 64'Hdb9fe7a5c6384210;
//frequency = 10'd130;
#1 rst_n = 1'b0;
#5 rst_n = 1'b1;
end
endmodule
四、引脚约束
五、后记
1、现在想想,只是实现蜂鸣器还能更简单的,只要对时钟进行分频就好了,然后计数器计算。完全不需要一个除法器。
2、这是我用基于野火的开发板写的。高云的小蜜蜂fpga系列开发板只要自己改一下时钟跟做一下引脚约束就好了。