Verilog设计实例(一):自动售货机设计实例

前言

本系列为FPGA设计实例,基于Verilog HDL,题目一般是我在网上看到的一些FPGA相关的实验题目,基本会是一个实际场景的系统实现,而不是简单单元的设计,这是为了能更全面的练习,这些实例一般是可以基于FPGA进行实现的,因为正好手里有一块zynq板子,所以想把这个东西用起来,之前做一个卷积核,但是把ip集成到zynq上和arm核协同验证时一直不成功,所以希望也可以学习一下zynq的软硬件协同使用。

以上是本系列的目的,OK,废话不多说,让我们直接开始第一个开发实例:自动售货机系统的设计。来源:哈工大MOOC。

用状态机设计一个自动售货机

它的投币口每次只能投入一枚五角或一元的硬币。投入一元五角钱硬币后机器自动给出一杯饮料,投入2元钱(2枚一元硬币)后,在给出硬币的同时找零一枚五角的硬币,投币时仅支持一枚一枚投。

信号定义

clk				# 时钟信号输入
rst				# 系统复位信号
half_yuan		# 投入五角硬币信号,信号为“1”代表投入五角
one_yuan		# 投入一元硬币信号,信号为“1”代表投入一元
half_out		# 找零信号,"1"代表找零五角
dispense		# 售出信号,“1“代表售出一杯饮料
collect			# 取走饮料信号,“1”代表购买者取走饮料

状态机

规定三种状态:IDLE——未投币,half——投币五角,one——投币一元。

状态转移图:
状态转移信号为——one_yuan half_yuan/dispense half_out,示例:01/10
自动售货机状态转移图

自动售货机的Verilog描述:


售货机模块的Verilog代码如下:

`timescale 1ns / 1ps

module vending_machine(
                        clk,
                        one_yuan,
                        half_yuan,
                        collect,
                        half_out,
                        dispense,
                        rst
    );

//定义端口
parameter idle=2'b00,half=2'b01,one=2'b10;
input one_yuan,half_yuan,rst,clk;
output reg collect,half_out,dispense;
reg[1:0] ST; //当前状态

//控制逻辑实现
always @(posedge clk)   begin
if(rst)
    begin 
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= idle;
    end
else
    case(ST)
    
        idle:
        if(half_yuan)
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= half;
        end
        else if(one_yuan)
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= one;
        end
        else
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= idle;
        end
            
            
        half:
        if(half_yuan)
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= one;
        end
        else if(one_yuan)
        begin
        dispense <= 1;
        collect <= 1;
        half_out <= 0;
        ST <= idle;        
        end
        else
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= half;
        end
        
        
        one:
        if(half_yuan)
        begin
        dispense <= 1;
        collect <= 1;
        half_out <= 0;
        ST <= idle;
        end
        else if(one_yuan)
        begin
        dispense <= 1;
        collect <= 1;
        half_out <= 1;
        ST <= idle;
        end
        else
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= one;
        end
        
        
        default:
        begin
        dispense <= 0;
        collect <= 0;
        half_out <= 0;
        ST <= idle;
        end
        
    endcase
end
//
endmodule

同时编写testbench激励:

`timescale 1ns / 1ps

module VM_tb();
    reg clk;
    reg rst;
    reg half_yuan;
    reg one_yuan;
    wire collect;
    wire half_out;
    wire dispense;
    
    vending_machine vm1(
                        .one_yuan(one_yuan),
                        .half_yuan(half_yuan),
                        .collect(collect),
                        .half_out(half_out),
                        .dispense(dispense),
                        .clk(clk),
                        .rst(rst)
    );
    
    always #10 clk = ~clk;
    
    always@(posedge clk)
    begin
    one_yuan = {$random}%2;
    half_yuan = ~one_yuan;//连续投币,每次投入一枚硬币
    end
    
    
    
    initial begin
    clk = 0;
    rst = 0;
    one_yuan = 0;
    half_yuan = 0;
    #20
    rst = 1;
    #40
    rst = 0;
    #1000
    $stop;
    end
    
endmodule

testbench激励中假设我们是连续投币,每次只能投一枚一元或五角硬币,硬币足够时就给出饮料,需要找零时即找零。

测试波形

在Vivado中跑仿真,波形截图如下:

从图中可以看到,黄色线前的时钟周期,先投了一元,然后黄色线处又接着投了一元,下一时钟周期给出饮料并且找零五角;给饮料的时钟周期也投了一元,下一周期再投了一元,然后再下一周期给出饮料并且找零,符合我们对售货机的行为描述。

改进之处

对于售货机来说,如果检测到投币后隔了较久才投下一个币,当前代码检测后one_yuan/half_yuan信号不归零,信号在下一个时钟沿可能会重复捕获,所以需要设置一次投币信号检测,检测完成后复原,避免投币信号未发生变化时被多次捕获。
当然也有别的方法来避免重复捕获,比如及时复原投币信号。
还可以为售货机添加其他功能,比如选择货物,补货提醒等更加实用的功能,模拟更多的需求场景。

总结

本实例是一个经典的开发实例,作为练手,可以用来熟悉状态机的设计与实现,对基本hdl语法练习以及基本的激励编写和调试能力练习也有很大的帮助。

版权声明:本文为博主作者:__Retr0原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/platinumrong/article/details/132803821

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2024年1月11日
下一篇 2024年1月11日

相关推荐