集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 1034|回复: 5

基于至简设计法的数字时钟设计

[复制链接]
fpga_wuhan 发表于 2017-2-21 09:28:15 | 显示全部楼层 |阅读模式

转载于电子工程网

数字时钟是常见的毕业设计题目。我们做毕业设计时,一般使用数码管来显示数字。小时、分钟和秒钟各两位数字,所以需要用到6位的数码管。

如果平时不动手,要做这个毕业设计,很多人都会觉得挺难的。收集到的代码,其风格也是五花八门,第一感觉是貌似能看懂,但就是不知道怎么设计出来的。

其实如果有正确的设计思路和方法,其实现起来是非常简单的。下面我们就核心的数字模块为例,讲解如何使用至简设计法来实现。

数字模块的功能,是产生6个信号,分别表示时十位、时个位、分十位、分个位、秒十位和秒个位的值。例如上述信号值依次为2、1、4、3、5、9时,则表示时间为21点43分59秒。

仔细观察6个信号,每个单独来看,其数字都是递增的,增加到一定数后就清零。以秒个位为例,开始时值为0,然后是1、2、3依次增加,直到变成9后,然后变成0,再次循环。其他信号都是相同的规律。这些依次递增的信号,就是计数器。

我们认识到这些信号是计数器,那就好办了,擅长就是计数器的设计。计数器设计只需要考虑两点,什么时候加1和要数多少个,明确这两个问题后,剩下的就是套用计数器模板了。

以秒个位这个计数器为例,这个计数器加1的条件是什么呢?到了1秒就加1。那我们怎么知道1秒钟时间到了呢?FPGA是通过数时钟周期数来确定时间的。例如下图,假设时钟频率是50MHz,即时钟周期是20ns,cnt是每个时钟加1,则当cnt==99时,就说明数了100个时钟周期,也就是时间是100*20=2000ns了。

QQ图片20170215151757.png



同样的道理,1秒钟时间,我们就是数1s/20ns= 50_000_000个时钟周期。我们也认识到这个cnt也是计数器,其加1条件是“1”,要数50_000_000个数。我们套用计数器模块,即有下面代码。



1
  

2
  

3
  

4
  

5
  

6
  

7
  

8
  

9
  

10
  

11
  

12
  

13
  

14

       

always @(posedge clk or negedge  rst_n)begin
  

        if(!rst_n)begin
  

            cnt <= 0;
  

        end
  

        else if(add_cnt)begin
  

            if(end_cnt)
  

                cnt <= 0;
  

            else
  

                cnt <= cnt + 1;
  

        end
  

     end
  
  

     assign add_cnt = 1 ;      
  

     assign end_cnt = add_cnt && cnt== 50_000_000-1;   



代码中,always语句除了名字后,完全套用模板,不用更改。加1条件体现在第13行,要数多少个体现在第14行。

确定了cnt后,那么秒个位的加1条件就非常明确了,就是cnt数到50_000_000个,也就是end_cnt有效的时候。所以秒个位的加1条件是end_cnt。

秒个位要数多少个数字呢?由0到9,因此有10个。

综上所述,我们得到秒个位的代码如下表。



1
  

2
  

3
  

4
  

5
  

6
  

7
  

8
  

9
  

10
  

11
  

12
  

13
  

14

       

