当前位置:网站首页>【Verilog 设计】Verilog 实现偶数、奇数分频和任意小数分频
【Verilog 设计】Verilog 实现偶数、奇数分频和任意小数分频
2022-07-29 21:15:00 【Linest-5】
目录
写在前面
在实际的项目工程中,经常需要不同的时钟频率工作,或者在一些笔试面试中,时钟分频也会被问到,因此这篇文章介绍几种常见的时钟分频的案例:偶数分频、奇数分频、任意小数分频。
偶数分频
偶数分频是最常见的分频方式也是最简单的,只需要一个简单的计数器即可,如果要实现4分频的时钟,只需要计数器从0计数到3,然后输出的时钟在计数到1和3的时钟翻转即可。
Verilog 实现
//`timescale 100ps / 1ps
//
// Engineer:
// Create Date: 2022/07/24
// Design Name:
// Module Name: freq_div_even
// Tool Versions: Vivado 2021.2
// Encode: GBK
// Description: 实现偶数四分频
// Additional Comments:
//
//
module freq_div_even(
input clk,
input rst,
output reg clk_out
);
reg [1:0] cnt;
always @(posedge clk or posedge rst) begin
if (rst) begin
cnt <= 'd0;
end
else if (cnt == 'd3) begin
cnt <= 'd0;
end
else begin
cnt <= cnt + 'd1;
end
end
always @(posedge clk or posedge rst) begin
if (rst) begin
clk_out <= 'd0;
end
else if (cnt == 'd1) begin
clk_out <= 'd1;
end
else if (cnt == 'd3) begin
clk_out <= 'd0;
end
else begin
clk_out <= clk_out;
end
end
endmoduleTestBench 测试文件
`timescale 10ps / 1ps
//
// Engineer:
// Create Date: 2022/07/24
// Design Name:
// Module Name: tb_freq_div_even
// Tool Versions: Vivado 2021.2
// Encode: GBK
// Description:
// Additional Comments:
//
//
module tb_freq_div_even();
reg clk;
reg rst;
wire clk_out;
initial begin
clk = 'd0;
rst = 'd1;
#20
rst = 'd0;
end
always #10 clk = ~clk;
freq_div_even inst_freq_div_even (
.clk(clk),
.rst(rst),
.clk_out(clk_out)
);
endmoduleRTL 视图

仿真波形
可以看到原时钟为50Mhz,在四分频后时钟为12.5Mhz,符合设计要求。如果要设计八分频甚至更大的分频也是如此操作。

奇数分频
相对于偶数分频,奇数分频要复杂一些,不仅要实现奇数分频而且占空比为50%,这里需要多加一个计数器,一个计数器由输入时钟上升沿触发,另一个计数器由输入时钟下降沿触发,最后将两个计数器的输出做相运算,即可得到奇数分频并且占空比为50%的时钟。
Verilog 实现
//`timescale 100ps / 1ps
//
// Engineer:
// Create Date: 2022/07/24
// Design Name:
// Module Name: freq_div_odd
// Tool Versions: Vivado 2021.2
// Encode: GBK
// Description: 实现奇数五分频
// Additional Comments:
//
//
module freq_div_odd(
input clk,
input rst,
output wire clk_out
);
reg [2:0] cnt1;
reg [2:0] cnt2;
reg clk1;
reg clk2;
always @(posedge clk or posedge rst) begin
if (rst) begin
cnt1 <= 'd0;
end
else if (cnt1 == 'd4) begin
cnt1 <= 'd0;
end
else begin
cnt1 <= cnt1 + 'd1;
end
end
always @(posedge clk or posedge rst) begin
if (rst) begin
clk1 <= 'd0;
end
else if (cnt1 < 'd2) begin
clk1 <= 'd1;
end
else begin
clk1 <= 'd0;
end
end
always @(negedge clk or posedge rst) begin
if (rst) begin
cnt2 <= 'd0;
end
else if (cnt2 == 'd4) begin
cnt2 <= 'd0;
end
else begin
cnt2 <= cnt2 + 'd1;
end
end
always @(negedge clk or posedge rst) begin
if (rst) begin
clk2 <= 'd0;
end
else if (cnt2 < 'd2) begin
clk2 <= 'd1;
end
else begin
clk2 <= 'd0;
end
end
assign clk_out = clk1 | clk2;
endmoduleTestBench 测试文件
`timescale 10ps / 1ps
//
// Engineer:
// Create Date: 2022/07/24
// Design Name:
// Module Name: tb_freq_div_odd
// Tool Versions: Vivado 2021.2
// Encode: GBK
// Description:
// Additional Comments:
//
//
module tb_freq_div_odd();
reg clk;
reg rst;
wire clk_out;
initial begin
clk = 'd0;
rst = 'd1;
#20
rst = 'd0;
end
always #10 clk = ~clk;
freq_div_odd inst_freq_div_odd (
.clk(clk),
.rst(rst),
.clk_out(clk_out)
);
endmoduleRTL 视图

仿真波形

任意小数分频
任意小数分频如果要分的更细一些,可以分成半整数分数和非半整数的小数分频,因为半整数也属于小数,所以这里统一用任意小数分频的设计方法实现。
在设计时也可以选择直接调用 PLL 锁相环实现,比如要实现 6.3 的分频,可以先将源时钟 10 倍频,得到源时钟的 10 倍频率的时钟,再进行 63 分频实现,这样就可以得到 63 分频的时钟。
另外也可以自己设计实现,分频结果 N = M + P,其中 M 为小数分频值得整数部分,P 为小数分频值得小数部分,同时小数可以用分式表示 b/a+b,比如 0.3 可以表示为3/7+3,此时b = 3,则原式可以表示为 N = M + b/a+b,对 M 进行通分得到 N = M(a+b) + b/a+b = [aM + b(M+1)]/a+b,这样就可以列出二元一次方程,6.3分频可以写成分式63/10。
可以得到以下二元一次不等式:
6a + 7b = 63
a + b = 10
解得:a = 7,b = 3
表示先做 7 次 6 分频,再做 3 次 7 分频即可达到 6.3 分频的目的。
Verilog 实现
//`timescale 100ps / 1ps
//
// Engineer:
// Create Date: 2022/07/24
// Design Name:
// Module Name: freq_div_decimal
// Tool Versions: Vivado 2021.2
// Encode: GBK
// Description: 实现任意小数分频,以6.3分频为例
// Additional Comments:
// 先做 7 次 6 分频,再做 3 次 7 分频
//
//
module freq_div_decimal(
input clk,
input rst,
output reg clk_out
);
reg [3:0] cnt1;
reg [3:0] cnt2;
always @(posedge clk or posedge rst) begin
if (rst) begin
cnt1 <= 'd0;
end
else if ((cnt2 < 'd7) &&(cnt1 == 'd5)) begin
cnt1 <= 'd0;
end
else if (cnt1 == 'd6) begin
cnt1 <= 'd0;
end
else begin
cnt1 <= cnt1 + 'd1;
end
end
always @(posedge clk or posedge rst) begin
if (rst) begin
cnt2 <= 'd0;
end
else if ((cnt2 == 'd9) && (cnt1 == 'd6)) begin
cnt2 <= 'd0;
end
else if ((cnt1 == 'd5) && (cnt2 < 'd7)) begin
cnt2 <= cnt2 + 'd1;
end
else if (cnt1 == 'd6) begin
cnt2 <= cnt2 + 'd1;
end
else begin
cnt2 <= cnt2;
end
end
always @(posedge clk or posedge rst) begin
if (rst) begin
clk_out <= 'd0;
end
else if ((cnt1 == 'd5) && (cnt2 < 'd7)) begin
clk_out <= 'd1;
end
else if (cnt1 == 'd6) begin
clk_out <= 'd1;
end
else begin
clk_out <= 'd0;
end
end
endmoduleTestBench 测试文件
`timescale 10ps / 1ps
//
// Engineer:
// Create Date: 2022/07/24
// Design Name:
// Module Name: tb_freq_div_even
// Tool Versions: Vivado 2021.2
// Encode: GBK
// Description:
// Additional Comments:
//
//
module tb_freq_div_even();
reg clk;
reg rst;
wire clk_out;
initial begin
clk = 'd0;
rst = 'd1;
#20
rst = 'd0;
end
always #10 clk = ~clk;
freq_div_decimal inst_freq_div_decimal (
.clk(clk),
.rst(rst),
.clk_out(clk_out)
);
endmoduleRTL 视图

仿真波形
可以看到仿真波形,先经过了 7 次的 6 分频,再经过 3 次的 7 分频,最终形成 6.3 分频的时钟输出。

边栏推荐
猜你喜欢
随机推荐
容器网络硬核技术内幕 (小结-中)
【ORM框架:Sequelize的查询】
Chrome浏览器打印flash log
阿里 P8 爆出的这份大厂面试指南,看完工资暴涨 30k!
剑指 Offer II 097. 子序列的数目
MySQL Data Query - Simple Query
Qualcomm WLAN framework learning (31) -- Power save
写出优雅的Kotlin代码:聊聊我认为的 “Kotlinic“
4. SAP ABAP OData 服务 Data Provider Class 的 GET_ENTITYSET 方法实现指南
最小jvm源码分析
MySQL数据查询 - 联合查询
mdnice-test
相亲信息
微信小程序 31 分包机制
打破原则!MongoDB 引入 SQL?
LeetCode 593 有效的正方形[数学] HERODING的LeetCode之路
2022了你还不会『低代码』?数据科学也能玩转Low-Code啦!
OAuth,JWT ,OIDC你们搞得我好乱啊
GET_ENTITYSET Method Implementation Guide for SAP ABAP OData Service Data Provider Class
First thoughts on the first attempt to avoid killing without a file (Part 1)

![[ACTF2020 新生赛]Exec 1](/img/1e/a3c19d514207e6965d09c66b86e519.png)







