在FPGA设计中经常需要使用到计时器,包括使用系统时钟产生1ms,10ms,100ms,1s计时等信号。使用一个通用的计时器产生模块,可以方便其它模块调用,参考代码如下:
// *****************************************************************************
// Project Name : *
// Target Device : *
// Tool version : *
// Module Name : timer_gen
// Description : timer generation
// Function : to generate all kinds of timer signals
// Attention : *
// Version History : *
// *****************************************************************************
// Engineer : zyhe
// Date : 2016-01-01
// Modification : 1) initial version
// *****************************************************************************
// Engineer : zyhe
// Date : 2016-05-01
// Modification : 1) standard coding style
// i_ for input, o_ for output, w_ for wire, r_ for register
// *****************************************************************************
// All rights reserved.
// *****************************************************************************
`timescale 1ns / 1ps
module timer_gen # (
parameter CLK_FREQ = 125000000 // max to 65536*2000 = 131.072MHz
) (
input i_sys_rst , // system reset
input i_sys_clk , // system clock
output reg o_pulse_1khz , // 50% duty, cycle is 1ms
output reg o_pulse_100hz , // 50% duty, cycle is 10ms
output reg o_pulse_10hz , // 50% duty, cycle is 100ms
output reg o_pulse_1hz , // 50% duty, cycle is 1s
output reg o_tick_1khz , // 1 high duty, cycle is 1ms
output reg o_tick_100hz , // 1 high duty, cycle is 10ms
output reg o_tick_10hz , // 1 high duty, cycle is 100ms
output reg o_tick_1hz // 1 high duty, cycle is 1s
);
reg [15:0] r_cnt_1khz ; // 62500
reg [2:0] r_cnt_100hz ;
reg [2:0] r_cnt_10hz ;
reg [2:0] r_cnt_1hz ;
reg r_clk_1khz ;
reg r_clk_1khz_d0 ; // delay one cycle
reg r_clk_100hz ;
reg r_clk_100hz_d0 ; // delay one cycle
reg r_clk_10hz ;
reg r_clk_10hz_d0 ; // delay one cycle
reg r_clk_1hz ;
reg r_clk_1hz_d0 ; // delay one cycle
always @ (posedge i_sys_clk)
begin
if (i_sys_rst)
begin
r_cnt_1khz <= 16'd0;
r_clk_1khz <= 1'b0;
end
else if (r_cnt_1khz == (CLK_FREQ / 2000) - 1)
begin
r_cnt_1khz <= 16'd0;
r_clk_1khz <= ~r_clk_1khz;
end
else
begin
r_cnt_1khz <= r_cnt_1khz + 1'b1;
r_clk_1khz <= r_clk_1khz;
end
end
always @ (posedge i_sys_clk)
begin
r_clk_1khz_d0 <= r_clk_1khz;
if (i_sys_rst)
begin
r_cnt_100hz <= 4'd0;
r_clk_100hz <= 1'b0;
end
else if (~r_clk_1khz_d0 & r_clk_1khz)
begin
if (r_cnt_100hz == 4'd4)
begin
r_cnt_100hz <= 4'd0;
r_clk_100hz <= ~r_clk_100hz;
end
else
begin
r_cnt_100hz <= r_cnt_100hz + 1'b1;
r_clk_100hz <= r_clk_100hz;
end
end
end
always @ (posedge i_sys_clk)
begin
r_clk_100hz_d0 <= r_clk_100hz;
if (i_sys_rst)
begin
r_cnt_10hz <= 4'd0;
r_clk_10hz <= 1'b0;
end
else if (~r_clk_100hz_d0 & r_clk_100hz)
begin
if (r_cnt_10hz == 4'd4)
begin
r_cnt_10hz <= 0;
r_clk_10hz <= ~r_clk_10hz;
end
else
begin
r_cnt_10hz <= r_cnt_10hz + 1'b1;
r_clk_10hz <= r_clk_10hz;
end
end
end
always @ (posedge i_sys_clk)
begin
r_clk_10hz_d0 <= r_clk_10hz;
if (i_sys_rst)
begin
r_cnt_1hz <= 4'd0;
r_clk_1hz <= 1'b0;
end
else if (~r_clk_10hz_d0 & r_clk_10hz)
begin
if (r_cnt_1hz == 4'd4)
begin
r_cnt_1hz <= 4'd0;
r_clk_1hz <= ~r_clk_1hz;
end
else
begin
r_cnt_1hz <= r_cnt_1hz + 1'b1;
r_clk_1hz <= r_clk_1hz;
end
end
end
always @ (posedge i_sys_clk)
begin
o_pulse_1khz <= r_clk_1khz;
o_pulse_100hz <= r_clk_100hz;
o_pulse_10hz <= r_clk_10hz;
o_pulse_1hz <= r_clk_1hz;
o_tick_1khz <= r_clk_1khz & (~r_clk_1khz_d0);
o_tick_100hz <= r_clk_100hz & (~r_clk_100hz_d0);
o_tick_10hz <= r_clk_10hz & (~r_clk_10hz_d0);
o_tick_1hz <= r_clk_1hz & (~r_clk_1hz_d0);
end
endmodule