基于Verilog的双币种自动售货机设计与验证

基于Verilog的双币种自动售货机设计与验证

在数字集成电路设计与FPGA开发入门学习中,自动售货机是训练顺序逻辑设计、掌握有限状态机(FSM)编程思想的经典案例,而支持两种币种识别交易的双币种售货机,相比单币种设计增加了面值判断、可变金额累计的逻辑,更能体现Verilog硬件描述语言对实际场景的抽象建模能力,本文就介绍两种币售货机的Verilog设计实现与验证过程。

设计需求分析

本次设计实现支持两种硬币的自动售货机,核心需求设定为:售货机出售单价固定为8元的商品,支持1元、5元两种面额硬币投入,需要完成三个核心功能:第一,实时累计用户投入的总金额;第二,当累计总金额大于等于商品价格时,触发出货,并根据超额金额完成找零;第三,单次交易完成后自动复位,回到空闲状态等待下一次投币。

端口定义符合Verilog可综合设计规范:输入信号包含系统时钟clk、低电平有效复位rst_n、1元投币脉冲信号one_coin、5元投币脉冲信号five_coin;输出信号包含出货使能信号product_out、3位找零金额信号change(由于最大找零金额为(7+5)-8=4元,3位比特可满足存储需求)。

总体设计思路

两种币售货机的核心逻辑是顺序状态跳转,因此采用三段式有限状态机实现,三段式FSM将状态更新、状态跳转、输出逻辑分离编码,结构清晰,能够有效规避组合逻辑毛刺,符合工业级可综合编程规范。

根据8元的商品定价,我们将已投金额划分为8种状态:S0对应0元(初始空闲状态)、S1对应1元、S2对应2元……S7对应7元,所有累计金额不小于8元的情况都直接触发交易完成,不需要额外定义状态,交易完成后直接返回S0空闲状态。

跳转规则清晰区分两种币种的面值差异:在当前状态下,若检测到1元投币脉冲,总金额增加1元,若新增总金额小于8则跳转到对应金额状态,若大于等于8则触发出货、计算找零后返回S0;若检测到5元投币脉冲,总金额增加5元,后续处理规则与1元投币一致,无投币输入时保持当前状态不变。

Verilog核心实现

以下为两种币售货机的Verilog核心代码框架,完整逻辑可根据状态规则扩展:

module two_coin_vending_machine(
    input        clk,
    input        rst_n,
    input        one_coin,  //1元投币脉冲,高电平有效
    input        five_coin, //5元投币脉冲,高电平有效
    output reg   product_out,
    output reg [2:0] change
);
// 状态定义:对应已投金额0~7元
parameter S0 = 3'd0;
parameter S1 = 3'd1;
parameter S2 = 3'd2;
parameter S3 = 3'd3;
parameter S4 = 3'd4;
parameter S5 = 3'd5;
parameter S6 = 3'd6;
parameter S7 = 3'd7;
reg [2:0] current_state;
reg [2:0] next_state;
// 第一段:时序逻辑更新当前状态
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) current_state <= S0;
    else current_state <= next_state;
end
// 第二段:组合逻辑计算下一个状态
always @(*) begin
    case(current_state)
        S0: begin
            if(one_coin) next_state = S1;
            else if(five_coin) next_state = S5;
            else next_state = S0;
        end
        S5: begin
            if(one_coin) next_state = S6;
            else if(five_coin) next_state = S0; //5+5=10≥8,交易完成返回S0
            else next_state = S5;
        end
        // 其余状态跳转逻辑按相同规则实现,此处省略
        default: next_state = S0;
    endcase
end
// 第三段:时序逻辑输出,控制出货与找零
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        product_out <= 1'b0;
        change <= 3'd0;
    end
    else begin
        product_out <= 1'b0;
        change <= 3'd0;
        case(current_state)
            S5: begin
                if(five_coin) begin
                    product_out <= 1'b1;
                    change <= 3'd2; // 找零10-8=2元
                end
            end
            // 其余交易场景输出逻辑此处省略
        endcase
    end
end
endmodule

本设计完全符合可综合规范,可直接移植到FPGA开发板进行板级验证,对两种币种的差异化金额处理,是本设计和单币种售货机最核心的区别。

功能仿真验证

设计完成后通过ModelSim进行功能仿真,构造多场景测试用例验证逻辑正确性:连续投8枚1