改进温度计模块-》pulse_cnt ,验证仿真无误
This commit is contained in:
parent
9e3862f694
commit
81852b1579
|
|
@ -0,0 +1,60 @@
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module pulse_cnt #(
|
||||||
|
parameter CLK_FREQ = 50_000_000
|
||||||
|
) (
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
input wire sig_in,
|
||||||
|
input wire [23:0] win_us,
|
||||||
|
output reg [23:0] cnt_out,
|
||||||
|
output reg vld_out
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
reg [31:0] window_cnt; // 当前时钟周期计数
|
||||||
|
reg [31:0] target_cnt; // 当前窗口所需时钟周期数
|
||||||
|
|
||||||
|
// 脉冲计数(宽度与输出一致,防止溢出)
|
||||||
|
reg [23:0] pulse_cnt;
|
||||||
|
|
||||||
|
// 标志:是否正在计算新的 target_cnt(避免组合逻辑环路)
|
||||||
|
reg calc_done;
|
||||||
|
|
||||||
|
reg sig_sync1, sig_sync2, sig_sync3;
|
||||||
|
wire sig_rise = sig_sync2 & ~sig_sync3;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
sig_sync1 <= sig_in;
|
||||||
|
sig_sync2 <= sig_sync1;
|
||||||
|
sig_sync3 <= sig_sync2;
|
||||||
|
end
|
||||||
|
|
||||||
|
// 主控制逻辑
|
||||||
|
always @(posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
window_cnt <= 0;
|
||||||
|
pulse_cnt <= 0;
|
||||||
|
cnt_out <= 0;
|
||||||
|
vld_out <= 0;
|
||||||
|
target_cnt <= 24'd50_000;
|
||||||
|
|
||||||
|
end else begin
|
||||||
|
vld_out <= 1'b0;
|
||||||
|
target_cnt <= ( {40'd0, win_us} * CLK_FREQ) / 1_000_000 ;
|
||||||
|
// 窗口计数结束条件:当前计数值到达 target_cnt
|
||||||
|
if (window_cnt >= target_cnt) begin
|
||||||
|
cnt_out <= pulse_cnt;
|
||||||
|
vld_out <= 1'b1;
|
||||||
|
// 复位窗口计数器与脉冲计数器,并触发重新计算目标值
|
||||||
|
window_cnt <= 0;
|
||||||
|
pulse_cnt <= 0;
|
||||||
|
end else begin
|
||||||
|
window_cnt <= window_cnt + 1;
|
||||||
|
if (sig_rise)
|
||||||
|
pulse_cnt <= pulse_cnt + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
`timescale 1ns / 1ps
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Company:
|
|
||||||
// Engineer:
|
|
||||||
//
|
|
||||||
// Create Date: 2026/03/22 18:53:43
|
|
||||||
// Design Name:
|
|
||||||
// Module Name: pulse_freq_10ms
|
|
||||||
// Project Name:
|
|
||||||
// Target Devices:
|
|
||||||
// Tool Versions:
|
|
||||||
// Description:
|
|
||||||
//
|
|
||||||
// Dependencies:
|
|
||||||
//
|
|
||||||
// Revision:
|
|
||||||
// Revision 0.01 - File Created
|
|
||||||
// Additional Comments:
|
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
`timescale 1ns / 1ps
|
|
||||||
|
|
||||||
module pulse_freq_10ms #(
|
|
||||||
parameter CLK_FREQ = 50_000_000, // 系统时钟频率(Hz),默认50MHz
|
|
||||||
parameter WINDOW_MS = 10 // 测量时间窗口(ms),默认10ms
|
|
||||||
) (
|
|
||||||
input clk, // 系统时钟
|
|
||||||
input rst_n, // 异步复位,低有效
|
|
||||||
input vin, // 输入方波
|
|
||||||
output reg [19:0] freq, // 时间窗口内脉冲计数(如果为1302,就是130.2k)
|
|
||||||
output reg valid // 测量完成有效脉冲
|
|
||||||
);
|
|
||||||
|
|
||||||
// 计算窗口计数最大值
|
|
||||||
localparam WINDOW_CNT = (CLK_FREQ / 1000) * WINDOW_MS - 1;
|
|
||||||
|
|
||||||
reg [31:0] cnt_window; // 窗口计时器(使用32位以防大数值)
|
|
||||||
reg [19:0] pulse_cnt; // 脉冲计数器
|
|
||||||
reg vin_sync1, vin_sync2;
|
|
||||||
wire vin_rise;
|
|
||||||
|
|
||||||
// 边沿检测
|
|
||||||
always @(posedge clk) begin
|
|
||||||
vin_sync1 <= vin;
|
|
||||||
vin_sync2 <= vin_sync1;
|
|
||||||
end
|
|
||||||
assign vin_rise = vin_sync1 & ~vin_sync2;
|
|
||||||
|
|
||||||
// 核心逻辑:窗口计数 + 脉冲计数 + 锁存输出
|
|
||||||
always @(posedge clk or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
cnt_window <= 0;
|
|
||||||
pulse_cnt <= 0;
|
|
||||||
valid <= 0;
|
|
||||||
end else begin
|
|
||||||
valid <= 0; // 默认无效
|
|
||||||
if (cnt_window == WINDOW_CNT) begin // 窗口时间到
|
|
||||||
freq <= pulse_cnt; // 输出计数值
|
|
||||||
valid <= 1;
|
|
||||||
cnt_window <= 0;
|
|
||||||
pulse_cnt <= 0;
|
|
||||||
end else begin
|
|
||||||
cnt_window <= cnt_window + 1;
|
|
||||||
if (vin_rise) pulse_cnt <= pulse_cnt + 1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module tb_pulse_cnt();
|
||||||
|
|
||||||
|
// 参数定义
|
||||||
|
localparam CLK_FREQ = 50_000_000; // 50 MHz 时钟
|
||||||
|
localparam CLK_PERIOD = 20ns; // 1/50MHz = 20ns
|
||||||
|
|
||||||
|
// 信号声明
|
||||||
|
reg clk;
|
||||||
|
reg rst_n;
|
||||||
|
reg [23:0] win_us;
|
||||||
|
reg sig_in;
|
||||||
|
wire [23:0] cnt_out;
|
||||||
|
wire vld_out;
|
||||||
|
|
||||||
|
// 实例化被测模块
|
||||||
|
pulse_cnt #(
|
||||||
|
.CLK_FREQ(CLK_FREQ)
|
||||||
|
) dut (
|
||||||
|
.clk (clk),
|
||||||
|
.rst_n (rst_n),
|
||||||
|
.sig_in (sig_in),
|
||||||
|
.win_us (win_us),
|
||||||
|
.cnt_out(cnt_out),
|
||||||
|
.vld_out(vld_out)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 时钟生成
|
||||||
|
initial begin
|
||||||
|
clk = 0;
|
||||||
|
forever #(CLK_PERIOD/2) clk = ~clk;
|
||||||
|
end
|
||||||
|
|
||||||
|
// 测试激励
|
||||||
|
initial begin
|
||||||
|
// 初始化
|
||||||
|
rst_n = 0;
|
||||||
|
win_us = 24'd1000; // 默认窗口 1000 us = 1 ms
|
||||||
|
sig_in = 0;
|
||||||
|
|
||||||
|
// 释放复位
|
||||||
|
repeat(5) @(posedge clk);
|
||||||
|
rst_n = 1;
|
||||||
|
repeat(2) @(posedge clk);
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 测试1:窗口内无脉冲
|
||||||
|
// --------------------------------------------------
|
||||||
|
$display("Test 1: No pulse, expect cnt_out = 0 after window");
|
||||||
|
win_us = 24'd1000; // 1 ms 窗口
|
||||||
|
wait (vld_out);
|
||||||
|
$display(" cnt_out = %0d (expected 0)", cnt_out);
|
||||||
|
#(CLK_PERIOD*2);
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 测试2:固定频率脉冲 50 kHz (周期 20 us)
|
||||||
|
// --------------------------------------------------
|
||||||
|
$display("Test 2: 50 kHz pulse, window = 1 ms -> expected 50 pulses");
|
||||||
|
fork
|
||||||
|
begin : pulse_gen
|
||||||
|
forever begin
|
||||||
|
#10us sig_in = 1;
|
||||||
|
#10us sig_in = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
|
||||||
|
wait (vld_out);
|
||||||
|
$display(" cnt_out = %0d (expected 50)", cnt_out);
|
||||||
|
#(CLK_PERIOD*2);
|
||||||
|
disable pulse_gen;
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 测试3:脉冲频率 250 kHz (周期 2 us),窗口 1 ms -> 250 个脉冲
|
||||||
|
// --------------------------------------------------
|
||||||
|
$display("Test 3: 250 kHz pulse, window = 1 ms -> expected 250 pulses");
|
||||||
|
fork
|
||||||
|
begin : pulse_gen2
|
||||||
|
forever begin
|
||||||
|
#2us sig_in = 1;
|
||||||
|
#2us sig_in = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
|
||||||
|
wait (vld_out);
|
||||||
|
$display(" cnt_out = %0d (expected 250)", cnt_out);
|
||||||
|
#(CLK_PERIOD*2);
|
||||||
|
disable pulse_gen2;
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 测试4:动态改变窗口宽度 (2 ms),脉冲频率 250 kHz
|
||||||
|
// --------------------------------------------------
|
||||||
|
$display("Test 4: 250 kHz pulse, window = 2 ms -> expected 500 pulses");
|
||||||
|
win_us = 24'd2000; // 2 ms
|
||||||
|
|
||||||
|
// 重新启动一个脉冲生成进程
|
||||||
|
fork
|
||||||
|
begin : pulse_gen3
|
||||||
|
forever begin
|
||||||
|
#2us sig_in = 1; // 250 kHz -> 周期 4 us
|
||||||
|
#2us sig_in = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
|
||||||
|
wait (vld_out);
|
||||||
|
$display(" cnt_out = %0d (expected 500)", cnt_out);
|
||||||
|
#(CLK_PERIOD*2);
|
||||||
|
disable pulse_gen3;
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 测试5:边界情况 - 窗口极小 (1 us)
|
||||||
|
// --------------------------------------------------
|
||||||
|
$display("Test 5: 500 kHz pulse, window = 1 us -> expected 0.5? rounded to 0 or 1?");
|
||||||
|
win_us = 24'd2;
|
||||||
|
// 重新启动一个脉冲生成进程
|
||||||
|
fork
|
||||||
|
begin : pulse_gen4
|
||||||
|
forever begin
|
||||||
|
#1us sig_in = 1;
|
||||||
|
#1us sig_in = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
|
||||||
|
wait (vld_out);
|
||||||
|
$display(" cnt_out = %0d (expected 500)", cnt_out);
|
||||||
|
#(CLK_PERIOD*2);
|
||||||
|
disable pulse_gen4;
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 测试6:复位过程中行为
|
||||||
|
// --------------------------------------------------
|
||||||
|
$display("Test 6: Assert reset mid-window, check output goes to 0");
|
||||||
|
win_us = 24'd1000;
|
||||||
|
#(500us); // 窗口中间复位
|
||||||
|
rst_n = 0;
|
||||||
|
repeat(5) @(posedge clk);
|
||||||
|
rst_n = 1;
|
||||||
|
wait (vld_out);
|
||||||
|
$display(" cnt_out = %0d (should be fresh measurement)", cnt_out);
|
||||||
|
|
||||||
|
#(10us);
|
||||||
|
$display("Simulation finished.");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
// 监控输出有效标志并打印结果
|
||||||
|
always @(posedge vld_out) begin
|
||||||
|
$display("[%t] vld_out asserted, cnt_out = %0d", $time, cnt_out);
|
||||||
|
end
|
||||||
|
|
||||||
|
// 可选:波形转储
|
||||||
|
initial begin
|
||||||
|
$dumpfile("tb_pulse_cnt.vcd");
|
||||||
|
$dumpvars(0, tb_pulse_cnt);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue