当前位置:   article > 正文

FPGA 时钟分频_fpga时钟分频

fpga时钟分频

 

硬件说明


时钟信号的处理是FPGA的特色之一,因此分频器也是FPGA设计中使用频率非常高的基本设计之一。一般在FPGA中都有集成的锁相环可以实现各种时钟的分频和倍频设计,但是通过语言设计进行时钟分频是最基本的训练,在对时钟要求不高的设计时也能节省锁相环资源。在本实验中我们将实现任意整数的分频器,分频的时钟保持50%占空比。 
1,偶数分频:偶数倍分频相对简单,比较容易理解。通过计数器计数是完全可以实现的。如进行N倍偶数分频,那么通过时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,以此循环下去。 
2,奇数分频: 如果要实现占空比为50%的奇数倍分频,不能同偶数分频一样计数器记到一半的时候输出时钟翻转,那样得不到占空比50%的时钟。以待分频时钟CLK为例,如果以偶数分频的方法来做奇数分频,在CLK上升沿触发,将得到不是50%占空比的一个时钟信号(正周期比负周期多一个时钟或者少一个时钟);但是如果在CLK下降沿也触发,又得到另外一个不是50%占空比的时钟信号,这两个时钟相位正好相差半个CLK时钟周期。通过这两个时钟信号进行逻辑运算我们可以巧妙的得到50%占空比的时钟。 
总结如下:对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%奇数n分频时钟。再者同时进行下降沿触发的模N计数,到和上升沿触发输出时钟翻转选定值相同值时,进行输出时钟时钟翻转,同样经过(N-1)/2时,输出时钟再次翻转生成占空比非50%的奇数n分频时钟。两个占空比非50%的n分频时钟进行逻辑运算(正周期多的相与,负周期多的相或),得到占空比为50%的奇数n分频时钟。 

Verilog代码

  1.  
  2. module divide ( clk,rst_n,clkout);
  3.  
  4. input clk,rst_n; //输入信号,其中clk连接到FPGA的C1脚,频率为12MHz
  5. output clkout; //输出信号,可以连接到LED观察分频的时钟
  6.  
  7. //parameter是verilog里常数语句
  8. parameter WIDTH = 3; //计数器的位数,计数的最大值为 2**WIDTH-1
  9. parameter N = 5; //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出
  10.  
  11. reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
  12. reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟
  13.  
  14. //上升沿触发时计数器的控制
  15. always @ (posedge clk or negedge rst_n ) //posedge和negedge是verilog表示信号上升沿和下降沿
  16. //当clk上升沿来临或者rst_n变低的时候执行一次always里的语句
  17. begin
  18. if(!rst_n)
  19. cnt_p<=0;
  20. else if (cnt_p==(N-1))
  21. cnt_p<=0;
  22. else cnt_p<=cnt_p+1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
  23. end
  24.  
  25. //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
  26. always @ (posedge clk or negedge rst_n)
  27. begin
  28. if(!rst_n)
  29. clk_p<=0;
  30. else if (cnt_p<(N>>1)) //N>>1表示右移一位,相当于除以2去掉余数
  31. clk_p<=0;
  32. else
  33. clk_p<=1; //得到的分频时钟正周期比负周期多一个clk时钟
  34. end
  35.  
  36. //下降沿触发时计数器的控制
  37. always @ (negedge clk or negedge rst_n)
  38. begin
  39. if(!rst_n)
  40. cnt_n<=0;
  41. else if (cnt_n==(N-1))
  42. cnt_n<=0;
  43. else cnt_n<=cnt_n+1;
  44. end
  45.  
  46. //下降沿触发的分频时钟输出,和clk_p相差半个时钟
  47. always @ (negedge clk)
  48. begin
  49. if(!rst_n)
  50. clk_n<=0;
  51. else if (cnt_n<(N>>1))
  52. clk_n<=0;
  53. else
  54. clk_n<=1; //得到的分频时钟正周期比负周期多一个clk时钟
  55. end
  56.  
  57. assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; //条件判断表达式
  58. //当N=1时,直接输出clk
  59. //当N为偶数也就是N的最低位为0,N(0)=0,输出clk_p
  60. //当N为奇数也就是N最低位为1,N(0)=1,输出clk_p&clk_n。正周期多所以是相与
  61. endmodule

测试文件,进行功能仿真时需要编写testbench测试文件。verilog里的testbench文件和源文件一样也是.v文件,仿真能让我们更直观的观察信号波形,可以先阅读Diamond的使用了解如何使用Diamond中集成的仿真工具。

  1.  
  2. `timescale 1ns/100ps //仿真时间单位/时间精度,时间单位要大于或者等于时间精度
  3.  
  4. module divide_tb(); //测试文件也是一个module,因为用于仿真所以无需输入输出信号
  5.  
  6. reg clk,rst_n; //需要产生的激励信号定义,激励信号需要过程块产生所以定义为reg型变量
  7. wire clkout; //需要观察的输出信号定义,定义为wire型变量
  8.  
  9. //初始化过程块
  10. initial
  11. begin
  12. clk = 0;
  13. rst_n = 0;
  14. #25 //#表示延时25个时间单位
  15. rst_n = 1; //产生了一个初始25ns低电平,然后变高电平的复位信号
  16. end
  17.  
  18. always #10 clk = ~clk; //每隔10ns翻转一次clk信号,也就是产生一个时钟周期20ns的clk,频率为50MHz
  19.  
  20. //module调用例化格式
  21. divide #(.WIDTH(4),.N(11)) u1 ( //#后面的()中为参数传递,如果不传递参数就是所调用模块中的参数默认值
  22. //divide表示所要例化的module名称,u1是我们定义的例化名称,必须以字母开头
  23. .clk (clk), //输入输出信号连接。 .clk表示module本身定义的信号名称;(clk)表示我们在这里定义的激励信号
  24. .rst_n (rst_n), //在testbench里定义的信号名称可以与所要调用module的端口信号名称不同
  25. .clkout (clkout)
  26. );
  27. endmodule

引脚分配


时钟为12MHz。你可以通过仿真波形观察分频时钟(注意仿真的时间是有限的,所以分频时钟频率需要较高)。如果我们想通过眼睛观察LED的闪烁,那么需要设置参数N和WIDTH得到一个频率较低的时钟(例如N=12000000,WIDTH=24,分频时钟周期为1秒)。 

信号引脚
clkC1
rst_nL14
clkoutN13


修改程序中的分频系数和计数器位数就能够调整LED闪烁速度(注意计数的最大值一定要保证超过分频系数N)。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/872394
推荐阅读
相关标签
  

闽ICP备14008679号