=====实验目的===== * (1)熟悉和掌握FPGA开发流程和Lattice Diamond软件使用方法; * (2)通过实验理解和掌握分频器原理; * (3)学习用Verilog HDL行为级描述时序逻辑电路。 =====实验任务===== 设计一个任意整数分频器。 =====实验原理===== 时钟信号的处理是FPGA的特色之一,因此分频器也是FPGA设计中使用频率非常高的基本设计之一。一般在FPGA中都有集成的锁相环可以实现各种时钟的分频和倍频设计,但是通过语言设计进行时钟分频是最基本的训练,在对时钟要求不高的设计时也能节省锁相环资源。在本实验中我们将实现任意整数的分频器,分频的时钟保持50%占空比。 1,偶数分频:偶数倍分频相对简单,比较容易理解。通过计数器计数是完全可以实现的。如进行N倍偶数分频,那么通过时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,以此循环下去。\\ {{::分频器实验原理1.png?nolink&1300|}}\\ 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分频时钟。\\ {{::分频器实验原理2.png?nolink&1300|}} =====Verilog HDL建模描述===== 用行为级描述任意整数分频器\\ 程序清单divide.v\\ module divide # ( //parameter是verilog里参数定义 parameter WIDTH = 24, //计数器的位数,计数的最大值为 2**WIDTH-1 parameter N = 12_000_000 //分频系数,请确保 N<2**WIDTH-1,否则计数会溢出 ) ( input clk, //clk连接到FPGA的C1脚,频率为12MHz input rst_n, //复位信号,低有效, output clkout //输出信号,可以连接到LED观察分频的时钟 ); reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器 reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟 /**********上升沿触发部分**************************************/ //上升沿触发时计数器的控制 always @(posedge clk or negedge rst_n) //posedge和negedge是verilog表示信号上升沿和下降沿 begin //当clk上升沿来临或者rst_n变低的时候执行一次always里的语句 if(!rst_n) cnt_p <= 1'b0; else if(cnt_p == (N-1)) cnt_p <= 1'b0; else cnt_p <= cnt_p + 1'b1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器 end //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50% always @(posedge clk or negedge rst_n) begin if(!rst_n) clk_p <= 1'b0; else if(cnt_p < (N>>1)) //N>>1表示右移一位,相当于除以2取商 clk_p <= 1'b0; else clk_p <= 1'b1; //得到的分频时钟正周期比负周期多一个clk时钟 end /*****************下降沿触发部分**************************************/ //下降沿触发时计数器的控制 always @(negedge clk or negedge rst_n) begin if(!rst_n) cnt_n <= 1'b0; else if(cnt_n == (N-1)) cnt_n <= 1'b0; else cnt_n <= cnt_n + 1'b1; end //下降沿触发的分频时钟输出,和clk_p相差半个clk时钟 always @(negedge clk or negedge rst_n) begin if(!rst_n) clk_n <= 1'b0; else if(cnt_n < (N>>1)) clk_n <= 1'b0; else clk_n <= 1'b1; //得到的分频时钟正周期比负周期多一个clk时钟 end /*************************************************************************/ wire clk1 = clk; //当N=1时,直接输出clk wire clk2 = clk_p; //当N为偶数也就是N的最低位为0,N[0]=0,输出clk_p wire clk3 = clk_p & clk_n; //当N为奇数也就是N最低位为1,N[0]=1,输出clk_p&clk_n。正周期多所以是相与 assign clkout = (N==1)? clk1:(N[0]? clk3:clk2); //条件判断表达式 endmodule =====实验步骤===== - 打开Lattice Diamond,建立工程。 - 新建Verilog HDL设计文件,并键入设计代码。 - 根据逻辑综合并分配管脚,在本实验中引脚分配如下:clk---C1,rst_n---L14,clkout---N13 - 如果仿真无误,构建并输出编程文件,烧写至FPGA的Flash之中。 - 观察输出结果。