//测量输入信号的正、负脉宽
//输出数据为脉冲所占时钟周期数
`define WIDTH 16
module pulse_width_detect
(
//输入标准时钟
//输入复位信号
//输入使能输出
//输入待测信号
//输入选择输出
input i_clk,
input i_rstn,
input i_en_o,
input i_sig,
input i_sel,
output o_data_ok,
output [`WIDTH-1:0]o_data //输出数据
//输出数据有效
);
//r_sig 输入信号寄存器
//将输入信号与系统时钟同步化
reg r_sig;
always @(posedge i_clk)
if(!i_rstn)
r_sig<=0;
else
r_sig<=i_sig;
//r_rstn 复位信号寄存器
//用于检测复位信号的变化沿
reg r_rstn;
always @(posedge i_clk)
r_rstn <= i_rstn;
//r_start、r_end 输入信号边沿寄存器
//有效时分别表示 i_sig 的上升沿、下降沿
reg r_start;
reg r_end;
always @(posedge i_clk)
if(!i_rstn) begin
r_start<=0;
r_end <= 0;
end else begin
r_start<=(i_sig ==1 && r_sig == 0 && r_rstn == 1) ? 'b1 :'b0;//上升沿
r_end <=(i_sig ==0 && r_sig == 1 && r_rstn == 1) ? 'b1 :'b0;//下跳沿
end
reg [`WIDTH-1:0]r_pos;
reg [`WIDTH-1:0]r_neg;
//r_start_pos、r_start_neg 高、低电平计时器开关
//有效时分别表示允许对高、低电平计时器计时
reg r_start_pos;
reg r_start_neg;
always @(posedge i_clk)
if(!i_rstn) begin
r_start_pos<=0;
r_start_neg<=0;
end else begin
if(r_start) begin//在上升沿开始测量高电平周期
if(r_pos ==0) r_start_pos <= 1;
r_start_neg <= 0;
end else if(r_end) begin//在下降沿开始测量低电平周期
r_start_pos <= 0;
if(r_neg ==0) r_start_neg <= 1;
end
end
//每个时钟上升沿对有效输入信号计时
always @(posedge i_clk)
if(!i_rstn)
r_pos<=0;
else
if(r_start_pos)
r_pos <= r_pos + 1;
//每个时钟上升沿对有效输入信号计时
always @(posedge i_clk)
if(!i_rstn)
r_neg<=0;
else
if(r_start_neg)
r_neg <= r_neg + 1;
//测量时输出无效、不测量时输出有效
assign o_data_ok = ( r_start_pos |r_start_neg ) ? 'b0 : 'b1 ;
//当禁止输出时输出高阻;允许输出时,根据 i_sel 确定输出数据
assign o_data = i_en_o ? (i_sel ? r_pos : r_neg ): 'bz ;
endmodule
;
测量向量
`define WIDTH 16
module freq_tb
;
;
;
;
;
i_sel
o_data_ok
i_en_o
;
i_clk
[`WIDTH-1:0] o_data
i_sig
i_rstn
reg
wire
reg
reg
wire
reg
reg
;
pulse_width_detect
DUT (
.i_sel (i_sel ) ,
.o_data_ok (o_data_ok ) ,
.i_en_o (i_en_o ) ,
.i_clk (i_clk ) ,
.o_data (o_data ) ,
.i_sig (i_sig ) ,
.i_rstn (i_rstn ) );
initial begin
i_clk = 0;
i_sig = 0;
i_rstn = 0;
i_sel = 0;
#200
i_rstn = 1;
end
initial begin
i_en_o = 1;
#2000
i_en_o = 0;
#1000
i_en_o = 1;
end
always #50 i_clk = ~i_clk ;
reg [8:0]cnt;
always @(posedge i_clk)
if(!i_rstn)
cnt<=0;
else
cnt<=cnt+ 1;
reg [12:0]cnt1;
always @(posedge i_clk)
if(!i_rstn)
cnt1<=0;
else
cnt1<=cnt1+ 1;
always @(posedge i_clk)
if(cnt1 == 12'hfff)
begin
i_rstn = 0;
#200
i_rstn = 1;
end
always @(posedge i_clk)
if(cnt == 128)
i_sig <= {$random}%2;
always @(posedge i_clk)
if(cnt == 10 )
i_sel <= ~ i_sel ;
endmodule