当前位置:首页 > 新闻资讯 > FPGA之家动态 >

FPGA从入门到精通(九)分频器

时间:2024-07-30      来源:网络搜集 关于我们 0

数电基础板载晶振提供的时钟信号频率是固定的,不一定满足需求,因此需要对基准时钟进行分频。要得到更慢的时钟频率可以分频,要得到更快的时钟频率可以倍频。我们有两种方式可以改变频率,一种是锁相环(PLL,后面章节会讲解),另一种是用 Verilog代码描述。用Verilog代码描述的往往是分频电路,即分频器。分频就是输出信号的频率是输入信号的1/n。原理是,输入信号为计数脉冲,每n个脉冲输出就翻转一次。就可以看作是对输入信号的“分频”。十进制的计数器对应十分频,如果是二进制的计数器那就是二分频,还有四进制、八进制、十六进制等等以此类推。设计规划

实现6分频,第一种方法是仅实现分频,第二种方法是降频:

时钟信号周期为1格,输出信号周期为6格,因此频率为原来的1/6,也就是6分频。

方法一:只需要让计数器从0计数到2,就让clk_out输出信号取反。

方法二:方法一得到的新时钟信号和真正的时钟信号有区别,在高速系统中不稳定因为在FPGA中凡是时钟信号都要连接到全局时钟网络上,它能够使时钟信号到达每个寄存器的时间都尽可能相同,以保证更低的时钟偏斜(Skew)和抖动(Jitter)。用分频的方式产生的clk_out信号并没有连接到全局时钟网络上,但sys_clk则是由外部晶振直接通过管脚连接到了FPGA的专用时钟管脚上,自然就会连接到全局时钟网络上。因此我们可以产生一个clk_flag标志信号,从0计数到5,就变高电平,下一个时钟电平变为低电平并维持5个时钟间隔。和方法1对比,相当于把clk_out的上升沿信号变成了clk_flag的脉冲电平信号。虽然需要多使用一些寄存器资源但是能使系统更加稳定。

编写代码module divider_six(input wire sys_clk , //系统时钟50MHzinput wire sys_rst_n , output reg clk_out ); reg [1:0] cnt; always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1b0) cnt <= 2b0; else if(cnt == 2d2) cnt <= 2b0; else cnt <= cnt + 1b1; //clk_out:6分频50%占空比输出 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1b0) clk_out <= 1b0; else if(cnt == 2d2) clk_out <= ~clk_out; endmodule我们观察cnt和clk_out的变化条件:计数器发生改变的条件有两个,一个是时钟上升沿,一个是复位有效(复位下降沿)。计数器发生的改变有两个,要么+1要么清零。清零条件有两个:复位和溢出。因此第一个always块中有三个判断条件:复位和溢出时清零,其他的时候+1。clk_out的变化条件:时钟上升沿和复位有效(复位下降沿)。复位时clk_out为低电平,溢出时取反。

module divider_six(input wire sys_clk , //系统时钟50MHzinput wire sys_rst_n , output reg clk_flag); reg [2:0] cnt;  //cnt:计数器从0到5循环计数 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1b0) cnt <= 3b0; else if(cnt == 3d5) cnt <= 3b0; else cnt <= cnt + 1b1; //clk_flag:脉冲信号指示6分频 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1b0) clk_flag <= 1b0; else if(cnt == 3d4) clk_flag <= 1b1; else clk_flag <= 1b0; endmodule和方法1相似,区别在于输出的变化不同,从0计数到4输出变为1,否则为0。cnt溢出的条件是计数到5,输出的变化是计数到4。

编写testbench`timescale 1ns/1nsmodule tb_divider_six();reg sys_clk;reg sys_rst_n;wire clk_out;//初始化系统时钟、全局复位 initial begin sys_clk = 1b1; sys_rst_n <= 1b0; #20 sys_rst_n <= 1b1; end //sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz always #10 sys_clk = ~sys_clk; //--------------------divider_sixht_inst-------------------- divider_six divider_six_inst ( .sys_clk (sys_clk ), //input sys_clk .sys_rst_n (sys_rst_n ), //input sys_rst_n .clk_out (clk_out ) //output clk_out ); endmodule两种方法的testbench代码一样,除了输出是clk_out还是clk_flag。对比波形如果波形没有出来,可以在modelsim通过view的transcript查看错误。方法1得到的波形

方法2得到的波形


注明:本内容来源网络,不用于商业使用,禁止转载,如有侵权,请来信到邮箱:429562386ⓐqq.com 或联系本站客服处理,感谢配合!

用户登陆

    未注册用户登录后会自动为您创建账号

提交留言