1.1偶数分频简介
实现分频一般有两个方法,一个方法是直接使用 PLL 进行分频,比如 FPGA 或者 ASIC 设计中,都可
以直接使用 PLL 进行分频,但是这种分频倍数有时候受限于 PLL 本身的特性,比如输入 100Mhz 时钟,很
多 PLL 都实现不了分频到 1Mhz 的时钟,这个就是 PLL 本身特性限制的。还有一种实现方法就是直接使用
逻辑实现,即使用代码实现分频设计。我们本节介绍的是使用代码进行设计分频器。 本节我们先看下偶数分
频设计。
偶数分频,顾名思义,是说分频后的频率和分频前的频率比例是偶数,比如 100Mhz 时钟,进行二分频
后,就是 50Mhz。
实现偶数分频可通过一个简单计数器实现,而如果需要三分频,五分频,七分频等奇数分频,一个计数
器是不够的。
偶数分频实现比较简单,假设为 N(偶数)分频,只需计数到 N/2-1,然后时钟翻转、计数器清零,如
此循环就可以得到 N(偶)分频。 举个例子,比如晶振时钟是 100Mhz 时钟,想得到一个 25Mhz 的时钟,
那么这个是一个 100/25=4 的四分频设计, 那么按照我们刚说的计数到 4/2-1=1,然后时钟翻转、计数器清零,
就可以得到一个 24Mhz 的时钟。
2.1Verilog程序设计
//file name : even_divide_8.v
//file funciton :设计一个偶数分频器实现8分频的操作
//file date :2023/4/6
//file version : 1.0version
//author : ZihangNie
//***************************************************
module even_divide_8(
//input signal
input sys_clk , //输入系统时钟
input sys_rst_n , //输入复位信号
//output signal
output reg clk_8 //输出8分频的时钟信号
) ;
//常量定义
parameter WIDTH = 8 ;
//寄存器定义
reg [2:0] cnt ; //定义一个分频计数器
//****************************************************
//*******************main code************************
//****************************************************
//计数模块
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
cnt <= 3'b0 ;
end
else if ( cnt == WIDTH/2-1) begin
cnt <= 0 ; // 计数器满了测清零
end
else begin
cnt <= cnt + 1'b1 ; //计数器没有计数满了则加一
end
end
//分频模块
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
clk_8 <= 1'b0 ;
end
else if(cnt == WIDTH/2 - 1) begin
clk_8 <= ~clk_8 ;
end
else begin
clk_8 <= clk_8 ;
end
end
endmodule
2.testbench 仿真
//file name : tb_even_divide_8.v
//file function : 实现八分频偶数计数器的仿真
//file version :1.0version
//file date : 2023/4/6
//Author : ZihangNie
//******************************************************************
`timescale 1ns/1ps //f仿真时间单位1ns,仿真精度单位1ps
module tb_even_divide_8(); // 定义仿真模块
//input signal
reg sys_clk ; // 输入全局时钟
reg sys_rst_n ; //输入系统复位
//output signal
wire clk_8 ; //输出八分频计数时钟
//对模块进行初始化操作
initial begin
sys_clk = 1'b0 ;
sys_rst_n = 1'b0 ;
#200
sys_rst_n = 1'b1 ;
end
always #10 sys_clk = ~sys_clk ;
//对八分频电路模块进行例化
even_divide_8 u_even_divide_8(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.clk_8(clk_8)
);
endmodule
3 modlesim仿真
从仿真结果上看实现了8分频操作
4 奇数分频器操作
//file name : odd_divide_15.v
//file function : 设计一个奇数分频器,分成15份
//file version : 1.0version
//file date : 2023/4/6
//Author :ZihangNie
//****************************************************************
//function description :
/*为 N分频,需从0计数到 N-1(一共N/2个基准时钟),一直循环
设计一个对基准时钟上升沿敏感的信号,每当计数到(N-1)/2-1时,时钟翻转;计数到计数器最大值时再反转
设计一个对基准时钟下降沿敏感的信号,每当计数到(N-1)/2-1时,时钟翻转;计数到计数器最大值时再反转
将 上升沿敏感的信号和 下降沿敏感的信号相与(&&)即N分频电路*/
module odd_divide_15(
// input signal
input sys_clk , //输入全局时钟
input sys_rst_n ,// 输入复位信号
// output signal
output clk_15 //输出15分频时钟
) ;
//parameter 参数定义
parameter N = 15 ; //定义15分频参数
//register 参数定义
reg [3:0] cnt ;
reg pos_clk_cnt ;
reg neg_clk_cnt ;
assign clk_15 = pos_clk_cnt && neg_clk_cnt ;
//******************************************main code***************************************
//******************************************************************************************
//******************************************************************************************
//计数模块
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
cnt <= 4'b0;
end
else if ( cnt == N - 1'b1) begin
cnt <= 4'b0 ; // 如果计数满了则清零
end
else begin
cnt <= cnt + 1'b1 ; // 如果计数没有满则加一操作
end
end
//上升沿敏感触发信号
always @ (negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
pos_clk_cnt <= 1'b0 ;
end
else if ( cnt == N/2- 1) begin
pos_clk_cnt <= 1'b1;
end
else if ( cnt == N-1 ) begin
pos_clk_cnt <= 1'b0 ;
end
else begin
pos_clk_cnt <= pos_clk_cnt ;
end
end
//下降沿敏感触发信号
always @ (posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n ) begin
neg_clk_cnt <= 1'b0 ;
end
else if ( cnt == N/2 -1 ) begin
neg_clk_cnt <= 1'b1 ;
end
else if (cnt == N/2 -1 ) begin
neg_clk_cnt <= 1'b0 ;
end
else if (cnt == N-1 ) begin
neg_clk_cnt <= 1'b0;
end
else begin
neg_clk_cnt <= neg_clk_cnt;
end
end
endmodule