简易数字频率计(verilog HDL设计)(2020维护版本)

举报
李锐博恩 发表于 2021/07/15 07:21:58 2021/07/15
【摘要】 目录   前言 简易数字频率计原理 结语 前言 这篇博客大概是2017年写的,目前已经是2020年8月不到,今天维护了一下但是并未保存,很受伤,不得不重新在维护一次。 最近看到很多评论,说程序有问题,于是我就对这个程序进行一次测试。 并更新博文程序与其他部分内容。 简易数字频率计原理 原理:数字频率计的原理十分简单,简单的就是一句话和一幅图而已...

目录

 

前言

简易数字频率计原理

结语


前言

这篇博客大概是2017年写的,目前已经是2020年8月不到,今天维护了一下但是并未保存,很受伤,不得不重新在维护一次。

最近看到很多评论,说程序有问题,于是我就对这个程序进行一次测试。

并更新博文程序与其他部分内容。

简易数字频率计原理

原理:数字频率计的原理十分简单,简单的就是一句话和一幅图而已。

一句话:测量被测信号的频率,要清楚频率的定义,一言以蔽之,就是1s中信号的周期数。

根据频率的定义,我们测量被测信号1s中变化的次数即可,即1s中的周期数。

首先我们设置一个基准时钟信号,频率为1Hz,从第一个上升沿开始计数(被测信号的上升沿数),直到下一个上升沿到达时停止计数,对数据进行锁存,再到达下一个上升沿时,对计数器进行清零,准备下一次的测量。

根据以上描述,得到相关信号的关系:

一幅图:

我尝试使用wavedrom画了这个图:

                             

本图是简易频率计的工作时序图,从图中 可以看出:

基准信号的第一个上升沿到达时,计数使能信号有效,计数器开始计数;

第二上升沿到达时,计数结束,锁存使能有效,计数数据开始锁存;

第三个上升沿到达时,清零信号有效,对计数器的输出清零,准备下一次的测量。

一个测量过程需要3 sec(重要)。

下面是数字频率计的原理图:

                 

由此原理图可以清晰的理解下面的verilog HDL程序:

程序可以分为四个部分,一个顶层模块,三个子模块:

