双边沿计数器要在时钟的上升沿和下降沿都要计数的计数器。因此需要两个计数,即上升沿计数器和下降沿计数器作为辅助,如下图:
文章图片
可以观察到将上升沿和下降沿计数器相加就可以得到一个双边沿计数器。比较复杂的情况是两个计数器的置位条件。现在假设我们制作一个最大值为17的双边沿计数器,如下下图所示:
文章图片
我们可以看出当两个加速器加到最大值时候,需要一个计数器置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实现时钟的偶数与奇数分频
- Xilinx|Xilinx ISE系列教程(全网首发)
- 泛联新安EDA系列——国内自主研发,首款集成双国军标的HDL代码缺陷管理平台VHawk
- Verilog|(127)Verilog HDL(设计一个优先编码器之Always case2)
- Verilog|(128)Verilog HDL(设计一个优先编码器之Always casez)
- FPGA之旅设计99例|FPGA之旅设计99例之第十三例-----FPGA在OLED上显示DHT11数据
- FPGA刷题——数据位宽转换(整数倍&非整数倍)
- 视频处理|Syetem Verilog 将视频流输出写入 BMP 图片文件 testbench 激励代码
- 视频处理|Syetem Verilog 用BMP图片文件产生视频流 testbench 激励代码