LED开关的简单Verilog示例?

时间:2013-05-30 16:02:44

标签: verilog hdl

我正在尝试为1热编码的简单LED开关按钮构建StateMachine。

特别是我试图用我的例子来理解阻塞和非阻塞分配。

你能不能做得更好,或者在任何街区完全错误?

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);


reg on;
reg off;

reg t_on_off;
reg t_off_on;


always @* begin
  t_on_off = on & (push);
end

always @* begin
  t_off_on = off & (push);
end


always @(posedge clk or posedge rst) begin
  if (rst)              on <= 1'b0;
  else if (t_off_on)    on <= 1'b1;
  else if (t_on_off)    on <= 1'b0;
end

always @(posedge clk or posedge rst) begin
  if (rst)              off <= 1'b1;
  else if (t_off_on)    off <= 1'b0;
  else if (t_on_off)    off <= 1'b1;
end


always @* begin
  led_on = on;
end


endmodule

特别是我想知道:我可以将转换的分配合并到一个单独的块中,例如:

always @* begin
  t_on_off = on & (push);
  t_off_on = off & (push);
end

5 个答案:

答案 0 :(得分:3)

如果它不需要一热,那么将其简化为:

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);

always @(posedge clk or posedge rst) begin
  if (rst)        led_on  <= 1'b0;
  else if (push)  led_on  <= !led_on;
end

endmodule

它的功能与您拥有的功能相同,更具可读性。

答案 1 :(得分:1)

  

特别是我想知道:我可以将过渡的分配组合成一个单独的块,比如......

是的,你可以完全按照你的描述那样做。

如果需要,您也可以组合顺序块:

always @(posedge clk or posedge rst) begin
  if (rst) begin
     on  <= 1'b0;
     off <= 1'b1;
  end else if (t_off_on) begin
     on  <= 1'b1;
     off <= 1'b0;
  end 
  (etc....)
end

答案 2 :(得分:1)

是的,您可以将多个始终块合并为一个。

您只需将同步(异步)和异步块分离为单独的始终块。

然而,一个好的风格是为每个输出都有一个始终块。这更容易阅读,更真实,就像每个总是块彼此同时一样。

答案 3 :(得分:1)

重构建议:

output reg led_on;

always @* begin
  led_on = on;
end

为:

output led_on; //wire by default (not declared reg)

assign led_on = on;

您也可以对t_on_offt_off_on

执行相同的操作
wire t_on_off;
wire t_off_on;

assign t_on_off = on  & (push);
assign t_off_on = off & (push);

或者如果你喜欢滚动声明并在一行中分配。

wire t_on_off = on  & (push);
wire t_off_on = off & (push);

但是如果你将两个时钟总是块一起滚动到一个,则不需要单独的逻辑,将@Tim的答案与t_on_off检查结合起来:

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);

reg on;
reg off;

assign  led_on = on;

always @(posedge clk or posedge rst) begin
  if (rst) begin
    on  <= 1'b0;
    off <= 1'b1;
  end
  else if (off & push) begin
    on  <= 1'b1;
    off <= 1'b0;
  end
  else if (on  & push) begin
    on  <= 1'b0;
    off <= 1'b1;
  end
end

endmodule

答案 4 :(得分:0)

这已经过去很久了,但所提出的解决方案可能并不完全符合您的预期。从我可以推断出的解决方案,所有人都认为只要按下按钮(即它将按时钟的频率切换),LED就会保持切换状态,如果时钟频率很高,则会在视觉上察觉不到。但是,我认为你会想要每次按下按钮时只切换LED一次,在此期间保持LED状态。

以下示例根据3个按钮的活动切换3个LED的状态。

    只要按下 pbutton0 ,就会激活
  1. led0
  2. led1 会定期切换(基于 clk_div 的大小)并在按下 pbutton1 时重置。
  3. 每当按下 pbutton2 时,
  4. led2 就会切换。
  5. 请注意, led0 是组合的,而其他两个LED是顺序的。要切换 led2 ,必须存储 pbutton2 的先前状态;每当 pbutton2(t-1) == 0和 pbutton2(t) == 1时,这意味着按钮刚刚从低到高,因此,状态 led2 必须改变。

    最后,请忽略时钟源,因为它仅用于演示Xilinx SP605开发套件中的代码。

    ////////////////////////////////////////////////////
    // This project uses 3 pushbuttons and 3 LEDs.
    //  pbutton0 activates led0
    //  pbutton1 serves as reset for led1 periodic toggling
    //  pbutton2 toggles led2
    //
    // The clock source (divider+buffer) was created using the clocking IP wizard.
    //
    
    module xilinx_sp605_board_leds
    (
        input CLK_IN1_P,
        input CLK_IN1_N,
    
        input pbutton0,
        input pbutton1,
        input pbutton2,
    
        output led0,
        output reg led1,
        output reg led2
    );
    
    // declarations
    wire clk;
    wire reset = pbutton1;
    reg [19:0] clk_div;
    reg pbutton2_reg;
    
    // led0 = state of pbutton0
    assign led0 = pbutton0;
    
    // differential clock divider+buffer
    clk_source CLK_SOURCE (
        .CLK_IN1_P(CLK_IN1_P),
        .CLK_IN1_N(CLK_IN1_N),
        .CLK_OUT1(clk),
        .RESET(reset));
    
    // led1, led2 toggling
    always @(posedge reset or posedge clk)
    begin
        if(reset)begin
            clk_div <= 0;
            led1 <= 0;
    
            pbutton2_reg <= 0;
            led2 <= 0;
        end else begin
            clk_div <= clk_div + 1;
            if(clk_div==0) 
                led1 <= ~led1;
    
            pbutton2_reg <= pbutton2;
            if(~pbutton2_reg && pbutton2)
                led2 <= ~led2;
        end
    end
    
    endmodule