状态变化太快,我在 basys-2 中使用按钮
States are moving too fast, I use pushbuttons in basys-2
我在模拟售水机。现在,我们在七段解码器下有 4 个按钮。从左到右,前 3 个按钮将用于增加总分。第一个将使总数增加 25 美分,第二个按钮将使总数增加 10 美分,第三个按钮将使总数增加 5 美分。最后,第四个按钮将用于重置计数。
问题是:当我按下 5、10 或 25 美分按钮时,总数立即变为 50 美分并流出水。
这是我的代码:
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
和 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";
您 运行 遇到的问题是您假设按下按钮一次会导致机器看到给定按钮被按下一次。但是,您可能 运行 在 50 Mhz 之类的频率下 运行 关闭时钟。因此,即使您按下按钮半秒钟,机器也会看到按钮被按下数百万个周期(准确地说,50 Mhz 时钟为 25000000 个周期)。这是足够的时间来达到你的最终状态,然后再达到一些。
您需要更改处理输入的方式,方法是向机器添加状态以处理等待按钮返回的操作,或者添加模块以将原始按钮输入转换为脉冲输入。下面是在模块中执行后面操作的示例:
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
现在您可以像在 FSM 中使用 five
、ten
和 twentyfive
一样使用 pbPulse
输出(即,按钮连接到线路进入 btn
,其中一个信号连接到 pbPulse
,请注意,您需要三个这样的模块)。
一些其他注意事项,您不应使用 always @(state, five, ten, twentyfive)
(即显式敏感列表),而应使用 always @(*)
。此外,不要在组合块(即不是 always @(posedge clk)
的块)中使用 NBA(<=
),也不要在顺序块(即 always @(posedge clk)
).
我在模拟售水机。现在,我们在七段解码器下有 4 个按钮。从左到右,前 3 个按钮将用于增加总分。第一个将使总数增加 25 美分,第二个按钮将使总数增加 10 美分,第三个按钮将使总数增加 5 美分。最后,第四个按钮将用于重置计数。
问题是:当我按下 5、10 或 25 美分按钮时,总数立即变为 50 美分并流出水。
这是我的代码:
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
和 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";
您 运行 遇到的问题是您假设按下按钮一次会导致机器看到给定按钮被按下一次。但是,您可能 运行 在 50 Mhz 之类的频率下 运行 关闭时钟。因此,即使您按下按钮半秒钟,机器也会看到按钮被按下数百万个周期(准确地说,50 Mhz 时钟为 25000000 个周期)。这是足够的时间来达到你的最终状态,然后再达到一些。
您需要更改处理输入的方式,方法是向机器添加状态以处理等待按钮返回的操作,或者添加模块以将原始按钮输入转换为脉冲输入。下面是在模块中执行后面操作的示例:
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
现在您可以像在 FSM 中使用 five
、ten
和 twentyfive
一样使用 pbPulse
输出(即,按钮连接到线路进入 btn
,其中一个信号连接到 pbPulse
,请注意,您需要三个这样的模块)。
一些其他注意事项,您不应使用 always @(state, five, ten, twentyfive)
(即显式敏感列表),而应使用 always @(*)
。此外,不要在组合块(即不是 always @(posedge clk)
的块)中使用 NBA(<=
),也不要在顺序块(即 always @(posedge clk)
).