FPGA 频率计实验
实验要求:实现等精度频率计,通过数码管显示。
频率计实验又称为频率计数器,是一种专门对被测信号进行测量的电子仪器。
计数法:直接计数单位时间内的被测信号的脉冲数,这种方式测量精度高、速度快、适合不同频率、不同精确度测频的需要。
测待测频率,需要有一个基准时钟,基准时钟频率设置为CLK_FS,基准时钟的脉冲数为fs_cnt,生成门控信号为高,在门控信号为高的时候,查待测信号的脉冲数,设待测信号的频率为clk_fx,待测信号的脉冲数为fx_cnt;
则满足下列比例:
fs_cnt/CLK_FS=fx_cnt/clk_fx;
这是一个理想的公式
因为门控信号拉高的长度不一定等于基准时钟与待测信号时钟的整数倍。
等精度频率计:是以待测信号为基准,拉高门控信号,保证门控信号是待测信号周期的整数倍,但是会对基准信号产生误差。
下面是频率计的代码:
测试频率为基准时钟/100的代码
> module frequency(clk,rst_n,data_fx);
> input clk,rst_n;
> output [19:0] data_fx;
> //parameter define parameter CLK_FS=26'd50000000; //基准时钟频率值
>
> //wire define wire [19:0] data_fx; //被测信号测量值
> cymometer #(.CLK_FS(CLK_FS))
> u_cymometer(
> .clk(clk),
> .rst_n(rst_n),
> .clk_fx(clk_out),
> .data_fx(data_fx)
> );
> clk_test #(.DIV_N(7'd100) )
> u_clk_test(
> .clk(clk),
> .rst_n(rst_n),
> .clk_out(clk_out)
> );
> endmodule
`
> module clk_test #(parameter DIV_N=7'd100)
> ( input clk,
> input rst_n,
> output reg clk_out
> );
> reg [6:0] cnt;
> always @(posedge clk or negedge rst_n) begin
> if(!rst_n)
> begin
> cnt <= 0;
> clk_out <= 0;
> end
> else begin
> if(cnt==DIV_N/2-1)
> begin
> cnt <= 0;
> clk_out <= ~clk_out;
> end
> else
> begin
> cnt <= cnt+1;
> clk_out <= clk_out;
> end
> end
> end
>endmodule
>
> module cymometer #(parameter CLK_FS=50000000)
> (
> input clk,
> input rst_n,
> input clk_fx,
> output reg [19:0] data_fx );
> parameter CNT_FS=500;
> //define reg [19:0] cnt_fs;
> //生成门信号 reg gate;
> reg gate_fs_reg; //中间寄存器
> reg gate_fs;
> reg gate_fx0;
> reg gate_fx1;
> reg gate_fs0;
> reg gate_fs1;
> reg [19:0] count_fx;
> reg [19:0] count_fx_reg;
> reg [19:0] count_fs;
> reg [19:0] count_fs_reg;
> wire gate_fs_en;
> wire gate_fx_en; //cnt_fs
> always @(posedge clk_fx or negedge rst_n) begin
> if(!rst_n)
> cnt_fs <= 0;
> else begin
> if(cnt_fs==CNT_FS+20)
> cnt_fs <= 0;
> else
> cnt_fs <= cnt_fs+1;
> end
> end
>
> //gate
> always @(posedge clk_fx or negedge rst_n) begin
> if(!rst_n)
> gate <= 0;
> else begin
> if(cnt_fs < 20 || cnt_fs > CNT_FS)
> gate <= 0;
> else
> gate <= 1;
> end
> end //gate_fs
> always @(posedge clk or negedge rst_n)
> begin if(!rst_n)
> begin
> gate_fs <= 0;
> gate_fs_reg <= 0;
> end
> else begin
> gate_fs_reg <= gate;
> gate_fs <= gate_fs_reg;
> end
> end
>
> //基准信号下降沿
> always @(posedge clk or negedge rst_n) begin
> if(!rst_n)
> begin
> gate_fs0 <= 0;
> gate_fs1 <= 0;
> end
> else begin
> gate_fs0 <= gate_fs;
> gate_fs1 <= gate_fs0;
> end
> end
> assign gate_fs_en=~gate_fs0&&gate_fs1;
> always @(posedge clk_fx or negedge rst_n) begin
> if(!rst_n)
> begin
> gate_fx0 <= 0;
> gate_fx1 <= 0;
> end
> else begin
> gate_fx0 <= gate;
> gate_fx1 <= gate_fx0;
> end
> end
> assign gate_fx_en=~gate_fx0&&gate_fx1;
> always @(posedge clk_fx or negedge rst_n) begin
> if(!rst_n)
> begin
> count_fx <= 0;
> count_fx_reg <=0;
> end
> else begin
> if(gate==1)
> count_fx_reg <= count_fx_reg+1;
> else if(gate_fx_en)
> begin
> count_fx_reg <= 0;
> count_fx <= count_fx_reg;
> end
> end
> end
>
> always @(posedge clk or negedge rst_n) begin
> if(!rst_n) begin
> count_fs <= 0;
> count_fs_reg <= 0;
> end
> else begin
> if(gate_fs==1)
> count_fs_reg <= count_fs_reg+1;
> else if(gate_fs_en) begin
> count_fs_reg <= 0;
> count_fs <= count_fs_reg;
> end
> end
> end
>
> //输出频率
> always @(posedge clk or negedge rst_n) begin
> if(!rst_n)
> data_fx <= 0;
> else if(gate_fs==0)
> data_fx <= CLK_FS/(count_fs/count_fx);
> end
> endmodule
>
>
> `timescale 1ns/1ns
> module frequency_tb;
> reg clk,rst_n;
> wire [19:0] data_fx;
> always #5 clk=~clk;
> initial
> begin
> rst_n=0;
> clk=0;
> #100 rst_n=1;
> #70000000 $stop;
> end
> frequency inst(clk,rst_n,data_fx);
> endmodule