顶层:


  
  1. `timescale 1ns / 1ps
  2. //
  3. // blog: https://blog.csdn.net/Reborn_Lee
  4. // Engineer: 李锐博恩
  5. // Design Name: frequency detect
  6. // Module Name: freDetect
  7. //
  8. //
  9. module freDetect(
  10. input wire clk_1Hz, //1Hz基准频率,周期1s;
  11. input wire fin, //输入待测信号
  12. input wire rst, //复位信号
  13. output wire [3:0] d0,
  14. output wire [3:0] d1,
  15. output wire [3:0] d2,
  16. output wire [3:0] d3,
  17. output wire [3:0] d4,
  18. output wire [3:0] d5,
  19. output wire [3:0] d6,
  20. output wire [3:0] d7
  21. );
  22. wire [3:0] q0, q1, q2, q3, q4, q5, q6, q7; //中间数据
  23. //控制模块实例
  24. control control_inst(.clk_1Hz(clk_1Hz),
  25. .rst(rst),
  26. .count_en(count_en),
  27. .latch_en(latch_en),
  28. .clear(clear)
  29. );
  30. //计数器模块实例  
  31. counter_10 counter_inst0(.en_in(count_en),.clear(clear),.rst(rst),
  32. .fin(fin),.en_out(en_out0),.q(q0));
  33. counter_10 counter_inst1(.en_in(en_out0),.clear(clear),.rst(rst),
  34. .fin(fin),.en_out(en_out1),.q(q1));
  35. counter_10 counter_inst2(.en_in(en_out1),.clear(clear),.rst(rst),
  36. .fin(fin),.en_out(en_out2),.q(q2));
  37. counter_10 counter_inst3(.en_in(en_out2),.clear(clear),.rst(rst),
  38. .fin(fin),.en_out(en_out3),.q(q3));
  39. counter_10 counter_inst4(.en_in(en_out3),.clear(clear),.rst(rst),
  40. .fin(fin),.en_out(en_out4),.q(q4));
  41. counter_10 counter_inst5(.en_in(en_out4),.clear(clear),.rst(rst),
  42. .fin(fin),.en_out(en_out5),.q(q5));
  43. counter_10 counter_inst6(.en_in(en_out5),.clear(clear),.rst(rst),
  44. .fin(fin),.en_out(en_out6),.q(q6));
  45. counter_10 counter_inst7(.en_in(en_out6),.clear(clear),.rst(rst),
  46. .fin(fin),.en_out(en_out7),.q(q7));
  47. //锁存器模块实例  
  48. latch_freq latch_freq_inst(.clk_1Hz(clk_1Hz),.rst(rst),.latch_en(latch_en),
  49. .q0(q0),.q1(q1),.q2(q2),.q3(q3),.q4(q4),.q5(q5),
  50. .q6(q6),.q7(q7),.d0(d0),.d1(d1),.d2(d2),.d3(d3),
  51. .d4(d4),.d5(d5),.d6(d6),.d7(d7));
  52. endmodule

 

顶层模块例化了各种子模块:

控制模块:


  
  1. `timescale 1ns / 1ps
  2. //
  3. // blog: https://blog.csdn.net/Reborn_Lee
  4. // Engineer: 李锐博恩
  5. // Design Name: frequency detect
  6. // Module Name: control
  7. //
  8. //
  9. module control(
  10. input wire clk_1Hz,
  11. input wire rst,
  12. output reg count_en,
  13. output reg latch_en,
  14. output reg clear
  15. );
  16. reg[1:0] state; //状态信号,用于控制各种使能信号
  17. always @(posedge clk_1Hz or posedge rst)
  18. if(rst) //复位信号有效
  19. begin //各种使能信号清零
  20. state <= 2'd0;
  21. count_en <= 1'b0;
  22. latch_en <=1'b0;
  23. clear <= 1'b0;
  24. end
  25. else //遇到基准信号的下一个上升沿,状态变化一次,每次变化后状态持续1s
  26. begin
  27. case(state)
  28. 2'd0:
  29. begin //第一个上升沿到达,开始计数,计数1个基准信号周期内待测信号的上升沿个数,此个数即为待测信号的频率  
  30. count_en <= 1'b1; //计数使能信号有效
  31. latch_en <=1'b0;
  32. clear <= 1'b0;
  33. state <= 2'd1;
  34. end
  35. 2'd1:
  36. begin //第二个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中
  37. count_en <= 1'b0;
  38. latch_en <=1'b1;
  39. clear <= 1'b0;
  40. state <= 2'd2;
  41. end
  42. 2'd2:
  43. begin //第三个上升沿到达,清零使能信号有效,计数器清零,为下一次计数做准备
  44. count_en <= 1'b0;
  45. latch_en <=1'b0;
  46. clear <= 1'b1;
  47. state <= 2'd0; //状态清零,进入下一次测量  
  48. end
  49. default:
  50. begin
  51. count_en <= 1'b0;
  52. latch_en <=1'b0;
  53. clear <= 1'b0;
  54. state <= 2'd0;
  55. end
  56. endcase
  57. end
  58. endmodule

