记录遇见的校招笔试题

频率计数器

`timescale 1ns/1ps

/*

若参考时钟为100MHz

检测频率范围1Hz~1MHz,由于参考时钟远快于被测时钟

现将被测时钟打三拍检测上升沿

然后再参考时钟域下计数

上升沿计数清零并保存计数器最大值

然后用参考时钟除以(计数最大值+1)得到被测时钟频率

若参考时钟频率为100MHz

检测频率范围1MHz到200MHZ或者1MZ~100MHz、1MHz~500MHz

先用被测时钟进行计数到199、99、499,,目的是为了降低被测时钟频率,方便100MHz去采样

0~99:1;100~199:0,其他亦然

将该信号打3拍进入参考时钟域

在高电平期间计数

在下降沿锁存计数最大值

然后计算频率

用参考时钟频率*高电平计数周期(被测时钟域下100)/ (高电平下参考时钟计数最大值+1)

*/

module frequency_counter(

input wire clk_100MHz, // 100 MHz reference clock

input wire reset, // Reset signal

input wire signal_in, // Input signal whose frequency needs to be measured

output reg [31:0] frequency // Measured frequency output

);

reg [31:0] counter_100MHz; // Counter for 100 MHz clock cycles

reg [31:0] signal_period; // Measured period of the input signal in 100 MHz clock cycles

/*

reg [31:0] signal_edge_count; // Edge count of input signal

reg signal_in_prev; // Previous state of the input signal

always @(posedge clk_100MHz or posedge reset) begin

if (reset) begin

counter_100MHz <= 32'd0;

signal_period <= 32'd0;

signal_in_prev <= 1'b0;

signal_edge_count <= 32'd0;

frequency <= 32'd0;

end else begin

// Count 100 MHz clock cycles

counter_100MHz <= counter_100MHz + 1;

// Detect rising edge of input signal

if (signal_in && !signal_in_prev) begin

// Capture the period of the signal in 100 MHz clock cycles

signal_period <= counter_100MHz;

counter_100MHz <= 32'd0; // Reset the 100 MHz counter

signal_edge_count <= signal_edge_count + 1; // Increment edge count

end

// Save the current state of the input signal

signal_in_prev <= signal_in;

// Calculate frequency only when we have measured at least one period

if (signal_period != 32'd0) begin

// Frequency = 100 MHz / signal period (in 100 MHz clock cycles)

frequency <= 100_000_000 / signal_period;

end

end

end

*/

reg [2:0] signal_in_prev;

reg out_flag;

always@(posedge clk_100MHz)begin

if(reset)begin

signal_in_prev <= 0;

end

else begin

signal_in_prev <= {signal_in_prev[1:0],signal_in};

end

end

always@(posedge clk_100MHz)begin

if(reset)begin

counter_100MHz <= 0;

signal_period <= 0;

counter_100MHz <= 0;

out_flag <= 0;

end

else if(signal_in_prev[2:1]==2'b01)begin

signal_period <= counter_100MHz;

counter_100MHz <= 0;

out_flag <= 1;

end

else begin

counter_100MHz <= counter_100MHz + 1;

signal_period <= signal_period;

out_flag <= 0;

end

end

always@(posedge clk_100MHz)begin

if(reset)begin

frequency <= 0;

end

else if(out_flag)begin

frequency <= 100_000_000 / (signal_period + 1);

end

else begin

frequency <= frequency;

end

end

endmodule

`timescale 1ns/1ps

module frequency_counter_tb;

// Parameters

localparam CLK_PERIOD = 10; // 100 MHz clock period (10 ns)

localparam RESET_TIME = 100; // Reset time in ns

// Testbench signals

reg clk_100MHz;

reg reset;

reg signal_in;

wire [31:0] frequency;

// Instantiate the frequency_counter module

frequency_counter uut (

.clk_100MHz(clk_100MHz),

.reset(reset),

.signal_in(signal_in),

.frequency(frequency)

);

// Generate 100 MHz clock

initial begin

clk_100MHz = 0;

forever #(CLK_PERIOD/2) clk_100MHz = ~clk_100MHz;

end

// Test sequence

initial begin

// Initialize signals

reset = 1;

signal_in = 0;

// Apply reset

#(RESET_TIME) reset = 0;

// Wait for reset to be deasserted

#(RESET_TIME);

// Generate a 1 kHz signal (period = 1 ms)

