Verilog - 创建一个计时器来计算秒数

问题描述 投票:0回答:3

我正在使用 FPGA (BEMICROMAX10) 创建一个使用面包板上七段显示器的数字时钟,但我在让秒数精确到 1 秒时遇到问题。我使用的时钟系统输入是 50 MHz。我将仅将相关代码发布到秒。我用来确定 N 的方程是 (1/50000000) * 2^N = 1,它给出了 25.58,所以当我使用 26 时,它只是有点慢,而当我使用 25 时,它有点太快了。有什么想法可以纠正这个问题吗?

谢谢你

module digital_clock(clk, segsec);
input clk;
output [13:0] segsec;

parameter N = 25;
reg [N-1:0] slow_clk = 0;
reg [7:0] countsec = 0;

always @ (posedge clk)
    slow_clk <= slow_clk + 1'b1;

always @ (posedge slow_clk[N-1])
    if (countsec == 8'b00111011) countsec <= 8'b0;
    else  countsec <= countsec + 8'b1;

assign segsec = (countsec == 8'h0 ) ? 16'b01111110111111:
    (countsec == 8'h1) ? 16'b01111110000110: //1        0000110     0111111
    (countsec == 8'h2) ? 16'b01111111011011: //2        1011011
    (countsec == 8'h3) ? 16'b01111111001111: //3        1001111
    (countsec == 8'h4) ? 16'b01111111100110: //4        1100110
    (countsec == 8'h5) ? 16'b01111111101101: //5        1101101
    (countsec == 8'h6) ? 16'b01111111111101: //6        1111101
    (countsec == 8'h7) ? 16'b01111110000111: //7        0000111
    (countsec == 8'h8) ? 16'b01111111111111: //8        1111111
    (countsec == 8'h9) ? 16'b01111111101111: //9        1101111
    (countsec == 8'ha) ? 16'b00001100111111: //10
    (countsec == 8'hb) ? 16'b00001100000110://11
    (countsec == 8'hc) ? 16'b00001101011011://12
    (countsec == 8'hd) ? 16'b00001101001111://13
    (countsec == 8'he) ? 16'b00001101100110: //14
    (countsec == 8'hf) ? 16'b00001101101101: //15
    (countsec == 8'h10) ? 16'b00001101111101://16
    (countsec == 8'h11) ? 16'b00001100000111://17
    (countsec == 8'h12) ? 16'b00001101111111://18
    (countsec == 8'h13) ? 16'b00001101101111://19
    (countsec == 8'h14) ? 16'b10110110111111://20
    (countsec == 8'h15) ? 16'b10110110000110://21
    (countsec == 8'h16) ? 16'b10110111011011://22
    (countsec == 8'h17) ? 16'b10110111001111://23
    (countsec == 8'h18) ? 16'b10110111100110://24
    (countsec == 8'h19) ? 16'b10110111101101://25
    (countsec == 8'h1a) ? 16'b10110111111101://26
    (countsec == 8'h1b) ? 16'b10110110000111://27
    (countsec == 8'h1c) ? 16'b10110111111111://28
    (countsec == 8'h1d) ? 16'b10110111101111://29
    (countsec == 8'h1e) ? 16'b10011110111111://30
    (countsec == 8'h1f) ? 16'b10011110000110://31
    (countsec == 8'h20) ? 16'b10011111011011://32
    (countsec == 8'h21) ? 16'b10011111001111://33
    (countsec == 8'h22) ? 16'b10011111100110://34
    (countsec == 8'h23) ? 16'b10011111101101://35
    (countsec == 8'h24) ? 16'b10011111111101://36
    (countsec == 8'h25) ? 16'b10011110000111://37
    (countsec == 8'h26) ? 16'b10011111111111://38
    (countsec == 8'h27) ? 16'b10011111101111://39
    (countsec == 8'h28) ? 16'b11001100111111://40
    (countsec == 8'h29) ? 16'b11001100000110://41
    (countsec == 8'h2a) ? 16'b11001101011011://42
    (countsec == 8'h2b) ? 16'b11001101001111://43
    (countsec == 8'h2c) ? 16'b11001101100110://44
    (countsec == 8'h2d) ? 16'b11001101101101://45
    (countsec == 8'h2e) ? 16'b11001101111101://46
    (countsec == 8'h2f) ? 16'b11001100000111://47
    (countsec == 8'h30) ? 16'b11001101111111://48
    (countsec == 8'h31) ? 16'b11001101101111://49
    (countsec == 8'h32) ? 16'b11011010111111://50
    (countsec == 8'h33) ? 16'b11011010000110://51
    (countsec == 8'h34) ? 16'b11011011011011://52
    (countsec == 8'h35) ? 16'b11011011001111://53
    (countsec == 8'h36) ? 16'b11011011100110://54
    (countsec == 8'h37) ? 16'b11011011101101://55
    (countsec == 8'h38) ? 16'b11011011111101://56
    (countsec == 8'h39) ? 16'b11011010000111://57
    (countsec == 8'h3a) ? 16'b11011011111111://58
    (countsec == 8'h3b) ? 16'b11011011101111://59
    16'b01111110111111;
endmodule
verilog hdl
3个回答
2
投票

一般来说,有以下三种方法可以解决这个问题:

  1. 使用具有更合适频率的单独时钟源(例如,1.048576 MHz = 220 Hz)。您使用的主板似乎没有任何用于时钟晶体的插座,但您可以将一个时钟晶体连接到其中一个 GPIO 引脚。

  2. 使用 FPGA 中的 PLL 之一将 50 MHz 时钟转换为适当的频率。有关详细信息,请参阅MAX 10 时钟和 PLL 用户指南

  3. 使用相位累加器生成 1 PPS(每秒脉冲)信号:

    reg [25:0] accum = 0;
    wire pps = (accum == 0);
    
    always @(posedge clk) begin
        accum <= (pps ? 50_000_000 : accum) - 1;
    
        if (pps) begin
            … things to do once per second …
        end
    end
    

    该架构对所有逻辑使用单个时钟信号,而不是从组合逻辑生成单独的、较慢的时钟。 (出于各种原因,您最好使用尽可能少的不同时钟。)


0
投票

您的方程可以计算出您的计数器所需的位数;在这种情况下,您需要一个 26 位计数器。但是计数器可以环绕到您喜欢的任何值;它根本不需要环绕。您已经知道这一点,因为您的另一个计数器已经具有使其在 8'b00111011 (59) 处环绕的逻辑。所以,改变这个:

always @ (posedge clk)
    slow_clk <= slow_clk + 1'b1;

对此:

always @ (posedge clk)
    if (slow_clk == 26'd49999999) slow_clk <= 8'b0;
    else  slow_clk <= slow_clk + 8'b1;

我还注意到你的计数器只有 25 位。这个:

parameter N = 25;

应该是这样的:

parameter N = 26;

但是,正如有人在您之前的问题下提到的那样,您有一个派生时钟。这里不需要派生时钟,如果可以的话,您应该始终避免使用派生时钟。派生时钟不是“同步设计”,因此可能会导致大问题,除非您知道自己在做什么。因此,不要使用 always 对第二个

slow_clk[N-1]
块进行计时,而使用
clk
进行计时,并使用
slow_clk[N-1]
作为使能信号。不要这样做:

always @ (posedge slow_clk[N-1]) if (countsec == 8'b00111011) countsec <= 8'b0; else countsec <= countsec + 8'b1;

这样做:

assign enable = (slow_clk == 26'd49999999); always @ (posedge clk) if (enable == 1'b1) if (countsec == 8'b00111011) countsec <= 8'b0; else countsec <= countsec + 8'b1;

这是 EDA Playground 上的一个版本(
加速了 1000000 倍

):

http://www.edaplayground.com/x/4eeB


0
投票

always_ff@(posedge clock or negedge reset) begin if (~reset | ~led1R) begin Counttimer <= 0; end else if (Counttimer < 'hB71B00) begin Counttimer <= Counttimer + 1; end else if ( Counttimer >= 'hB71B00) //3008 begin Counttimer <= 0; end end

© www.soinside.com 2019 - 2024. All rights reserved.