计数模块:


  
  1. `timescale 1ns / 1ps
  2. //
  3. // blog: https://blog.csdn.net/Reborn_Lee
  4. // Engineer: 李锐博恩
  5. // Design Name: frequency detect
  6. // Module Name: counter_10
  7. //
  8. //
  9. module counter_10(
  10. input wire en_in, //输入使能信号
  11. input wire rst, //复位信号
  12. input wire clear, //清零信号
  13. input wire fin, //待测信号
  14. output reg en_out, //输出使能,用于控制下一个计数器的状态,当输出使能有效时,下一个模10计数器计数加1
  15. output reg [3:0] q //计数器的输出,4位BCD码输出  
  16. );
  17. always@ (posedge fin or posedge rst) //输入待测信号的上升沿作为敏感信号
  18. if(rst) begin //复位信号有效,计数器输出清零
  19. en_out <= 1'b0;
  20. q <= 4'b0;
  21. end
  22. else if(en_in) begin //进位输入使能信号有效
  23. if(q == 4'b1001) begin //若q = 4'b1001的话,q清零,同时进位输出使能有效,即en_out 赋值为1'b1
  24. q <= 4'b0;
  25. en_out <= 1'b1;
  26. end
  27. else begin //若q未达到4'b1001时,每到达待测信号的一个上升沿,q加1,同时输出进位清零  
  28. q <= q + 1'b1;
  29. en_out <=1'b0;
  30. end
  31. end
  32. else if(clear) begin //若清零信号有效,计数器清零,主要用于为下一次测量准备  
  33. q <= 4'b0;
  34. en_out <= 1'b0;
  35. end
  36. else begin
  37. q <= q;
  38. en_out <=1'b0;
  39. end
  40. endmodule

 

锁存模块:

 


  
  1. `timescale 1ns / 1ps
  2. //
  3. // blog: https://blog.csdn.net/Reborn_Lee
  4. // Engineer: 李锐博恩
  5. // Design Name: frequency detect
  6. // Module Name: latch_freq
  7. //
  8. //
  9. module latch_freq(
  10. input wire clk_1Hz,
  11. input wire latch_en,
  12. input wire rst,
  13. input wire [3:0] q0,
  14. input wire [3:0] q1,
  15. input wire [3:0] q2,
  16. input wire [3:0] q3,
  17. input wire [3:0] q4,
  18. input wire [3:0] q5,
  19. input wire [3:0] q6,
  20. input wire [3:0] q7,
  21. output reg [3:0] d0,
  22. output reg [3:0] d1,
  23. output reg [3:0] d2,
  24. output reg [3:0] d3,
  25. output reg [3:0] d4,
  26. output reg [3:0] d5,
  27. output reg [3:0] d6,
  28. output reg [3:0] d7
  29. );
  30. always@ (posedge clk_1Hz or posedge rst)
  31. if(rst) //复位信号有效时输出清零  
  32. begin
  33. d0 <= 4'b0; d1 <= 4'b0; d2 <= 4'b0; d3 <= 4'b0; d4 <= 4'b0;
  34. d5 <= 4'b0; d6 <= 4'b0; d7 <= 4'b0;
  35. end
  36. else if(latch_en) //锁存信号有效时,将计数器的输出信号锁存至锁存器  
  37. begin
  38. d0 <= q0; d1 <= q1; d2 <= q2; d3 <= q3; d4 <= q4;
  39. d5 <= q5; d6 <= q6; d7 <= q7;
  40. end
  41. else //上面两种情况均未发生时,输入不变
  42. begin
  43. d0 <= d0; d1 <= d1; d2 <= d2; d3 <= d3; d4 <= d4;
  44. d5 <= d5; d6 <= d6; d7 <= d7;
  45. end
  46. endmodule

 

测试文件为:


  
  1. `timescale 1ns/1ps
  2. //测试模块
  3. module freDetect_tb;
  4. //为了仿真方便,全部缩小100倍;
  5. parameter CLK_1HZ_DELAY = 1000_0000; //1Hz基准信号,对应周期为1s=1000_000_000ns
  6. parameter FIN_DELAY = 2; //5MHz待测信号,对应周期为0.2*1000_000=200ns
  7. reg clk_1Hz;
  8. reg fin;
  9. reg rst;
  10. wire[3:0] d0, d1, d2, d3, d4, d5, d6, d7;
  11. initial
  12. begin
  13. rst =1'b1;
  14. #1 rst = 1'b0;
  15. end
  16. initial
  17. begin
  18. fin = 1'b0;
  19. forever
  20. # (FIN_DELAY/2) fin = ~fin;
  21. end
  22. initial
  23. begin
  24. clk_1Hz = 1'b0;
  25. forever
  26. # (CLK_1HZ_DELAY/2) clk_1Hz = ~clk_1Hz;
  27. end
  28. freDetect freDetect_inst(.clk_1Hz(clk_1Hz), .rst(rst), .fin(fin),
  29. .d0(d0), .d1(d1), .d2(d2), .d3(d3), .d4(d4), .d5(d5), .d6(d6), .d7(d7));
  30. endmodule

 

本仿真在vivado自带的仿真器进行行为仿真,使用其他仿真软件也可以,例如modelsim,本文使用vivado进行仿真,仿真结果如下:

我们设定的待测频率也是5Mhz=5000000Hz。

由于时间紧张,我就不具体展开中间变量了,大家自行分析。

结语

由于这篇博客时间有点长,csdn也经过了一些改版,导致早期的程序出现一些奇怪的字符,见博客:

网上复制代码需谨慎,莫名其妙报错看这里!

这恐怕也是广大看客直接复制我这篇文章代码所遇到的问题之一,不过现在这个问题解决了,大家可以再次尝试了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/80377207

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。