generate_signal(50_000);

// Wait some time to measure the frequency

#100_000; // 1 second in simulation time

// Check the measured frequency

$display("Measured frequency: %d Hz (Expected: 1000 Hz)", frequency);

// Generate a 10 kHz signal (period = 100 us)

generate_signal(600_000);

// Wait some time to measure the frequency

#100_000; // 100 ms in simulation time

// Check the measured frequency

$display("Measured frequency: %d Hz (Expected: 10000 Hz)", frequency);

// Generate a 1 MHz signal (period = 1 us)

generate_signal(200_000);

// Wait some time to measure the frequency

#100_000; // 10 ms in simulation time

// Check the measured frequency

$display("Measured frequency: %d Hz (Expected: 1000000 Hz)", frequency);

// End simulation

$stop;

end

// Task to generate a signal of a given frequency

task generate_signal;

input integer freq;

integer period;

begin

period = 1_000_000_000 / freq; // Period in ns

repeat(100) begin

signal_in = 1;

#(period/2);

signal_in = 0;

#(period/2);

end

end

endtask

endmodule

//第二种

`timescale 1ns/1ps

module freq_detect(

input clk_ref_in , //参考时钟50MHz

input clk_test_in , //待测时钟(范围1MHz~200MHz)

output [15:0] freq_num //输出端口频率值(单位:MHz)

);

//=====================register design===================

reg [7:0] clk_cnt = 0;

reg high_lev = 0;

reg [2:0] high_lev_r = 0;

reg [15:0] clk_ref_cnt = 0;

reg [15:0] clk_ref_cnt_lat = 0;

reg [15:0] clk_F = 0;

//=========================clk_test_in时钟域=============

//clk_in:1~200MHz,先降频,经200倍分频后的时钟不大于1MHz

//目的在于参考时钟50MHz,可以很好的采样到慢时钟

always@(posedge clk_test_in)begin

if(clk_cnt >= 199)begin

clk_cnt <= 0;

end

else begin

clk_cnt <= clk_cnt + 1;

end

end

//分频输出

always@(posedge clk_test_in)begin

if((clk_cnt == 99)||(clk_cnt == 199))begin

high_lev <= ~high_lev;

end

end

//================clk_ref_in时钟域=======================

//对high_lev打三拍同步到快时钟域

always@(posedge clk_ref_in)begin

high_lev_r <= {high_lev_r[1:0],high_lev};

end

//在ref时钟域下对分频后的高电平进行计数

always@(posedge clk_ref_in)begin

if(high_lev_r[2])begin

clk_ref_cnt <= clk_ref_cnt + 1;

end

else begin

clk_ref_cnt <= 0;

end

end

//用锁存器锁存高电平计数的最大值:即 分频时钟下降沿达到最大值

always@(posedge clk_ref_in)begin

if(high_lev_r[2:1]==2'b10)begin

clk_ref_cnt_lat <= clk_ref_cnt + 1;

end

end

// 计算输出频率

always@(posedge clk_ref_in)begin

clk_F <= 5000/clk_ref_cnt_lat;

end

assign freq_num = clk_F;

endmodule

`timescale 1ns/1ps

module freq_detect_tb();

reg clk_ref_in ;

reg clk_test_in ;

wire [15:0]freq_num ;

parameter REF_FERQ_PERIOD = 20;

parameter TEST_FERQ_PERIOD = 1000/20;

initial begin

clk_ref_in = 0;

forever begin

#(REF_FERQ_PERIOD/2);

clk_ref_in = ~clk_ref_in;

end

end

initial begin

clk_test_in = 0;

forever begin

#(TEST_FERQ_PERIOD/2);

clk_test_in = ~clk_test_in;

end

end

freq_detect uut(

.clk_ref_in (clk_ref_in ), //参考时钟50MHz

.clk_test_in (clk_test_in ), //待测时钟(范围1MHz~200MHz)

.freq_num (freq_num ) //输出端口频率值(单位:MHz)

);

endmodule

全部评论

相关推荐

不愿透露姓名的神秘牛友
昨天 14:10
码农索隆:成年人最直白的答复:已读不回
点赞 评论 收藏
分享
06-23 11:28
门头沟学院 Java
牛客91966197...:也有可能是点拒绝的时候自动弹的话术
点赞 评论 收藏
分享
昨天 11:23
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务