概述
双边沿计数器要在时钟的上升沿和下降沿都要计数的计数器。因此需要两个计数,即上升沿计数器和下降沿计数器作为辅助,如下图:
可以观察到将上升沿和下降沿计数器相加就可以得到一个双边沿计数器。比较复杂的情况是两个计数器的置位条件。现在假设我们制作一个最大值为17的双边沿计数器,如下下图所示:
我们可以看出当两个加速器加到最大值时候,需要一个计数器置0,另一个计数器置1.若是在上升沿检测到加和为最大值,则将上升沿计数器置0。否则则将下降沿计数器置0。因此就需要为这两个计数器声明两个置1信号,如果置1信号为高时,则在下一个时钟周期将对应的计数器置为1。此外还需要说明的时,这两个计数器的各自的计数最大值,就是要双边沿计数最大值的一半即可。具体代码如下,有详细的注释:
//function:实现双边沿的计数器
//date:2022/08/31
module double_edge_cnt #(
parameter MAX = 100 //计数的最大值
)
(
input wire clk ,
input wire rst_n ,
output wire [31:0] d_cnt
);
wire even_flag ; //偶数标志
wire [31:0] HALF_MAX ;
reg [31:0] cnt_posedge ; //上升沿计数器
reg [31:0] cnt_negedge ; //下降沿计数器
reg set_one_flag_pos; //上升沿计数器置1信号
reg set_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
end
always @(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;
reg clk ;
reg rst_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;
end
always # (`CLK_CYCLE/2) clk = ~clk;
endmodule
仿真波形图:
最后
以上就是天真画板为你收集整理的双边沿计数器verilog设计(详细说明)的全部内容,希望文章能够帮你解决双边沿计数器verilog设计(详细说明)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复