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.
2 Answers 2
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
-
\$\begingroup\$ Mind helping me with the code? \$\endgroup\$ninesalt– ninesalt2015年12月12日 21:00:28 +00:00Commented Dec 12, 2015 at 21:00
-
\$\begingroup\$ I think this is way too complicated for what I want to do. \$\endgroup\$ninesalt– ninesalt2015年12月12日 21:29:10 +00:00Commented Dec 12, 2015 at 21:29
-
\$\begingroup\$ What, a two always block state machine is too complicated? It is possible to compress it into a single always block, but it's slightly less readable. Also, the template I posted has 3 states; you only need 2. \$\endgroup\$alex.forencich– alex.forencich2015年12月12日 21:44:01 +00:00Commented Dec 12, 2015 at 21:44
-
\$\begingroup\$ Well, I suppose with only two states, you don't really need a whole state machine. \$\endgroup\$alex.forencich– alex.forencich2015年12月12日 21:47:17 +00:00Commented Dec 12, 2015 at 21:47
-
\$\begingroup\$ What is that rst in the first if condition? \$\endgroup\$ninesalt– ninesalt2015年12月12日 22:27:14 +00:00Commented Dec 12, 2015 at 22:27
The basic idea is to use a counter.
Most likely, you'll have a clock of 50Mhz which means you if you count to 50 million starting from 0 on your counter, it will take that clock around 1s. So you can output 1'b1 from your counter's module, once it's done counting. Hence, the output of this counter's module can give you a slowed down clk.
Implement it as explained above.