always@(posedge clk or negedge  rst_n)begin
  

        if(rst_n==1'b0)begin
  

            miao_g <= 0;
  

        end
  

        else if(add_miao_g)begin
  

            if(end_miao_g)
  

                miao_g <= 0;
  

            else
  

                miao_g <= miao_g + 1;
  

        end
  

     end
  
  

     assign add_miao_g = end_cnt;
  

     assign end_miao_g = add_miao_g && miao_g == 10-1;



用类似于秒个位的思考方法,我们可以得到秒十位、分个位、分十位、时个位和时十位的代码,完整的代码如下表。



1
  

2
  

3
  

4
  

5
  

6
  

7
  

8
  

9
  

10
  

11
  

12
  

13
  

14
  

15
  

16
  

17
  

18
  

19
  

20
  

21
  

22
  

23
  

24
  

25
  

26
  

27
  

28
  

29
  

30
  

31
  

32
  

33
  

34
  

35
  

36
  

37
  

38
  

39
  

40
  

41
  

42
  

43
  

44
  

45
  

46
  

47
  

48
  

49
  

50
  

51
  

52
  

53
  

54
  

55
  

56
  

57
  

58
  

59
  

60
  

61
  

62
  

63
  

64
  

65
  

66
  

67
  

68
  

69
  

70
  

71
  

72
  

73
  

74
  

75
  

76
  

77
  

78
  

79
  

80
  

81
  

82
  

83
  

84
  

85
  

86
  

87
  

88
  

89
  

90
  

91
  

92
  

93
  

94
  

95
  

96
  

97
  

98
  

99
  

100
  

101
  

102
  

103
  

104
  

105
  

106
  

107
  

108
  

109
  

110
  

111
  

112
  

113
  

114
  

115
  

116
  

117
  

118
  

119
  

120
  

121
  

122
  

123

       

always @(posedge clk or negedge rst_n)begin
  

        if(!rst_n)begin
  

            cnt <= 0;
  

        end
  

        else  if(add_cnt)begin
  

            if(end_cnt)
  

                cnt <= 0;
  

            else
  

                cnt <=  cnt + 1;
  

        end
  

    end
  
  

    assign add_cnt = 1  ;      
  

    assign end_cnt = add_cnt  && cnt== 50_000_000-1;   
  
  

    always@(posedge clk or  negedge rst_n)begin
  

        if(rst_n==1'b0)begin
  

            miao_g <= 0;
  

        end
  

        else if(add_miao_g)begin
  

             if(end_miao_g)begin
  

                miao_g <=  0;
  

            end
  

            else begin
  

                miao_g <=  miao_g + 1;
  

            end
  

        end
  

    end
  
  

    assign add_miao_g =  end_cnt;
  

    assign end_miao_g =  add_miao_g && miao_g == 10-1;
  
  

    always  @(posedge clk or negedge rst_n)begin
  

        if(rst_n==1'b0)begin
  

            miao_s <= 0;
  

        end
  

        else  if(add_miao_s)begin
  

             if(end_miao_s)begin
  

                miao_s <=  0;
  

            end
  

            else begin
  

                miao_s <=  miao_s + 1;
  

            end
  

        end
  

    end
  
  

    assign add_miao_s =  end_miao_g;
  

    assign end_miao_s =  add_miao_s && miao_s == 6-1;
  
  

    always  @(posedge clk or negedge rst_n)begin
  

        if(rst_n==1'b0)begin
  

            fen_g <= 0;
  

        end
  

        else  if(add_fen_g)begin
  

             if(end_fen_g)begin
  

                fen_g <=  0;
  

            end
  

            else begin
  

                fen_g <=  fen_g + 1;
  

            end
  

        end
  

    end
  
  

    assign add_fen_g =  end_miao_s;
  

    assign end_fen_g =  add_fen_g && fen_g == 10-1;
  
  

    always  @(posedge clk or negedge rst_n)begin
  

        if(rst_n==1'b0)begin
  

            fen_s <= 0;
  

        end
  

        else  if(add_fen_s)begin
  

             if(end_fen_s)begin
  

                fen_s <= 0;
  

            end
  

            else begin
  

                fen_s <=  fen_s + 1;
  

            end
  

        end
  

    end
  
  

    assign add_fen_s =  end_fen_g;
  

    assign end_fen_s =  add_fen_s && fen_s == 6-1;
  
  

    always  @(posedge clk or negedge rst_n)begin
  

        if(rst_n==1'b0)begin
  

            shi_g <= 0;
  

        end
  

        else  if(add_shi_g)begin
  

             if(end_shi_g)begin
  

                shi_g <=  0;
  

            end
  

            else begin
  

                shi_g <=  shi_g + 1;
  

            end
  

        end
  

    end
  
  

    assign add_shi_g =  end_fen_s;
  

    assign end_shi_g =  add_shi_g &&  shi_g ==x-1;
  
  

    always  @(posedge clk or negedge rst_n)begin
  

        if(rst_n==1'b0)begin
  

            shi_s <= 0;
  

        end
  

        else  if(add_shi_s)begin
  

             if(end_shi_s)begin
  

                shi_s <=  0;
  

            end
  

            else begin
  

                shi_s <=  shi_s + 1;
  

            end
  

        end
  

    end
  
  

    assign add_shi_s =  end_shi_g;
  

assign end_shi_s = add_shi_s && shi_s == 3-1;
  
  

always@(*)begin
  

         if(shi_s==2)
  

            x  =4;
  

        else
  

            x  =10;
  

end
  




细心的读者可以发现,上面每段计数器格式都非常相似。没错,这就是的技巧。我们设计的这套模板,基本上可以应用于任何场合,任何时候读者只考虑两个因素就够了,不会出现丢三落四的情况,而且每次只需要考虑一个因素,保证能做出最优的设计。

如果你还未发现这代码优秀的地方,建议你百度下数字时钟的代码,好好比一比,特别是好好想想我们的设计思路,明德扬是有方法有步骤、可以做到一次性设计对,而他们的则是想到哪写到哪,每次设计都不同的想法。每次设计都是不同的思想,水平怎么能提高!
      整个培训周期,都是训练类似于这种固定、专业的思维方法,无论你遇到多复杂多前卫的项目,都能用这种思维方式来设计。

对了,上面代码中,我们没有补充信号定义这些。其实我们认为这些信号定义纯属体力劳动,是根本就不需要学习的,所以我们就没列出来。读者有兴趣可必补充。另外加上数码管译码电路,那么一个完整的数字时钟代码就出来了。
星宇 发表于 2017-2-21 14:29:23 | 显示全部楼层
一套好的设计思想很重要
大鹏 发表于 2017-2-21 14:31:47 | 显示全部楼层
感觉有点瑕疵!
zxopen08 发表于 2017-2-23 09:13:24 | 显示全部楼层
基于至简设计法的数字时钟设计
zxopenljx 发表于 2019-11-8 10:41:43 | 显示全部楼层
基于至简设计法的数字时钟设计
zxopenljx 发表于 2023-6-5 09:57:51 | 显示全部楼层
基于至简设计法的数字时钟设计
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-4-25 22:50 , Processed in 0.070316 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表