偶数分频 可以采用同步整数分频思路,使用摩尔状态机或者计数器(序列机)思想都可以,在这里提供一个同步7分频的摩尔状态机的实现思路:
module clk_divide(
inputwireclk,
inputwirerst_n,outputwireclk_o
);
//==================1. 同步整数分频器====================//
//基于摩尔状态机实现7分频(一段式状态机) 同样可以实现偶数分频
localparamS0=7'b0000_001,//S0状态:clk_o输出0
S1=7'b0000_010,//S1状态:clk_o输出0
S2=7'b0000_100,//S2状态:clk_o输出0
S3=7'b0001_000,//S3状态:clk_o输出0
S4=7'b0010_000,//S4状态:clk_o输出1
S5=7'b0100_000,//S5状态:clk_o输出1
S6=7'b1000_000;
//S1状态:clk_o输出1reg[6:0]state;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= S0;
clk_o <= 1'b0;
end
else begin
case(state)
S0:begin state <= S1;
clk_o <= 1'b0;
end
S1:begin state <= S2;
clk_o <= 1'b0;
end
S2:begin state <= S3;
clk_o <= 1'b0;
end
S3:begin state <= S4;
clk_o <= 1'b0;
end
S4:begin state <= S5;
clk_o <= 1'b1;
end
S5:begin state <= S6;
clk_o <= 1'b1;
end
S6:begin state <= S0;
clk_o <= 1'b1;
end
default:begin state <= S0;
clk_o <= 1'b1;
end
endcase
end
end
testbench如下所示:
`timescale 1ns/1ns`define CLK_CYCLE 20
module tb_clk_divide;
regclk;
regrst_n;
wireclk_o;
clk_divide u_clk_divide(
.clk(clk),
.rst_n(rst_n) ,.clk_o(clk_o)
);
initial begin
clk = 1'b0;
rst_n = 1'b0;
#201;
rst_n = 1'b1;
endalways #(`CLK_CYCLE / 2) clk = ~clk;
endmodule
仿真波形为:
文章图片
奇数分频 方法一 主要思路如下:
首先基于时钟的上升沿和时钟的下降沿构造两个计数器,两个计数器都是技术到分频的最大值置0.之后分别给予两个计数器,声明两个变量即clk_div1和clk_div2。两者在各自的时钟沿下,若小于最大计数值的一半,则拉高信号。否则拉低信号。最后将这两个变量信号相或就可以得到最后的分频时钟啦。
module clk_divide(
inputwireclk,
inputwirerst_n,outputwireclk_o
);
//==================2. 奇数分频器=======================//
//方法1
parameterCLK_DIV=7;
//奇数分频的频数reg[3:0]cnt_pos;
//上升沿计数器
reg[3:0]cnt_neg;
//下降沿计数器
regclk_div1;
//分频信号1
regclk_div2;
//分频信号2always @(posedge clk or negedge rst_n) begin//时钟上升沿触发
if(!rst_n) begin
cnt_pos <= 'd0;
end
else if(cnt_pos == CLK_DIV - 1'b1) begin//计数最大值置0
cnt_pos <= 'd0;
end
else
cnt_pos <= cnt_pos + 1'b1;
endalways @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div1 <= 1'b0;
end
else if(cnt_pos < CLK_DIV / 2) begin//小于计数值的一半,拉高clk_div1
clk_div1 <= 1'b1;
end
else begin+
clk_div1 <= 1'b0;
end
endalways @(negedge clk or negedge rst_n) begin//时钟下降沿触发
if(!rst_n) begin
cnt_neg <= 'd0;
end
else if(cnt_neg == CLK_DIV - 1) begin//计数到最大值置0
cnt_neg <= 'd0;
end
else begin
cnt_neg <= cnt_neg + 1'b1;
end
endalways @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div2 <= 1'b0;
end
else if(cnt_neg < CLK_DIV / 2) begin//小于计数值的一半,拉高clk_div2
clk_div2 <= 1'b1;
end
else begin
clk_div2 <= 1'b0;
end
endassign clk_o = clk_div1 | clk_div2;
//将clk_div1和clk_div2或运算
仿真截图:
文章图片
方法二 【verilog实战|verilog实现时钟的偶数与奇数分频】第二个方法是来自《硬件架构的艺术》上的方法,基于其思路,实现代码如下,代码中有详细的注释,便不在赘述了。
module clk_divide(
inputwireclk,
inputwirerst_n,outputwireclk_o
);
//方法2(来自《硬件架构的艺术》)
//步骤1:创建由时钟上升沿触发的0-(N-1)的计数器,N为分频系数
parameterN=5;
reg[3:0]cnt_up;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_up <= 'd0;
end
else if(cnt_up == N-1) begin
cnt_up <= 'd0;
end
else begin
cnt_up <= cnt_up + 1'b1;
end
end//步骤2:使用两个触发器,按照如下方式产生使能信号
//tff1_en:在计数值为0时使能
//tff2_en:在计数值为(N+1)/2时使能
wiretff1_en;
wiretff2_en;
assign tff1_en = (cnt_up == 0) ? 1'b1 : 1'b0;
assign tff2_en = (cnt_up == (N+1)/2) ? 1'b1 : 1'b0;
//步骤三:产生以下信号
//div1:TFF1的输出--->由输入时钟的上升沿触发
//div2:TFF2的输出--->由输入时钟的下降沿触发
regdiv1;
regdiv2;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div1 <= 1'b0;
end
else if(tff1_en) begin
div1 <= ~div1;
end
else begin
div1 <= div1;
end
endalways @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
div2 <= 1'b0;
end
else if(tff2_en) begin
div2 <=~div2;
end
else begin
div2 <= div2;
end
end//步骤四:将div1和div2信号异或
assign clk_o = div1 ^ div2;
endmodule
仿真如下:
文章图片
全部代码
//时钟分频器
//2022/09/01
//======================================================//
//==================1. 同步整数分频器====================//
//==================2. 奇数分频器=======================//module clk_divide(
inputwireclk,
inputwirerst_n,outputwireclk_o
);
/*
//==================1. 同步整数分频器====================//
//基于摩尔状态机实现7分频(一段式状态机) 同样可以实现偶数分频
localparamS0=7'b0000_001,//S0状态:clk_o输出0
S1=7'b0000_010,//S1状态:clk_o输出0
S2=7'b0000_100,//S2状态:clk_o输出0
S3=7'b0001_000,//S3状态:clk_o输出0
S4=7'b0010_000,//S4状态:clk_o输出1
S5=7'b0100_000,//S5状态:clk_o输出1
S6=7'b1000_000;
//S1状态:clk_o输出1reg[6:0]state;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= S0;
clk_o <= 1'b0;
end
else begin
case(state)
S0:begin state <= S1;
clk_o <= 1'b0;
end
S1:begin state <= S2;
clk_o <= 1'b0;
end
S2:begin state <= S3;
clk_o <= 1'b0;
end
S3:begin state <= S4;
clk_o <= 1'b0;
end
S4:begin state <= S5;
clk_o <= 1'b1;
end
S5:begin state <= S6;
clk_o <= 1'b1;
end
S6:begin state <= S0;
clk_o <= 1'b1;
end
default:begin state <= S0;
clk_o <= 1'b1;
end
endcase
end
end
*/
//==================2. 奇数分频器=======================//
/*
//方法1
parameterCLK_DIV=7;
//奇数分频的频数reg[3:0]cnt_pos;
//上升沿计数器
reg[3:0]cnt_neg;
//下降沿计数器
regclk_div1;
//分频信号1
regclk_div2;
//分频信号2always @(posedge clk or negedge rst_n) begin//时钟上升沿触发
if(!rst_n) begin
cnt_pos <= 'd0;
end
else if(cnt_pos == CLK_DIV - 1'b1) begin//计数最大值置0
cnt_pos <= 'd0;
end
else
cnt_pos <= cnt_pos + 1'b1;
endalways @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div1 <= 1'b0;
end
else if(cnt_pos < CLK_DIV / 2) begin//小于计数值的一半,拉高clk_div1
clk_div1 <= 1'b1;
end
else begin+
clk_div1 <= 1'b0;
end
endalways @(negedge clk or negedge rst_n) begin//时钟下降沿触发
if(!rst_n) begin
cnt_neg <= 'd0;
end
else if(cnt_neg == CLK_DIV - 1) begin//计数到最大值置0
cnt_neg <= 'd0;
end
else begin
cnt_neg <= cnt_neg + 1'b1;
end
endalways @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div2 <= 1'b0;
end
else if(cnt_neg < CLK_DIV / 2) begin//小于计数值的一半,拉高clk_div2
clk_div2 <= 1'b1;
end
else begin
clk_div2 <= 1'b0;
end
endassign clk_o = clk_div1 | clk_div2;
//将clk_div1和clk_div2或运算
*///方法2(来自《硬件架构的艺术》)
//步骤1:创建由时钟上升沿触发的0-(N-1)的计数器,N为分频系数
parameterN=5;
reg[3:0]cnt_up;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_up <= 'd0;
end
else if(cnt_up == N-1) begin
cnt_up <= 'd0;
end
else begin
cnt_up <= cnt_up + 1'b1;
end
end//步骤2:使用两个触发器,按照如下方式产生使能信号
//tff1_en:在计数值为0时使能
//tff2_en:在计数值为(N+1)/2时使能
wiretff1_en;
wiretff2_en;
assign tff1_en = (cnt_up == 0) ? 1'b1 : 1'b0;
assign tff2_en = (cnt_up == (N+1)/2) ? 1'b1 : 1'b0;
//步骤三:产生以下信号
//div1:TFF1的输出--->由输入时钟的上升沿触发
//div2:TFF2的输出--->由输入时钟的下降沿触发
regdiv1;
regdiv2;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div1 <= 1'b0;
end
else if(tff1_en) begin
div1 <= ~div1;
end
else begin
div1 <= div1;
end
endalways @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
div2 <= 1'b0;
end
else if(tff2_en) begin
div2 <=~div2;
end
else begin
div2 <= div2;
end
end//步骤四:将div1和div2信号异或
assign clk_o = div1 ^ div2;
endmodule
推荐阅读
- verilog实战|双边沿计数器verilog设计(详细说明)
- Xilinx|Xilinx ISE系列教程(全网首发)
- 泛联新安EDA系列——国内自主研发,首款集成双国军标的HDL代码缺陷管理平台VHawk
- Verilog|(127)Verilog HDL(设计一个优先编码器之Always case2)
- Verilog|(128)Verilog HDL(设计一个优先编码器之Always casez)
- FPGA之旅设计99例|FPGA之旅设计99例之第十三例-----FPGA在OLED上显示DHT11数据
- FPGA刷题——数据位宽转换(整数倍&非整数倍)
- 视频处理|Syetem Verilog 将视频流输出写入 BMP 图片文件 testbench 激励代码
- 视频处理|Syetem Verilog 用BMP图片文件产生视频流 testbench 激励代码