计数器及其验证

基本理论

计数是一种最简单基本的运算,计数器就是实现这种运算的逻辑电路,计数器在数字 系统中主要是对脉冲的个数进行计数,以实现测量、计数和控制的功能,同时兼有分频功 能。计数器在数字系统中应用广泛,如在电子计算机的控制器中对指令地址进行计数,以 便顺序取出下一条指令,在运算器中作乘法、除法运算时记下加法、减法次数,又如在数 字仪器中对脉冲的计数等等。 计数器也是在 FPGA 设计中最常用的一种时序逻辑电路,根据计数器的计数值我们可 以精确的计算出 FPGA 内部各种信号之间的时间关系,每个信号何时拉高、何时拉低、拉 高多久、拉低多久都可以由计数器实现精确的控制。而让计数器计数的是由外部晶振产生 的时钟,所以可以比较精准的控制具体需要计数的时间。计数器一般都是从 0 开始计数, 计数到我们需要的值或者计数满溢出后清零,并可以进行不断的循环,3 位数的十进制计 数器最大可以计数到 999,4 位数的最大可以计数到 9999;3 位数的二进制计数器最大可以 计数到 111(7),4 位数的最大可以计数到 1111(15)。 

实例及验证

实例:使用计数器1s时间间隔,让led灯闪烁一次

模块框图

其中计数器计数的计算过程:

系统时钟频率为:f=50Mhz=5*10^7hz

系统的时钟周期为;T=1/f=2*10^-8s=20ns

1s需要多少时钟周期1s/20ns=5*10^7

所以,计数器从0开始所以需要计数(5*10^7)-1次才是1s。

波形绘制

方式一:计数到最大值二分之一减一,然后给led_out取反

方式二:由于是计数到最大值二分之一减一时led_out取反,所以最大值可以设置为(5*10^7)/2-1、

方式三:引入脉冲标志信号cnt_flag,当计数到二分之一最大值减一时产生一个周期的高脉冲信号,led_out在检测到cnt_flag拉高后产生一次翻转。

方式一代码实现(不带标志信号)

module  counter

#(

    parameter   CNT_MAX = 25'd24_999_999    )

(

    input   wire    sys_clk     ,   //系统时钟50MHz

    input   wire    sys_rst_n   ,   //全局复位

 

    output  reg     led_out         //输出控制led灯

);

 

reg     [24:0]  cnt;                //经计算得需要25位宽的寄存器才够500ms

 

//cnt:计数器计数,当计数到CNT_MAX的值时清零

always@(posedge sys_clk or negedge sys_rst_n)

    if(sys_rst_n == 1'b0)

        cnt <= 25'b0;

    else    if(cnt == CNT_MAX)

        cnt <= 25'b0;

    else

        cnt <= cnt + 1'b1;

//led_out:输出控制一个LED灯,每当计数满标志信号有效时取反

always@(posedge sys_clk or negedge sys_rst_n)

    if(sys_rst_n == 1'b0)

        led_out <= 1'b0;

    else    if(cnt == CNT_MAX)

        led_out <= ~led_out;

endmodule

 

方式一的RTL视图(不带标志信号)

如图最左边为一个加法器ADDER,加法器输入端为寄存器反馈值和1,输出接到了选择器MUX2_1输入,选择器输入为加法器输入,选择信号为比较器输出,当计数到最大值,则选择器输出为DATAB,起到了计数值清零的作用,与此同时触发器led_out取反输出一次。

方式二代码实现(带标志信号)

module counter

#(

    parameter   CNT_MAX = 25'd24_999_999

)

(

    input   wire    sys_clk  ,

    input   wire    sys_rst_n,

   

    output  reg    led_out  //在非阻塞赋值只能用于对寄存器类型变量进行赋值

);

 

reg         [24:0]  cnt;

reg                 cnt_flag;

 

always@(posedge sys_clk or negedge sys_rst_n)

    if(sys_rst_n == 1'b0)

        cnt <= 25'd0;

    else    if(cnt == CNT_MAX)//计数到最大之清零

        cnt <= 25'd0;

    else                      //未到最大加一

        cnt <= cnt + 25'd1;

       

       

always@(posedge sys_clk or negedge sys_rst_n)

    if(sys_rst_n == 1'b0)

        cnt_flag <= 1'b0;

    else    if(cnt == (CNT_MAX - 25'd1))//计数到最大值减一产生一个高脉冲信号

        cnt_flag <= 1'b1;

    else

        cnt_flag <= 1'b0;

 

always@(posedge sys_clk or negedge sys_rst_n)       

    if(sys_rst_n == 1'b0)

        led_out <= 1'b0;

    else    if(cnt_flag == 1'b1)//检测到高脉冲led_out反转一次

        led_out <= ~led_out;

    else

        led_out <= led_out;

endmodule

方式二的RTL视图(带标志信号)

与方式一相比较,增加了一个比较器EQUAL用于判断是否计数到最大值减一,还增加了一个D触发器cnt_flag。

 parameter与localparam的区别

*parameter可以写在端口列表进行参数传递

//parameter   CNT_MAX = 24_999_999;

//localparam  CNT_MAX = 24_999_999;

例如

module counter

#(

    parameter   CNT_MAX = 24_999_999,

 )

(

    input   wire    sys_clk  ,

    input   wire    sys_rst_n,

   

    output  wire    led_out 

);

例化时可以修改参数,注意实例化名称位置

counter

#(

    .CNT_MAX(100),

 )

 counter_inst0

(

    .sys_clk  (),

    .sys_rst_n(),

  

    .led_out  (),

);

counter

#(

    .CNT_MAX(10000),

 )

 counter_inst1

(

    .sys_clk  (),

    .sys_rst_n(),

  

    .led_out  (),

);

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值