【问题标题】:Rising Edge Counter上升沿计数器
【发布时间】:2016-07-08 15:52:28
【问题描述】:

总的来说,我是 fpgas 的新手。我想制作每次 SCK 看到上升沿时迭代的计数器。我的代码遇到的问题是它似乎计数了两次。每次出现上升沿转换时,都会点亮两个 LED - 而不是只有一个 LED。知道这可能来自哪里吗?

module spi_slave(pcEn, LED, clk, SCK);
input clk, SCK;
output reg pcEn;
output reg [7:0] LED = 8'h00;
reg r1 = 0;
reg r2 = 0;
reg r3 = 0;
reg [3:0] cnt = 4'b0000;

always @(posedge clk) 
begin

    r1 <= SCK;              
    r2 <= r1;
    pcEn <= r1 && !r3;   
    if (pcEn == 1) begin
        cnt = cnt + 4'b0001;

        if (cnt == 4'b0001) begin
            LED[0] = 1'b1;  
            end
        else if (cnt == 4'b0010) begin
            LED[1] = 1'b1;  
            end
        else if (cnt == 4'b0011) begin
            LED[2] = 1'b1;  
            end
        else if (cnt == 4'b0100) begin
            LED[3] = 1'b1;      
            end
        else if (cnt == 4'b0101) begin
            LED[4] = 1'b1;      
            end
        else if (cnt == 4'b0110) begin
            LED[5] = 1'b1;  
            end
        else if (cnt == 4'b0111) begin
            LED[6] = 1'b1;  
            end
        else if (cnt == 4'b1000) begin
            LED[7] = 1'b1;  
            end
        else
            LED = 8'h00;
        end
    else 
        #100;

    r3 <= r2;
    end

endmodule

【问题讨论】:

    标签: verilog counter


    【解决方案1】:

    计数器计数两次​​,因为您正在比较 r1 &amp; !r3

    r1->r2->r3 。在 r1 等于 1 之后设置 r3 需要 2 个时钟。这意味着r1&amp;!r3 条件将在 2 个时钟内保持有效。 pcEn 将产生 2 个时钟,因此计数器将计数两次。

    r1 &amp;&amp; !r2 或者如果你想要延迟 r2 &amp;&amp; !r3 应该可以正常工作。

    您应该能够在要调试的波形中看到此行为。在您的模拟中使用$dumpvars; 来查看波形。

    还有一些更改可以改进代码。

    1. 使用重置。
    2. 始终使用非阻塞赋值。
    3. 不需要#100 延迟。

      module spi_slave(pcEn, LED, clk, SCK,rst_n);
      input clk, SCK,rst_n;
      output reg pcEn;
      output reg [7:0] LED ;
      reg r1 ;
      reg r2 ;
      reg r3 ;
      reg [3:0] cnt ;
      
      always @(posedge clk or negedge rst_n)
      begin
      
         if ( rst_n == 0 )
         begin
              r1 <=0 ;
              r2 <= 0 ;
              r3 <= 0 ;
              cnt <= 0 ;
              LED <=0 ;
              pcEn <=0 ;
         end
         else
         begin
               r1 <= SCK;
               r2 <= r1;
               r3 <= r2;
               pcEn <= r2 && !r3;
               if (pcEn == 1) begin
                   cnt <= cnt + 4'b0001;
      
                   if (cnt == 4'b0001) begin
                       LED[0] <= 1'b1;
                       end
                   else if (cnt == 4'b0010) begin
                       LED[1] <= 1'b1;
                       end
                   else if (cnt == 4'b0011) begin
                       LED[2] <= 1'b1;
                       end
                   else if (cnt == 4'b0100) begin
                       LED[3] <= 1'b1;
                       end
                   else if (cnt == 4'b0101) begin
                       LED[4] <= 1'b1;
                       end
                   else if (cnt == 4'b0110) begin
                       LED[5] <= 1'b1;
                       end
                   else if (cnt == 4'b0111) begin
                       LED[6] <= 1'b1;
                       end
                   else if (cnt == 4'b1000) begin
                       LED[7] <= 1'b1;
                       end
                   else
                       LED <= 8'h00;
               end
         end
      end
      
      endmodule
      

    【讨论】:

      【解决方案2】:

      # 中的第一个延迟是不可合成的,它们只是用于模拟的延迟。

      通常认为将块和非阻塞逻辑分成不同的始终块的最佳做法。 always @* 用于组合(阻塞分配),always @(posedge clk) 用于顺序(非阻塞分配)。仅供参考:Verilog 支持 case-statements,这使得编码值比较比嵌套 else-if 更容易。

      我认为你可能想使用 r2 &amp;&amp; !r3 而不是 r1 &amp;&amp; !r3,正如 Rahul 也指出的那样

      always @* begin
        if (pcEn == 1'b0) begin
          next_cnt = cnt;
          next_LED = LED;
        else begin
          next_cnt = cnt + 4'b0001;
          next_LED = 8'h00; // Rest all to 0s
          if(cnt >= 8'h8) next_cnt = 4'b0000; // optional : assuming you want to roll back before waiting another 8 SCK toggles
          case(cnt)
          4'b0000 : next_LED[0] = 1'b1;
          4'b0001 : next_LED[1] = 1'b1;
          // ...
          4'b0111 : next_LED[7] = 1'b1;
          endcase
        end
      end
      always @(posedge clk) begin
        r1 <= SCK;
        r2 <= r1;
        r3 <= r2;
        pcEn <= r2 && !r3;
        cnt <= next_cnt;
        LED <= next_LED;
      end
      

      【讨论】:

        猜你喜欢
        • 2022-11-27
        • 2014-11-27
        • 2013-02-18
        • 2020-07-31
        • 1970-01-01
        • 1970-01-01
        • 2021-06-20
        • 2014-01-08
        • 1970-01-01
        相关资源
        最近更新 更多