状态变化太快,我在 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 中使用 fivetentwentyfive 一样使用 pbPulse 输出(即,按钮连接到线路进入 btn,其中一个信号连接到 pbPulse,请注意,您需要三个这样的模块)。

一些其他注意事项,您不应使用 always @(state, five, ten, twentyfive)(即显式敏感列表),而应使用 always @(*)。此外,不要在组合块(即不是 always @(posedge clk) 的块)中使用 NBA(<=),也不要在顺序块(即 always @(posedge clk)).