【FPGA/verilog -入门学习4】verilog 实现多路脉冲计数

2023-12-14 17:32:37

需求:

设计一个脉冲计数器,其功能如下

输入脉冲:4路脉冲信号,分别对每路进行脉冲检测并计数

使能信号:高电平进行计数,低电平清零计数器

计数器:在使能信号高电平期间,对脉冲信号的上升沿进行检测并递增计数值

编写测试脚本,进行仿真验证

需求分析:

使用上一章的一路脉冲检测,使用例化方式产生多路

vlg_design

使用上章节生成的最小系统

/
/*
脉冲计数,当是能时,对pluse脉冲计数
实现步骤
1)产生pluse 上升沿脉冲 一个clk时钟
2)产生i_en 下降沿,当下降沿 o_state=1
3)对pluse上升沿计数,锁存在r_cnt
4)当o_state=1 时,o_cnt<=r_cnt
 
 */
/
`timescale 1ns/1ps
module vlg_design(
    input clk,//100M
    input pulse,// 
    input reset_n,
    input  i_en,  
    output reg[31:0] o_cnt,  //输出计数值
    output  o_state
    );
    

reg [1:0] r_pluse;
reg [1:0] r_en;
wire w_pluse_pos;
wire w_en_neg;
reg[31:0] r_cnt;

//产生一个pluse 上升沿脉冲时钟
 always @(posedge clk) begin
    if(!reset_n) r_pluse <='b00;
    else  r_pluse <= {r_pluse[0],pulse};
 end 
assign w_pluse_pos = r_pluse[0] & ~r_pluse[1];


//产生一个i_en 下降沿脉冲时钟
//en 下降沿时 o_state =1
 always @(posedge clk) begin
    if(!reset_n) r_en <='b00;
    else  r_en <= {r_en[0],i_en};
 end 
assign o_state = r_en[1] & ~r_en[0];

 


//EN = 1时候计数
 always @(posedge clk) begin
    if(!reset_n) r_cnt <= 'b0;
    else if(i_en)
            if(w_pluse_pos)r_cnt <= r_cnt + 1'b1;
            else ; 
         else  r_cnt <= 'b0;
end



//输出o_cnt
always @(posedge clk) begin
    if(!reset_n) o_cnt  <= 'b0;
    else if(!i_en && r_cnt)  begin
        o_cnt <= r_cnt;
        $display("r_cnt=%d\n",r_cnt);//显示
        end
    else o_cnt  <= 'b0;
end
 

endmodule

vlg_cnt4

创建需求功能模块

1,端口定义

input[3:0]pulse //多个输入,数据是并行的,定义方式

output [31:0]o_cnt_0, //数据也是并行的,用o_cnt_0~o_cnt_3

output [31:0]o_cnt_1,

output [31:0]o_cnt_2,

output [31:0]o_cnt_3,

output [3:0]o_state //输出状态

2,例化最小模块


/
`timescale 1ns/1ps
module vlg_cnt4(
    input clk,//100M
    input [3:0]pulse,// 
    input reset_n,
    input  i_en,  

    output [31:0]o_cnt_0,
    output [31:0]o_cnt_1,
    output [31:0]o_cnt_2,
    output [31:0]o_cnt_3,  //输出计数值
    output  [3:0]o_state    
    );
    

vlg_design uut0_vlg_design(

.clk(clk),
.pulse(pulse[0]),
.reset_n(reset_n),
.i_en(i_en),
.o_cnt(o_cnt_0),
.o_state(o_state[0])
);

vlg_design uut1_vlg_design(

.clk(clk),
.pulse(pulse[1]),
.reset_n(reset_n),
.i_en(i_en),
.o_cnt(o_cnt_1),
.o_state(o_state[1])
);

vlg_design uut2_vlg_design(

.clk(clk),
.pulse(pulse[2]),
.reset_n(reset_n),
.i_en(i_en),
.o_cnt(o_cnt_2),
.o_state(o_state[2])
);

vlg_design uut3_vlg_design(

.clk(clk),
.pulse(pulse[3]),
.reset_n(reset_n),
.i_en(i_en),
.o_cnt(o_cnt_3),
.o_state(o_state[3])
);



endmodule

testbench_top

//仿真文件

//随机数产生

rand = $random%100;不带{} 产生的是有符号的数字,范围是-99~99

rand = {$random}%100;使用带{} 表示产生的是正数,%后面的数表示数据的范围0~99

rand = 30 +{$random}%100 ;范围 30~129


`timescale 1ns/1ps
module testbench_top();
    

//参数定义

`define CLK_PERIORD        10        //时钟周期设置为10ns(100MHz)    


//接口申明
    
reg clk;
reg [3:0]pulse;
reg reset_n;
reg i_en;
wire[31:0] o_cnt_0;
wire[31:0] o_cnt_1;
wire[31:0] o_cnt_2;
wire[31:0] o_cnt_3;
wire [3:0]o_state;

 
    
vlg_cnt4        uut_vlg_cnt4(
    .clk(clk),
    .pulse(pulse),
    .reset_n(reset_n),
    .i_en(i_en),
    .o_cnt_0(o_cnt_0),
    .o_cnt_1(o_cnt_1),
    .o_cnt_2(o_cnt_2),
    .o_cnt_3(o_cnt_3),    
    .o_state(o_state)
    );    
    
//时钟和复位初始化、复位产生 
initial begin
clk <= 0;
reset_n <= 0;
#10;
reset_n <= 1;
clk <= 1;
pulse <= 4'b0000; 
i_en <= 0;
end

//时钟产生
always #(`CLK_PERIORD/2) clk = ~clk;    
integer i;
    
 
//测试激励产生
initial begin

    @(posedge reset_n);    //等待复位完成
    @(posedge clk);


 //生成一个4位的0~15的随机数,赋值给pluse
i_en <= 1;
@(posedge clk);

for(i = 0;i < 10;i = i+1) begin
    pulse  <=  {$random} % 15;
    repeat(3)@(posedge clk);
end
pulse <= 4'b0000; 
i_en <= 0;

#2_000_000;
 //生成一个4位的0~15的随机数,赋值给pluse
i_en <= 1;
@(posedge clk);

for(i = 0;i < 5;i = i+1) begin
    pulse  <=  {$random} % 15;
    repeat(3)@(posedge clk);
end
pulse <= 4'b0000; 
i_en <= 0;



@(posedge clk);
#2_000_000;
$stop;
end

endmodule

仿真结果

文章来源:https://blog.csdn.net/cengqiu4314/article/details/134887412
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。