基于FPGA+stm32的的等精度频率计

3 篇文章 1 订阅

整体功能:实现正弦波(方波)的频率和周期测量,并测量方波信号占空比

测量方法:

1.频率测量:使用等精度测量方法:等精度测量,由于设置的门控时间是5000个待测的信号的周期,所以当输入信号频率较低,会导致测量的时间过长。
2.占空比测量:这里借鉴了基于FPGA的简易频率计设计这篇文章的测量方法。通过门控时间内,对PLL倍频的200MHz时钟clk_200计数,读出待测信号连续的四个边沿的计数值,通过计算可以得到高电平的时间和待测信号的周期。然后计算可得到占空比。此外在输入频率较低的情况,上述测量得到的周期的倒数,可以作为低频信号的频率测量值。

整形电路

将待测信号整形变成FPGA可以识别到的TTL电平。具体实现由硬件实现的小伙伴完成,也没太操心@_@。

FPGA测频模块

测频模块

//频率测量(等精度)
module freq
   #(parameter    CLK_FS = 26'd50_000_000,// 基准时钟频率
	parameter  MAX       =  10'd32)  // 定义数据位宽        
    (   //system clock
        input                 clk_fs ,     // 时钟信号
        input                 rst_n   ,  // 复位信号

        //cymometer interface
        input                 clk_fx ,     // 待测信号
		input gate,       // 门控信号(与待测时钟同步)
		input gate_fs,    // 与基准时钟同步的门控信号
		input  neg_gate_fx,//
		input  neg_gate_fs,//
        
		output reg    [32-1:0]   fs_cnt      ,           //门控时间内基准时钟信号的个数 
		output reg    [32-1:0]   fx_cnt      ,          // 门控时间内待测信号的个数
		output reg  	[32-1:0]   data_fx_temp  // 待测信号的频率值
);


reg    [32-1:0]   fs_cnt_temp ;           // fs_cnt 计数
reg    [32-1:0]   fx_cnt_temp ;           // fx_cnt 计数

//门控时间内待测信号的计数,设置的为5000个,这里重新计数,只是用于检验信号是否正确
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        fx_cnt_temp <= 32'd0;
        fx_cnt <= 32'd0;
    end
    else if(gate)begin
      fx_cnt_temp <= fx_cnt_temp + 1'b1;
    end   
    else if(neg_gate_fx) begin
        
        fx_cnt_temp <= 32'd0;
        fx_cnt <= fx_cnt_temp;
        
    end
end

//门控时间内基准时钟的计数
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        fs_cnt_temp <= 32'd0;
        fs_cnt <= 32'd0;
    end
    else if(gate_fs)
        begin
        fs_cnt_temp <= fs_cnt_temp + 1'b1;
        end
    else if(neg_gate_fs) begin
        
        fs_cnt_temp <= 32'd0;
		fs_cnt <= fs_cnt_temp;
		data_fx_temp<=fs_cnt;
    end
end
//计算待测信号的频率值
//always @(posedge clk_fs or negedge rst_n) begin
//    if(!rst_n) begin
//        data_fx_temp <= 64'd0;
//    end
//    else if(gate_fs == 1'b0)
//			data_fx_temp <=CLK_FS*fx_cnt/fs_cnt;
//end

endmodule


//频率、占空比测量模块(测周法)
module duty_ratio(
     clk,
	  rst_n,
	  gate,sig,
     fre_count,
	  duty_count
);
input 	 clk; 
input 	 rst_n; 
input 	 	gate; 
input 	 	sig; 
output 	[31:0] 	fre_count; 
output	[31:0]	duty_count;

wire clk_200;
wire locked;

clk_200 pll_module(
    .areset(!rst_n),
    .inclk0(clk),
    .c0(clk_200)
);

