上升沿计数器



我是 fpga 的新手。 我想制作每次 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

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

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

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

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

还有一些更改来改进代码。

  1. 使用重置。
  2. 始终使用非阻塞分配。
  3. 不需要
  4. #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
    

首先#延迟是不可合成的,它们只是用于模拟的延迟。

通常被认为是将块和非阻塞逻辑分离到不同的始终块中的最佳实践。 always @*用于组合(阻塞分配),always @(posedge clk)用于顺序(非阻塞分配)。仅供参考:Verilog支持大小写语句,这使得编码值比较比嵌套else-if更容易。

我想你可能想使用r2 && !r3而不是r1 && !r3正如拉胡尔还指出的那样

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

相关内容

  • 没有找到相关文章

最新更新