在某些情况下需要对系统时钟分频后的时钟进行周期检测,引出周期标志信号以便在后续其他情况的使用。虽然在大多数情况下我们能够知道分频后的时钟是系统时钟的几倍分频,但为增强在分频时钟改变情况下周期标志信号的复用性或对未知时钟的周期检测,可以考虑以下方法或思想,以延申到类似情况下使用。
 
文章目录
- 检测方法
 - 方法一:上升沿判断
 - 方法二:时钟移位判断
 
- 实现与仿真
 - Verilog实现
 - 仿真测试
 
检测方法
方法一:上升沿判断
将时钟打一拍后取clk&(~clk_reg),上升沿时该值会拉高一个时钟周期。
也可以用下降沿进行判断方法类似。
方法二:时钟移位判断
对时钟左移判断移位后的值,移位后dived_clk_buf==2'd1即为上升沿到来,dived_clk_buf==2'd2即为下降沿到来。
reg  [1:0]      dived_clk_buf    ;always  @(posedge  clk or negedge rst_n)
beginif(rst_n == 1'b0)dived_clk_buf <= 2'd3;else dived_clk_buf <= {dived_clk_buf[0],dived_clk};//移位时钟以判断周期
endalways  @(posedge  clk or negedge rst_n)
beginif(rst_n == 1'b0)XX;else if(dived_clk_buf==2'd1)XXX;else XXXX;
end
 
实现与仿真
Verilog实现
由两部分组成:产生分频时钟模块+周期检测标志模块;改变分频时钟模块的分频周期可在仿真测试文件中例化时进行参数修改。
产生分频时钟模块:
//========================================================================
// 	Author			:YprgDay
//========================================================================
module dived_clk
#(parameter 				DIV_FREQUENCY		=	4				,//分频数(只允许偶分频),dived_clk周期为DIV_FREQUENCY*clk的周期parameter 				PERIOD_WIDTH_MAX	=	2				,//(DIV_FREQUENCY-1)对应的二进制位宽parameter 				CNT_PERIOD_MAX		=	DIV_FREQUENCY-1	,parameter 				CNT_HALF_PERIOD_MAX	=	CNT_PERIOD_MAX >> 1//计数分频中值
)
(input 	wire rst_n 	,input 	wire clk 	,output  reg  dived_clk
);reg [PERIOD_WIDTH_MAX-1:0] 		cnt_period			;//时钟分频计数//分频时钟always @(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)begindived_clk <= 0;endelse if(cnt_period == CNT_PERIOD_MAX)begindived_clk <= 0;endelse if(cnt_period == CNT_HALF_PERIOD_MAX)begindived_clk <= 1;endelse begindived_clk <= dived_clk;endend//分频计数器always @(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)begincnt_period <= 0;endelse if(cnt_period == CNT_PERIOD_MAX)begincnt_period <= 0;endelse begincnt_period <= cnt_period + 1'b1;endend	
endmodule
 
周期检测标志模块:
//========================================================================
// 	Author			:YprgDay
//========================================================================
module clk_period(input 	wire 	rst_n 		,input 	wire 	clk 		,input 	wire 	dived_clk	,output 	wire 	clk_flag1	,output 	wire 	clk_flag2
);reg 		dived_clk_reg		;reg  [1:0]  dived_clk_buf  		;//==========================< 方法一 >============================always @(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)begindived_clk_reg <= 0;endelse begindived_clk_reg <= dived_clk;endend	assign clk_flag1 = dived_clk&(~dived_clk_reg);//==========================< 方法二 >============================always  @(posedge  clk or negedge rst_n)beginif(rst_n == 1'b0)dived_clk_buf <= 2'd3;else dived_clk_buf <= {dived_clk_buf[0],dived_clk};//左移endassign clk_flag2 = (dived_clk_buf==2'd1);
endmodule
 
仿真测试
仿真产生系统时钟与复位信号。
//========================================================================
// 	Author			:YprgDay
//========================================================================
`timescale 1ns/1ns
module tb_clk_period();parameter 				CLK_PERIOD		=	10		    ;//设置时钟信号周期parameter 				HALF_CLK_PERIOD	=	CLK_PERIOD/2;//生成时钟信号半周期reg                     i_rst_n							;reg                     i_clk							;wire					dived_clk						;wire					clk_flag1						;wire					clk_flag2                       ;//==========================< Clock block >============================always 	  	#HALF_CLK_PERIOD		i_clk = ~i_clk;//==========================< i_rst_n block >============================initial begini_clk 	  = 	1'b1	;i_rst_n  <= 	1'b0	;#40i_rst_n  <= 	1'b1	;enddived_clk #(.DIV_FREQUENCY	  (8),//分频数(只允许偶分频),dived_clk周期为DIV_FREQUENCY*clk的周期.PERIOD_WIDTH_MAX (3)//(DIV_FREQUENCY-1)对应的二进制位宽)u_dived_clk(.rst_n		(i_rst_n	),.clk 		(i_clk		),.dived_clk  (dived_clk	));clk_period u_clk_period(.rst_n 		(i_rst_n 	),.clk 		(i_clk 		),.dived_clk	(dived_clk  ),.clk_flag1	(clk_flag1	),.clk_flag2  (clk_flag2	)
);
endmodule
 
仿真效果如下:
可以看出方法一的时钟标志信号在时钟上升沿后拉高;方法二的时钟标志信号在时钟上升沿后下一拍拉高。
