verilog实战|双边沿计数器verilog设计(详细说明)

双边沿计数器要在时钟的上升沿和下降沿都要计数的计数器。因此需要两个计数,即上升沿计数器和下降沿计数器作为辅助,如下图:
verilog实战|双边沿计数器verilog设计(详细说明)
文章图片

可以观察到将上升沿和下降沿计数器相加就可以得到一个双边沿计数器。比较复杂的情况是两个计数器的置位条件。现在假设我们制作一个最大值为17的双边沿计数器,如下下图所示:verilog实战|双边沿计数器verilog设计(详细说明)
文章图片

我们可以看出当两个加速器加到最大值时候,需要一个计数器置0,另一个计数器置1.若是在上升沿检测到加和为最大值,则将上升沿计数器置0。否则则将下降沿计数器置0。因此就需要为这两个计数器声明两个置1信号,如果置1信号为高时,则在下一个时钟周期将对应的计数器置为1。此外还需要说明的时,这两个计数器的各自的计数最大值,就是要双边沿计数最大值的一半即可。具体代码如下,有详细的注释:

//function:实现双边沿的计数器 //date:2022/08/31module double_edge_cnt #( parameterMAX=100//计数的最大值 )( inputwireclk, inputwirerst_n,outputwire[31:0]d_cnt ); wireeven_flag; //偶数标志 wire[31:0]HALF_MAX; reg[31:0]cnt_posedge; //上升沿计数器 reg[31:0]cnt_negedge; //下降沿计数器 regset_one_flag_pos; //上升沿计数器置1信号 regset_one_flas_neg; //下降沿计数器置1信号assign even_flag = (MAX[0] == 1'b0) ? 1'b1 : 1'b0; //判断MAX是不是偶数 assign HALF_MAX = even_flag ? MAX >> 1 : (MAX >> 1) + 1'b1; //MAX一半always @(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt_posedge <= 32'd0; set_one_flag_pos <= 1'b0; end else if((cnt_negedge + cnt_posedge == MAX)) begin//上升沿检测到加和最大值, cnt_posedge <= 32'd0; end else if(cnt_negedge + cnt_posedge == MAX - 1'b1) begin//上升沿检测到加和最大值减1,说明会在下降沿检测到最大值 set_one_flag_pos <= 1'b1; //因此拉高置1信号 cnt_posedge <= cnt_posedge + 1'b1; end else if(set_one_flag_pos) begin//置1信号为高,置位 set_one_flag_pos <= 1'b0; cnt_posedge <= 32'd1; end else begin cnt_posedge <= cnt_posedge + 1'b1; end endalways @(negedge clk or negedge rst_n) begin if(!rst_n) begin cnt_negedge <= 32'd0; set_one_flas_neg <= 1'b0; end else if(cnt_negedge + cnt_posedge == MAX) begin//下降沿检测到最大值 cnt_negedge <= 32'd0; end else if(cnt_negedge + cnt_posedge == MAX - 1'b1) begin//下降沿检测到最大值减1,说明会在上升沿检测到最大值 set_one_flas_neg <= 1'b1; //因此拉高下降沿计数器置1信号 cnt_negedge <= cnt_negedge + 1'b1; end else if(set_one_flas_neg) begin//置1信号为高 set_one_flas_neg <= 1'b0; cnt_negedge <= 32'd1; end else begin cnt_negedge <= cnt_negedge + 1'b1; end end//为双边沿计数器赋值 assign d_cnt = (((cnt_posedge == HALF_MAX) && (cnt_negedge == 'd0)) || ((cnt_posedge == 'd0) && (cnt_negedge == HALF_MAX))) ? 32'd0 : cnt_negedge + cnt_posedge; endmodule

testbench如下:
`timescale 1ns/1ns `define CLK_CYCLE 20 module tb_double_edge_cnt; regclk; regrst_n; wire[31:0]d_cnt; double_edge_cnt # ( 99 )u_double_edge_cnt( .clk(clk), .rst_n(rst_n) ,.d_cnt(d_cnt) ); initial begin clk = 1'b0; rst_n = 1'b0; #200 rst_n = 1'b1; #40000; //$finish; endalways # (`CLK_CYCLE/2) clk = ~clk; endmodule

【verilog实战|双边沿计数器verilog设计(详细说明)】仿真波形图:
verilog实战|双边沿计数器verilog设计(详细说明)
文章图片

    推荐阅读