How to set a delay in Verilog using a clock

delayintel-fpgaverilog

I'm trying to write an always block that will open a valve and then keep it open for a few seconds and then close it if needed. The valve opens when the input is 1 and it closes when it's zero. How can I make the code wait for a few seconds after the valve opens so that it doesn't close right after it opens?

Here is my code:

input in, alteraclock;
output reg out;
reg clock;

clock myclock(.clkin(alteraclock), .clkout(clock));

always@(in)
begin

if(in==1)

begin
out=1;  //open valve

end

else
begin
out=0;  //close valve
end

end

PS: I'm using an Altera DE2-115, if that helps at all.

Best Answer

Use a state machine and a large counter. In one state, wait for the input to change. When the input changes, set the counter to a large number, update the output, and switch to the delay state. In the delay state, decrement the counter. When it reaches zero, switch back to the wait for input state.

Edit: I'm not going to write your code for you, but here is a template for a state machine that you can play with:

localparam [1:0]
    STATE_IDLE = 2'd0,
    STATE_1 = 2'd1,
    STATE_2 = 2'd2;

reg [1:0] state_reg = STATE_IDLE, state_next;

reg [16:0] count_reg = 0, count_next;

always @* begin
    state_next = STATE_IDLE;

    count_next = count_reg;

    case (state_reg)
        STATE_IDLE: begin
            // idle state
            if (condition) begin
                count_next = some_value;
                state_next = STATE_1;
            end else begin
                state_next = STATE_IDLE;
            end
        end
        STATE_1: begin
            // some state
            count_next = count_reg - 1;

            if (count_reg == 0) begin
                state_next = STATE_2;
            end else begin
                state_next = STATE_1;
            end
        end
        STATE_2: begin
            // another state
            if (some_condition) begin
                state_next = STATE_IDLE;
            end else begin
                state_next = STATE_2;
            end
        end
    endcase
end

always @(posedge clk) begin
    if (rst) begin
        state_reg <= STATE_IDLE;
        count_reg <= 0;
    end else begin
        state_reg <= state_next;
        count_reg <= count_next;
    end
end

Here is a way to do this without an explicit state machine:

reg [32:0] counter = 0;

always @(posedge clk) begin
    if (rst) begin
        counter <= 0;
        out <= 0;
    end else if (counter > 0) begin
        counter <= counter - 1;
    end else begin
        out <= in;
        if (out != in) begin
            counter <= some_delay_value;
        end
    end
end