偶分频和奇分频 FPGA verilog 基础练习4
发现问题,用技术解决问题。兴趣是自己的源动力 !
前言
分频器的练习就是计数器的一个应用分支,用设立来检验自己对计数器的使用使用熟练。真实上板代码,都是使用IP核来进行的。核心的点就是要明白计数器使用的两个关键:
- 清零条件
- 递增条件
一、偶数分频
1.1 分频方案
偶数分频,计数器具有对称性,如果要实现6分频,则计数器只需要计数3个周期即可,即0~2,然后对输出取反。
1.1.1 功能代码
module divider_six
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
output reg clk_out //对系统时钟6分频后的信号
);
reg [1:0] cnt; //用于计数的寄存器
//cnt:计数器从0到2循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 2'b0;
else if(cnt == 2'd2)
cnt <= 2'b0;
else
cnt <= cnt + 1'b1;
//clk_out:6分频50%占空比输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_out <= 1'b0;
else if(cnt == 2'd2)
clk_out <= ~clk_out;
endmodule
1.1.2 仿真代码
module tb_top();
reg sys_clk;
reg sys_rst_n;
wire clk_out;
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
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
1.1.3 仿真结果
1.2 降频方案
为什么需要降频呢,因为你分频后的时钟其实一般不直接使用的,一般是使用全局时钟网络的时钟,这其实和时钟的布局布线有关(为了时钟到达所有的节点的时间几乎一样)。
1.2.1 功能代码
就是使用系统时钟来输出一个flag信号,这个flag信号的输出就是分频后的输出,且占空比不是50%。注意flag。这里的代码需要注意计数器的清零条件和递增条件。(代码中有注释)
module divider_six
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
output reg clk_flag //指示系统时钟6分频后的脉冲标志信号
);
reg [2:0] cnt; //用于计数的寄存器
//cnt:计数器从0到5循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 3'b0;
else if(cnt == 3'd5)
cnt <= 3'b0;
else
cnt <= cnt + 1'b1;
//clk_flag:脉冲信号指示6分频
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_flag <= 1'b0;
else if(cnt == 3'd4) // 注意:这里是4,不是5,因为flag会延迟一拍被时钟采样
clk_flag <= 1'b1;
else
clk_flag <= 1'b0;
endmodule
1.2.2 tb代码
`timescale 1ns/1ns
module tb_top();
reg sys_clk;
reg sys_rst_n;
wire clk_out;
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always #10 sys_clk = ~sys_clk;
//-----------------------divider_five_inst------------------------
divider_five divider_five_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.clk_flag (clk_out ) //output clk_out
);
endmodule
1.2.3 仿真结果
二、奇数分频
实现一个5分频的方法。如果占空比不要求50%,则很好设计,如下图。(这种使用降频的方法就不展示了,参照偶数分频)
但是,如果占空比要求50%,5分频那就是,2.5个时钟周期一个高电平,2.5个时钟周期一个低电平。
因此如何实现2.5个时钟周期呢?这就是要学习的地方了
- 使用时钟的上升沿和下降沿。
2.1 分频方案
可以看下图去理解。
理解:要在一个5clk,里面实现两个2.5clk的高电平和2.5clk的低电平。实现2.5clk,本质就是利用上升沿和下降沿的时间差0.5clk。
2.1.1 分频代码
module divider_five
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
output wire clk_out //对系统时钟5分频后的信号
);
reg [2:0] cnt;
reg clk1;
reg clk2;
//cnt:上升沿开始从0到4循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 3'b0;
else if(cnt == 3'd4)
cnt <= 3'b0;
else
cnt <= cnt + 1'b1;
// 因为是分频5个clk,如何实现2.5个clk呢?可以这里理解 2.5 = 2+0.5,只需要实现两个时钟相加就可以了
//clk1:上升沿触发,这里先实现一个 2 clk 的低电平,3clk的高电频
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
clk1 <= 1'b1;
else if(cnt == 3'd2)
clk1 <= 1'b0;
else if(cnt == 3'd4)
clk1 <= 1'b1;
else
clk1 <= clk1;
end
//clk2:下降沿触发,这里先实现一个 2 clk 的低电平,注意是下下降沿,因为要和上升沿错开,获得一个0.5 clk周期
always@(negedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
clk2 <= 1'b1;
else if(cnt == 3'd2)
clk2 <= 1'b0;
else if(cnt == 3'd4)
clk2 <= 1'b1;
else
clk2 <= clk2;
end
//clk_out:5分频50%占空比输出
assign clk_out = clk1 & clk2;
endmodule
2.1.2 tb代码
`timescale 1ns/1ns
module tb_top();
reg sys_clk;
reg sys_rst_n;
wire clk_out;
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always #10 sys_clk = ~sys_clk;
//-----------------------divider_five_inst------------------------
divider_five divider_five_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
2.1.3 仿真结果
小结:实现2.5个时钟周期,核心只需要记住一点:上升沿和下降沿之间,就是差了0.5个周期,抓住这个点,其他的设计就只需要注意清零条件和拉高条件即可
总结
- 核心思想:明白如何使用计数器来实现特定的功能,主要是对计数器练习的一个目的
- 知识点总结:
- 如何使用奇分频和偶分频:要点是计数器的清零条件
- 全局时钟的理解
- 如何产生一个0.5clk
- 欢迎一起交流学习,如有错误之处,还请各位指正。
参考资料文章来源:https://www.toymoban.com/news/detail-764927.html
[1] FPGA系列教学文章来源地址https://www.toymoban.com/news/detail-764927.html
到了这里,关于偶分频和奇分频 FPGA verilog 基础练习4的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!