大侠好,欢迎来到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等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!