FPGA学习altera 系列 第十三篇 频率计设计

2020-12-29 16:50:31 浏览数 (1)

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

今天给大侠带来“FPGA学习系列 altera"系列,持续更新。此学习心得是本人之前所写,所用设计软件为Quartus II 13.1,现Quartus II 新版本已更新到19 ,以下仅供初学者学习参考。后续会更新其他系列,敬请关注。话不多说,上货。

对于每一个的小实验,我们都可以把它看作是一个小项目,逐步的去分析,设计,调试,最后完成功能。下面我们就开始我们的“小项目”。

项目名称:频率计

具体要求:检测方波的频率和占空比。

通过分析上述的“项目名称”和“具体要求”,我们可以设计出如下的架构:

  • wave:方波输入
  • freq:测试出的方波频率
  • duty_cycle:测试出的方波占空比
  • wave是经过处理后的数字信号,不是外界的模拟信号。

系统设计:

1. 工程的名称:freq_meter。

2. 测试出高电平的时间和低电平的时间,然后经过计算得出频率和占空比。

3. 状态转移图如下:

  • h_s:代表high_state;
  • l_s:代表low_state
  • low_cnt:低电平计数器
  • high_cnt:高电平计数器
  • low_time:低电平的周期数(周期数*周期就是时间)
  • high_time:高电平的周期数

上述计数器的位宽都是26位,因为笔者想要想要可以测试到1Hz,故而需要计数到50_000_000。

设计代码如下:

代码语言:javascript复制
/*
模块名称:freq_meter
模块功能:检测方波的频率和占空比。
作者:郝旭帅
邮箱:746833924@qq.com
*/
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

解析:

上面的描述是同时进行的,不要拿软件的思想去理解HDL语言,一定要谨记。

频率=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);

激励代码如下:

代码语言:javascript复制
/*
模块名称:freq_meter_tb
模块功能:为freq_meter模块提供激励信号
作者:郝旭帅
邮箱:746833924@qq.com
*/
`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

仿真波形如下:

下面笔者介绍一些modelsim中的基本操作:

1. 简化信号名称:点击功能按钮(如下图)。

2. 更改显示的进制:选中你想更改进制的信号,然后右击,选择Radix,选择你想选择的进制。

设置完成之后,仿真图如下:

因为前面还没有测试完一个周期,所以出现了不准确的数值。当测试完一个周期后,数值很准确,几乎没有误差。

友情提示:被测试的频率越大误差越大,希望读者根据自己的误差要求去计算出可以测试的频率的范围。设计正确。

如果还是有不明白的读者可以发邮件到我邮箱或者加群询问。

END

0 人点赞