FPGA实现时间计数其实算是很基础的功能,首先我们先通过公式了解时间与频率的关系:
ƒ = 1 / T
这里的f表示频率,T表示周期,1的话就是时间国际单位下的1秒。对于FPGA来说f表示的是时钟的频率,T就是该频率下的周期。对于100MHz的时钟信号来说,T = 1 / f = (1*1_000_000_000) / 100_000_000 = 10ns。对于50MHz信号, T = 1 / f = (1*1_000_000_000) / 50_000_000 = 20ns。
知道了以上的基本概念就可以知道具体时间其实就是时钟周期的累加。比如在100MHz 的信号下,需要得到1us的时间,就需要cnt = time / T = 1 * 1_000/10 = 100,就需要累计100个时钟周期。以下的代码块是在100MHz下进行时间计数的,分别产生1us,1ms,1s及设置大于1s的整数计时结束脉冲。

1 `timescale 1ns/1ps 2 module time_cnt 3 #( 4 parameter SYS_FRE = 100_000_000 5 ) 6 ( 7 input i_sys_clk, 8 input i_sys_rstn, 9 input [31:0] i_time_number, 10 output o_1us_pulse, 11 output o_1ms_pulse, 12 output o_1s_pulse, 13 output o_time_end 14 ); 15 16 parameter CLK_PERIOD = 1_000_000_000/SYS_FRE; 17 parameter TIME_1US = 1000/CLK_PERIOD; 18 parameter TIME_STEP = 1000; 19 20 reg [6:0] r_time_us_cnt; 21 reg [9:0] r_time_ms_cnt; 22 reg [9:0] r_time_s_cnt; 23 reg [31:0] r_time_cnt; 24 reg r_time_over; 25 26 wire w_time_1us_end; 27 wire w_time_1ms_end; 28 wire w_time_1s_end; 29 wire w_time_end; 30 31 /******************************************************************************\ 32 1us count 33 \******************************************************************************/ 34 always@(posedge i_sys_clk) 35 begin 36 if(~i_sys_rstn | w_time_1us_end) 37 begin 38 r_time_us_cnt <= 'd1; 39 end 40 else 41 begin 42 r_time_us_cnt <= r_time_us_cnt + 1'b1; 43 end 44 end 45 46 assign w_time_1us_end = (r_time_us_cnt == TIME_1US) ? 1'b1 : 'd0; 47 /******************************************************************************\ 48 1ms count 49 \******************************************************************************/ 50 always@(posedge i_sys_clk) 51 begin 52 if(~i_sys_rstn) 53 begin 54 r_time_ms_cnt <= 'd1; 55 end 56 else if(w_time_1ms_end) 57 begin 58 r_time_ms_cnt <= 'd1; 59 end 60 else if(w_time_1us_end) 61 begin 62 r_time_ms_cnt <= r_time_ms_cnt + 1'b1; 63 end 64 end 65 66 assign w_time_1ms_end = (r_time_ms_cnt == TIME_STEP) & w_time_1us_end ? 1'b1 : 1'b0; 67 /******************************************************************************\ 68 1s count 69 \******************************************************************************/ 70 always@(posedge i_sys_clk) 71 begin 72 if(~i_sys_rstn | w_time_1s_end) 73 begin 74 r_time_s_cnt <= 'd1; 75 end 76 else if(w_time_1ms_end) 77 begin 78 r_time_s_cnt <= r_time_s_cnt + 1'b1; 79 end 80 end 81 82 assign w_time_1s_end = (r_time_s_cnt == TIME_STEP) & w_time_1ms_end ? 1'b1 : 1'b0; 83 /******************************************************************************\ 84 time count ,step unit is s 85 \******************************************************************************/ 86 always@(posedge i_sys_clk) 87 begin 88 if(~i_sys_rstn | w_time_end) 89 begin 90 r_time_cnt <= 'd1; 91 r_time_over <= 'd0; 92 end 93 else if(&r_time_cnt) 94 begin 95 r_time_cnt <= r_time_cnt; 96 r_time_over<= 1'b1; 97 end 98 else if(w_time_1s_end) 99 begin 100 r_time_cnt <= r_time_cnt + 1'b1; 101 end 102 end 103 104 assign w_time_end = (r_time_cnt == i_time_number) & w_time_1s_end ? 1'b1 : 1'b0; 105 106 assign o_1us_pulse = w_time_1us_end; 107 assign o_1ms_pulse = w_time_1ms_end; 108 assign o_1s_pulse = w_time_1s_end; 109 assign o_time_end = w_time_end; 110 111 endmodule
然后是对上述模块的仿真

1 `timescale 1ns/1ps 2 module time_cnt_tb; 3 4 reg clk; 5 reg rst_n; 6 7 8 wire w_1us_pulse; 9 wire w_1ms_pulse; 10 wire w_1s_pulse; 11 wire w_time_end; 12 13 initial 14 begin 15 rst_n = 1'b0; 16 #2000; 17 rst_n = 1'b1; 18 end 19 20 initial 21 begin 22 clk = 1'b0; 23 end 24 25 always #5 clk = ~clk; 26 27 time_cnt 28 #( 29 .SYS_FRE (100_000_000 ) 30 ) 31 u_time_cnt 32 ( 33 .i_sys_clk (clk ), 34 .i_sys_rstn (rst_n ), 35 .i_time_number (2 ), 36 .o_1us_pulse (w_1us_pulse ), 37 .o_1ms_pulse (w_1ms_pulse ), 38 .o_1s_pulse (w_1s_pulse ), 39 .o_time_end (w_time_end ) 40 ); 41 42 43 endmodule
以下就是modelsim仿真后的图像可以看到1us计数产生的脉冲间隔是1000ns即1us。相应的1ms跟1s,及我这里设置的总时间2s都可以通过仿真波形看到,只是仿真2s多的时间modelsim需要跑很久,这里就不贴图了。