reg [31:0] counter;                         //32位计数器
always @(posedge clk_200 or negedge rst_n)
begin
     if(!rst_n)
     begin
        counter  <= 1'b0;
     end
     else
     begin
        if(gate == 1'b1)
        begin
            counter <= counter + 1'b1;
        end          
        else
        begin
            counter <= 32'b0;
        end
     end
end


reg [1:0] en_sig_edge;
reg [1:0] en_sig_edge_n;

always @(posedge clk_200 or negedge rst_n)
begin
     if(!rst_n)
     begin
        en_sig_edge  <= 2'b0;
     end
     else
     begin
        en_sig_edge <= en_sig_edge_n;
     end
end

always @(*)
begin
     if(!rst_n)
     begin
       en_sig_edge_n = 2'b0;
     end
     else
     begin
        en_sig_edge_n = {en_sig_edge[0],sig};
     end
end


wire    edge_turn;
assign  edge_turn = en_sig_edge[0] ^ en_sig_edge[1];        //检测双边沿

reg [31:0] time_record[3:0];
always @(posedge clk_200 or negedge rst_n)
begin
    if(!rst_n)
    begin
        time_record[0] <= 32'b0;
        time_record[1] <= 32'b0;
        time_record[2] <= 32'b0;
        time_record[3] <= 32'b0;
    end

    else if(gate == 1'b0 )
    begin
        time_record[0] <= 32'b0;
        time_record[1] <= 32'b0;
        time_record[2] <= 32'b0;
        time_record[3] <= 32'b0;
    end

    else
    begin
        if(edge_turn)
            begin
            time_record[0] <= counter;
            time_record[1] <= time_record[0];
            time_record[2] <= time_record[1];
            time_record[3] <= time_record[2];
            end 
        else
            begin
            time_record[0] <= time_record[0];
            time_record[1] <= time_record[1];
            time_record[2] <= time_record[2];
            time_record[3] <= time_record[3];
            end
    end
end

reg [31:0] pipe_add_1;
reg [31:0] pipe_add_2;
reg [31:0] pipe_result;

always @(posedge clk or negedge rst_n)
begin
     if(!rst_n)
     begin
        pipe_add_1 <= 32'b0;
        pipe_add_2 <= 32'b0;
     end
     else
     begin
        pipe_add_1 <= time_record[0] + time_record[1];
        pipe_add_2 <= time_record[2] + time_record[3];
     end
end

always @(posedge clk or negedge rst_n)
begin
     if(!rst_n)
     begin
        pipe_result  <= 32'b0 ;
     end
     else
     begin
        pipe_result <= pipe_add_1 - pipe_add_2;
     end
end

reg [31:0] duty_count_reg;
always @(posedge sig or negedge rst_n)
begin
     if(!rst_n)
     begin
        duty_count_reg  <= 32'b0 ;
     end
     else
     begin
			if(gate == 1'b1)
				duty_count_reg <= time_record[0] - time_record[1];
			else
				duty_count_reg <= 32'b0;
     end
end

assign duty_count = duty_count_reg;
assign fre_count = pipe_result;

endmodule

由上述测频模块产生三组测量值,高电平时间计数值duty_count,2个待测信号周期计数值fre_count,门控时间内基准时钟的计数值data_fx。然后通过SPI 接口将这3组数据发给单片机进行处理。
SPI+DDS+FRE

MCU模块

通过SPI串口接收FPGA发送的三组数据。
根据公式可以算出
占 空 比 : d u t y = d u t y c o u n t / f r e c o u n t ∗ 2.0 占空比:duty ={duty_{count}}/{fre_{count}} *2.0 :duty=dutycount/frecount2.0
频 率 1 : f r e q 1 = c l k 200 M H z ∗ 2.0 / f r e c o u n t 频率1:freq 1 =clk_{200MHz}*2.0/{fre_{count}} 1:freq1=clk200MHz2.0/frecount
频 率 2 : f r e q 2 = c l k 50 M H z ∗ 5000 / d a t a f x 频率2:freq 2 =clk_{50MHz}*5000/{data_{fx}} 2:freq2=clk50MHz5000/datafx

当测量频率较低时,采用频率1freq1作为输出结果
但测量频率较高时,采用频率2freq2作为输出结果
最后通过LCD频显示。

实际测量

输入信号频率(Hz) / 占空比(%)测量频率 (单位:Hz) / 占空比(%)
1.234000 / 801.234014 /79.996
1000 /641000.10009/64.144
10000000/4010000400.967295 /40.0

实测图片:
测量值1

如有错误或者言语不恰当的地方可在评论区指出,谢谢!

实验源码

https://download.csdn.net/download/Cauchy_Z/20555477?spm=1001.2014.3001.5501

参考文章

[1]. [基于FPGA的简易频率计设计]

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

juajua_Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值