mdykj33的个人空间 https://bbs.21ic.com/?1591856 [收藏] [复制] [RSS]

日志

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

已有 223 次阅读2017-2-15 18:01 |个人分类:明德扬-至简设计法|系统分类:嵌入式系统| 数字时钟, fpga, 明德扬, 设计, 至简设计法

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



明德扬科技教育有限公司



 



   网:www.mdy-edu.com

  宝:mdy-edu.taobao.com

QQ 
群:97925396 



至简设计法数字时钟视频链接:www.mdy-edu.com/article_cat/video?id=20

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



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



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



 



数字模块的功能,是产生6个信号,分别表示时十位、时个位、分十位、分个位、秒十位和秒个位的值。例如上述信号值依次为214359时,则表示时间为214359秒。



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



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



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





 



同样的道理,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



秒个位要数多少个数字呢?由09,因此有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


  

 


  




 



 



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



如果你还未发现这代码优秀的地方,建议你百度下数字时钟的代码,好好比一比,特别是好好想想我们的设计思路,明德扬是有方法有步骤、可以做到一次性设计对,而他们的则是想到哪写到哪,每次设计都不同的想法。每次设计都是不同的思想,水平怎么能提高!



 



明德扬整个培训周期,都是训练类似于这种固定、专业的思维方法,无论你遇到多复杂多前卫的项目,都能用这种思维方式来设计。



 



对了,上面代码中,我们没有补充信号定义这些。其实我们认为这些信号定义纯属体力劳动,是根本就不需要学习的,所以我们就没列出来。读者有兴趣可必补充。另外加上数码管译码电路,那么一个完整的数字时钟代码就出来了。


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)