计数器(3):避免多计少计

  计数器,FPGA设计中最常用的设计,然而有些地方需要多加注意。

一、勿要多计

  打算计10下,所以我计数器就写计到10:cnt==10,程序如下所示。

1、设计文件

 1 module jsq
 2 //========================< 端口 >==========================================
 3 (
 4 input   wire                clk                 ,
 5 input   wire                rst_n               ,
 6 input   wire                en                  ,
 7 output  reg   [ 4:0]        cnt                 
 8 );
 9 //========================< 信号 >==========================================
10 reg                         en_flag             ;
11 wire                        add_cnt             ;
12 wire                        end_cnt             ;
13 
14 //========================< 程序 >==========================================
15 always @(posedge clk or negedge rst_n) begin
16     if(!rst_n) begin
17         en_flag <= 0;
18     end
19     else if(en) begin
20         en_flag <= 1;
21     end
22     else if(end_cnt) begin
23         en_flag <= 0;
24     end
25 end
26 
27 always @(posedge clk or negedge rst_n) begin
28     if(!rst_n)
29         cnt <= 0;
30     else if(add_cnt) begin
31         if(end_cnt)
32             cnt <= 0;
33         else
34             cnt <= cnt + 1;
35     end
36 end
37 
38 assign add_cnt = en_flag;
39 assign end_cnt = add_cnt && cnt== 10; //我想计10下
40 
41 
42 
43 endmodule

2、仿真文件

 1 `timescale 1ns/1ps  //时间精度
 2 `define    Clock 20 //时钟周期
 3 
 4 module jsq_tb;
 5 
 6 //========================< 端口 >==========================================
 7 reg                         clk                 ; //时钟,50Mhz
 8 reg                         rst_n               ; //复位,低电平有效
 9 reg                         en                  ;
10 wire  [ 4:0]                cnt                 ;
11 
12 //==========================================================================
13 //==    模块例化
14 //==========================================================================
15 jsq u_jsq
16 (
17     .clk                    (clk                ),
18     .rst_n                  (rst_n              ),
19     .en                     (en                 ),
20     .cnt                    (cnt                )
21 );
22 
23 //==========================================================================
24 //==    时钟信号和复位信号
25 //==========================================================================
26 initial begin
27     clk = 1;
28     forever
29         #(`Clock/2) clk = ~clk;
30 end
31 
32 initial begin
33     rst_n = 0; #(`Clock*20+1);
34     rst_n = 1;
35 end
36 
37 //==========================================================================
38 //==    设计输入信号
39 //==========================================================================
40 initial begin
41     en = 0;
42     #(`Clock*20+1); //初始化完成
43     en = 1;
44     #(`Clock*10);
45     en = 0;
46     #(`Clock*100);
47     $stop;
48 end
49 
50 
51 
52 endmodule

3、Modelsim仿真图像

  观察图像可以看到,计数器 cnt 计到了 cnt==10 这里,可是当我仔细数数时却发现,计数是从 0 开始计的,从 0 到 10,所以实际计了 11 下!和我之前写代码时脑中所想不一致!所以,如果只想计10下,那实际写代码应该写 9 才对。

  总结:计数器想计 n 下,那写代码只能写 cnt==n-1。

 

二、勿要少记

  数据 data 和数据使能 data_en 同时来,我想数一下到底来了多少个数据。

1、代码设计

 1 module jsq
 2 (
 3 input   wire                clk                 ,
 4 input   wire                rst_n               ,
 5 input   wire  [ 3:0]        data                ,
 6 input   wire                data_en             ,
 7 output  reg   [ 3:0]        cnt                 
 8 );
 9 
10 always @(posedge clk or negedge rst_n) begin
11     if(!rst_n) begin
12         cnt <= 0;
13     end
14     else if(data_en) begin
15         cnt <= cnt + 1;
16     end
17     else begin
18         cnt <= 0;
19     end
20 end
21 
22 
23 endmodule

2、仿真设计

 1 `timescale 1ns/1ps  //时间精度
 2 `define    Clock 20 //时钟周期
 3 
 4 module jsq_tb;
 5 
 6 //========================< 端口 >==========================================
 7 reg                         clk                 ; //时钟,50Mhz
 8 reg                         rst_n               ; //复位,低电平有效
 9 reg   [ 3:0]                data                ;
10 reg                         data_en             ;
11 wire  [ 4:0]                cnt                 ;
12 
13 //==========================================================================
14 //==    模块例化
15 //==========================================================================
16 jsq u_jsq
17 (
18     .clk                    (clk                ),
19     .rst_n                  (rst_n              ),
20     .data                   (data               ),
21     .data_en                (data_en            ),
22     .cnt                    (cnt                )
23 );
24 
25 //==========================================================================
26 //==    时钟信号和复位信号
27 //==========================================================================
28 initial begin
29     clk = 1;
30     forever
31         #(`Clock/2) clk = ~clk;
32 end
33 
34 initial begin
35     rst_n = 0; #(`Clock*20+1);
36     rst_n = 1;
37 end
38 
39 //==========================================================================
40 //==    设计输入信号
41 //==========================================================================
42 initial begin
43     data_en = 0;
44     data = 0;
45     #(`Clock*20+1); //初始化完成
46     
47     data_en = 1;
48     data = 0;
49     #(`Clock);
50     data = 1;
51     #(`Clock);
52     data = 2;
53     #(`Clock);
54     data = 3;
55     #(`Clock);
56     data = 4;
57     #(`Clock);
58     data = 5;
59     #(`Clock);
60     data = 6;
61     #(`Clock);
62     data = 7;
63     #(`Clock);
64     data = 8;
65     #(`Clock);
66     data = 9;
67     #(`Clock);
68     data = 0;
69     data_en = 0;
70     
71     #(`Clock*100);
72     $stop;
73 end
74 
75 
76 
77 endmodule

3、Modelsim仿真图像

  观察图像可以看到,计数器 cnt 计到了 cnt==10 这里,而我的 data_en 确实是维持了 10 个周期的。这种情况下,cnt 计到多少就是多少,第0下是不作数的。如果按照上面的情况,以为真实计数是 10-1=9下,反而是错的了。当然如果其他信号需要用到 cnt来搞事情,那还是需要写 cnt==n-1的,这就又回到上面第一种情况了。

  此外 cnt 较 data_en 延后了一个周期,当 data_en 都拉低了,而后 cnt 才计到 cnt==10,这是时序逻辑的特点,并非出错。

  总结:计数器计算一段波形的持续时间,最终即到 cnt==n,那波形时间就是n,不需要 -1。

posted @ 2019-05-04 19:26  咸鱼IC  阅读(1085)  评论(0编辑  收藏  举报