I am simulating water vending machine. Now, we have 4 push-buttons under a seven-segment decoder. From left to right, the first 3 buttons will be used for increasing the cent total. The first one will increase the total by 25 cents, the second button will increase total by 10 cents and third button will increase the total by 5 cents. Finally, the fourth button will be used to reset the count.
The problem is: when I press the 5, 10 or 25 cent buttons, the total instantly goes to 50 cents and dispenses water.
Here is my code:
module DispenserFSM(clk, rst, five, ten, twentyfive, current, dispense);
input clk, rst;
input five, ten, twentyfive;
output [5:0] current;
reg [5:0] current;
output dispense;
reg dispense;
// state encoding
parameter S0= 4'b0000,
S1= 4'b0001,
S2= 4'b0010,
S3= 4'b0011,
S4= 4'b0100,
S5= 4'b0101,
S6= 4'b0110,
S7= 4'b0111,
S8= 4'b1000,
S9= 4'b1001,
S10= 4'b1010;
reg [3:0] state, nextState;
// state register logic
always@(posedge clk, posedge rst)
if(rst == 1)
state <= S0;
else
state <= nextState;
// combinational circuit
always@(state, five, ten, twentyfive)
case(state)
S0: begin
if(five == 1)
nextState <= S1;
else if(ten == 1)
nextState <= S2;
else if(twentyfive == 1)
nextState <= S5;
else
nextState <= S0;
end
S1: begin
if(five == 1)
nextState <= S2;
else if(ten == 1)
nextState <= S3;
else if(twentyfive == 1)
nextState <= S6;
else
nextState <= S1;
end
S2: begin
if(five == 1)
nextState <= S3;
else if(ten == 1)
nextState <= S4;
else if(twentyfive == 1)
nextState <= S7;
else
nextState <= S2;
end
S3: begin
if(five == 1)
nextState <= S4;
else if(ten == 1)
nextState <= S5;
else if(twentyfive == 1)
nextState <= S8;
else
nextState <= S3;
end
S4: begin
if(five == 1)
nextState <= S5;
else if(ten == 1)
nextState <= S6;
else if(twentyfive == 1)
nextState <= S9;
else
nextState <= S4;
end
S5: begin
if(five == 1)
nextState <= S6;
else if(ten == 1)
nextState <= S7;
else if(twentyfive == 1)
nextState <= S10;
else
nextState <= S5;
end
S6: begin
if(five == 1)
nextState <= S7;
else if(ten == 1)
nextState <= S8;
else if(twentyfive == 1)
nextState <= S10;
else
nextState <= S6;
end
S7: begin
if(five == 1)
nextState <= S8;
else if(ten == 1)
nextState <= S9;
else if(twentyfive == 1)
nextState <= S10;
else
nextState <= S7;
end
S8: begin
if(five == 1)
nextState <= S9;
else if(ten == 1)
nextState <= S10;
else if(twentyfive == 1)
nextState <= S10;
else
nextState <= S8;
end
S9: begin
if(five == 1)
nextState <= S10;
else if(ten == 1)
nextState <= S10;
else if(twentyfive == 1)
nextState <= S10;
else
nextState <= S9;
end
S10: begin
nextState <= S10;
end
endcase
// output logic
always@(state)
case(state)
S0: begin
current = 6'b000000;
dispense = 1'b0;
end
S1: begin
current = 6'b000101;
dispense = 1'b0;
end
S2: begin
current = 6'b001010;
dispense = 1'b0;
end
S3: begin
current = 6'b001111;
dispense = 1'b0;
end
S4: begin
current = 6'b010100;
dispense = 1'b0;
end
S5: begin
current = 6'b011001;
dispense = 1'b0;
end
S6: begin
current = 6'b011110;
dispense = 1'b0;
end
S7: begin
current = 6'b100011;
dispense = 1'b0;
end
S8: begin
current = 6'b101000;
dispense = 1'b0;
end
S9: begin
current = 6'b101101;
dispense = 1'b0;
end
S10: begin
current = 6'b110010;
dispense = 1'b1;
end
endcase
endmodule
and ucf
NET "clk" LOC = "B8";
NET "rst" LOC = "G12";
NET "five" LOC = "A7";
NET "ten" LOC = "M4";
NET "twentyfive" LOC = "C11";
NET "current[5]" LOC = "G1";
NET "current[4]" LOC = "P4";
NET "current[3]" LOC = "N4";
NET "current[2]" LOC = "N5";
NET "current[1]" LOC = "P6";
NET "current[0]" LOC = "P7";
NET "dispense" LOC = "M5";
The problem you are running into is that you are assuming pushing down the button onces results in the machine seeing the given button being pushed once. However, you are probably running off a clock running at something like 50 Mhz. Thus, when you push the button down for even half a second, the machine sees the button pressed for millions of cycles (25000000 cycles for a 50 Mhz clock to be exact). Thats way more than enough time to reach your final state and then some.
You need to change how you handle the inputs, either by adding states to you machine to handle waiting for the button to go back up or adding a module to convert the raw button input into a pulsed input. Heres an example of doing the later in a module:
module pb_pulse(input btn,
input clk,
output pbPulse);
reg [1:0] btnState;
// If we see a edge now, but didnt 1 cycle ago, pulse
assign pbPulse = btnState[0] & ~btnState[1];
// Shift register storing the btn state now and 1 cycle ago
always @(posedge clk) begin
btnState <= {btnState[0], btn};
end
endmodule
Now you can use the pbPulse
output just as you are using five
, ten
and twentyfive
in your FSM presently (ie, button is connected to a line going into btn
and one of those signals connects to pbPulse
, note youll need three such modules).
A few other notes, you should not use always @(state, five, ten, twentyfive)
(ie, explicit sensitivity lists), use always @(*)
instead. Also, do not use NBA (<=
) in combinational blocks (ie, ones that arent always @(posedge clk)
) nor blocking assignment (=
) in sequential blocks (ie, ones that ARE always @(posedge clk)
).