【FPGA/verilog -入门学习3】verilog脉冲计数

需求:

1,在EN为高电平时,对输入的Pluse 脉冲计数,每个上升沿计数一次

2,EN 为低电平时,输出计数值和计数完成状态

需求分析:

【FPGA/verilog -入门学习3】verilog脉冲计数_第1张图片

输入输出

输入:clk,rest_n,i_en,pluse

输出:o_cnt ,o_state

操作步骤

输入端推进:

步骤1,对pluse 进行脉冲边沿检测,识别出每次上升沿,用于后续的计数

输出端获取:

步骤2,对输出o_state 实现方式:在每一次en=0 时识别为计数结束。可以用脉冲边沿检测法,检测en信号的下降沿作为o_state 的结束信号

【FPGA/verilog -入门学习3】verilog脉冲计数_第2张图片

步骤3:使用内部寄存器r_cnt ,当en=1时,pluse 的上升沿脉冲计数。计数到en= 0 时清零。

步骤4:当en = 0时,且r_cnt 有数值,将o_cnt <=r_cnt.

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 rest_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(!rest_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(!rest_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(!rest_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(!rest_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

testbench_top


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

//参数定义

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


//接口申明
    
reg clk;
reg pulse;
reg rest_n;
reg i_en;
wire [31:0] o_cnt;
wire o_state;

 
    
vlg_design        uut_vlg_design(
    .clk(clk),
    .pulse(pulse),
    .rest_n(rest_n),
    .i_en(i_en),
    .o_cnt(o_cnt),
    .o_state(o_state)
    );    
    
//时钟和复位初始化、复位产生 
initial begin
clk <= 0;
rest_n <= 0;
#10;
rest_n <= 1;
clk <= 1;
pulse <= 1'b0; 
i_en <= 0;
end

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

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


 
i_en <= 1;
@(posedge clk);


for (i = 0; i < 16; i = i+1) begin 
    pulse = ~pulse;  
    repeat(3)@(posedge clk);
end  
 
i_en <= 0;
@(posedge clk);


i_en <= 0;
 
    for (i = 0; i < 16; i = i+1) begin 
        pulse = ~pulse;  
        repeat(3)@(posedge clk);
    end  
 
i_en <= 0;
@(posedge clk); 
 


i_en <= 1; 
@(posedge clk);
 
for (i = 0; i < 6; i = i+1) begin 
    pulse = ~pulse;  
    repeat(5)@(posedge clk);
end  
 
i_en <= 0;
@(posedge clk);

 

#2_000_000;
$stop;
end

endmodule

仿真结果

【FPGA/verilog -入门学习3】verilog脉冲计数_第3张图片

难点分析

1,按模块划分,

//产生一个pluse 上升沿脉冲时钟

//产生一个i_en 下降沿脉冲时钟 //en 下降沿时 o_state =1

//EN = 1时候计数

//输出o_cnt

各模块的赋值部分,相互独立,各自处理各自判断,防止时序偏差

你可能感兴趣的:(verilog,&FPGA,fpga开发,学习)