改进温度计模块-》pulse_cnt ,验证仿真无误

This commit is contained in:
yangshenbo 2026-04-05 16:37:54 +08:00
parent 9e3862f694
commit 81852b1579
3 changed files with 220 additions and 71 deletions

60
rtl/pulse_cnt.v Normal file
View File

@ -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

View File

@ -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

160
tb/tb_pulse_cnt.sv Normal file
View File

@ -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