源码系列:基于FPGA的频率计设计(附源工程)

2020-12-29 17:54:04 浏览数 (1)

大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。

今天给大侠带来基于FPGA的频率计设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“ 频率计设计源码”,可获取源码文件。话不多说,上货。

设计背景

频率计又称为频率计数器,是一种专门对被测信号频率进行测量的电子测量仪器。频率计主要由四个部分构成:时基(T)电路、输入电路、计数显示电路以及控制电路。

频率,即是信号周期的倒数,也就是说,信号每单位时间完成周期的个数,一般取一秒为基本单位时间。

设计原理

本次设计主要是一个简单的二选一数据选择器,我们的设计主频率=1s/T,T=高电平的时间 低电平的时间。时间=周期数*周期。占空比=(高电平的时间/周期)100%。我们的时间单位都是以ns来计算的,所以要把1s换成1_000_000_000ns,驱动时钟是50MHz的,周期为20ns。计算占空比的时候,我们把周期20ns全部省略了。所以计算公式如下:

freq = 1_000_000_000/(low_time * 20 high_time * 20);

duty_cycle = (high_time * 100)/(high_time low_time)。

设计架构

设计架构图:

设计代码

设计模块freq_meter代码:

代码语言:javascript复制
module freq_meter (clk, rst_n, wave, freq, duty_cycle);  //端口列表
  
  input clk;                   //时钟
  input rst_n;                 //复位
  input wave;                  //被测频率
  output [25:0] freq;          //输出频率
  output [6:0] duty_cycle;   //输出占空比
  
  reg [25:0] low_cnt;
  reg [25:0] high_cnt;
  reg [25:0] low_time;
  reg [25:0] high_time;
  reg state;
  
  localparam high_state = 1'b0;
  localparam low_state = 1'b1;
  
  always @ (posedge clk or negedge rst_n)
    begin
      if (!rst_n)
        begin
        low_cnt <= 26'd0;
        high_cnt <= 26'd0;
        low_time <= 26'd0;
        high_time <= 26'd0;
        state <= high_state;
        end
      else
      begin
        case (state)
          high_state : begin
              if (wave == 1'b1)       //判断输入为高电平
                begin
                  high_cnt <= high_cnt   1'b1;
                  state <= high_state;
                end
              else
                begin
                  high_cnt <= 26'd0;
                  high_time <= high_cnt;
                  state <= low_state;
                end
            end
            
          low_state : begin
              if (wave == 1'b0)  //判断输入为低电平
                begin
                  low_cnt <= low_cnt   1'b1;
                  state <= low_state;
                end
              else
                begin
                  low_cnt <= 26'd0;
                  low_time <= low_cnt;
                  state <= high_state;
                end
            end
          default : state <= low_state;
          endcase
      end
    end
    
  assign freq = 1_000_000_000/(low_time * 20   high_time * 20);  //求频率
   assign duty_cycle = (high_time * 100)/(high_time   low_time);  //求占空比
  
endmodule

仿真测试

仿真测试freq_meter_tb代码:

代码语言:javascript复制
`timescale 1ns/1ps

module freq_meter_tb;
  reg clk;
  reg rst_n;
  reg wave;
  wire [25:0] freq;
  wire [6:0] duty_cycle;
  
  initial begin
    clk = 1'b1;
    rst_n = 1'b0;
    
    # 200.1
      rst_n = 1'b1;
    # 1_000_000_0//仿真10ms
      $stop;
  end
  
  always # 10 clk = ~clk;
  
  initial begin
    wave = 1'b1;
    forever begin//产生占空比为60%,频率为1KHz的方波
      # 600_000
        wave = 1'b0;
      # 400_000
        wave = 1'b1;
    end
  end
  
  freq_meter freq_meter_dut(
    .clk(clk),
    .rst_n(rst_n),
    .wave(wave),
    .freq(freq),
    .duty_cycle(duty_cycle)
  );
  
endmodule     

仿真图:

由于在前面没有测完一个周期出现了不稳定的因素,就出现了不准确的数值,当测试完一个周期以后,测到的数值就比较的准确,基本的没有什么误差。相对的,如果测试的频率越大,测到的数值就越准确。

END

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!

0 人点赞