上升沿计数器

时间:2016-07-08 15:52:29

标签: verilog counter

我一般都是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

2 个答案:

答案 0 :(得分:1)

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

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

r1 && !r2或者如果您想延迟r2 && !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
    

答案 1 :(得分:1)

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

通常,将块和非阻塞逻辑分成不同的始终块通常被认为是最佳实践。 always @*用于组合(阻止分配),always @(posedge clk)用于顺序(非阻塞分配)。仅供参考:Verilog支持案例陈述,这使得编码值比较容易,然后嵌套else-if。

我想你可能想要使用r2 && !r3代替r1 && !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