用FPGA制作一个简单的自动售货机

这篇博客讲了如何用FPGA模拟实现自动售卖机的功能。

文章目录

  • 用FPGA制作一个简单的自动售货机
  • 1. 程序功能和总体框架详解
  • 2.Divider分频模块
  • 3.Debounce模块,按键去抖
  • 4.FSM状态机
  • 5.Seg显示模块
  • 6.Siren蜂鸣器报警模块
  • 7. Led灯闪烁模块
  • 总结

1. 程序功能和总体框架详解

程序功能:

  • 按键K3为复位信号,led0,led1控制led等,siren控制蜂鸣器,seg_sel和seg_led分别控制数码管的片选和位选信号
  • 有两个商品cnt_40和cnt_50,分别价值40元和50元,K1,K2连接按键,每按一下,代表要购买的cnt_40和cnt_50加1,例如:买2个cnt_40,1个cnt_50,则按2下K1和1下K2,选好商品后,按K4确认;
  • 确认后开始投币,投币时K1,K2分别代表投入10元硬币和20元硬币,按K4确认;
  • 用4个数码管分别显示2个商品购买个数和2种硬币投入个数
  • 若硬币价钱和商品价钱相等,则出货:两个led灯的闪烁次数表示两个商品的出货个数
  • 若不相等,蜂鸣器报警

    整体框架的代码如下所示:
module top(input k1,input k2,input k4,input k3,input clk,output led1,output led2,output [5:0] seg_sel,output [7:0] seg_led,output siren);
wire key1,key2,key4,le,sir,f1hz;
wire [3:0] cnt_40;
wire [3:0] cnt_50;
wire [3:0] coin_10;
wire [3:0] coin_20;
wire [2:0] cnt;
wire [15:0] data;
assign data={cnt_40[3:0],cnt_50[3:0],coin_10[3:0],coin_20[3:0]};
debounce  d1 (.rst(k3),.clock(clk),.noisy(k1),.clean(key1));  //Debounce模块
debounce  d2 (.rst(k3),.clock(clk),.noisy(k2),.clean(key2));
debounce  d3 (.rst(k3),.clock(clk),.noisy(k4),.clean(key4));
fsm f1(.clock(f1hz),.k1(key1),.k2(key2),.k3(k3),.k4(key4),.led(le),.siren(sir),.cnt_40(cnt_40),.cnt_50(cnt_50),.coin_10(coin_10),.coin_20(coin_20));
divider  di1(.clock(clk),.rst(k3),.wave(f1hz)); //对应图中FSM模块
led  l1(.clk(clk),.cnt_40(cnt_40),.cnt_50(cnt_50),.led(le),.rst(k3),.wave(f1hz),.led1(led2),.led0(led1));
siren  si(.clk(clk),.rst(k3),.start(sir),.sir(siren));
display dx(.clk(clk),.rst(k3), .data(data),.seg_sel(seg_sel),.seg_led(seg_led));//对应图中Seg模块
endmodule

clk为时钟信号,下面是各个模块的解析和代码

实物效果图如下:

2.Divider分频模块

我使用的FPGA开发板的时钟频率为25Mhz,通过这个程序分频,得到一个1hz的时钟信号,led闪烁时,闪太快我们人眼看不出来,所以需要一个1hz的时钟信号,来让它闪慢一点。

module divider(input clock,input rst,output reg wave);
reg [30:0] cnt;
always@(posedge clock or negedge rst)
if(!rst)
begin
cnt<=0;
wave<=0;
end
else if(cnt==25000000)
begin
cnt<=0;
wave<=!wave;
end
else
begin
wave<=wave;
cnt<=cnt+1;
end
endmodule

3.Debounce模块,按键去抖

确保按键按一次,只会产生一个下降沿,因此需要一个去抖动模块

module debounce #(parameter DELAY=500000)(input rst, clock, noisy,output reg clean);reg [19:0] count;reg new;always @(posedge clock)if (!rst)begincount <= 0;new <= noisy;clean <= noisy;endelse if (noisy != new)beginnew <= noisy;count <= 0;endelse if (count == DELAY)clean <= new;elsecount <= count+1;
endmodule

4.FSM状态机

有4种状态,

  • Pay状态读取购物信息
  • BIJIAO状态来比较货物价值和投入硬币价值是否相等
  • SIREN_ON状态控制蜂鸣器报警
  • CHUHUO控制出货(led闪烁)
module fsm(input clock,input k1,input k2,input k3,input  k4,output reg led,output reg siren,output reg [3:0] cnt_40,output reg [3:0] cnt_50,output reg [3:0] coin_10,output reg [3:0] coin_20);parameter PRICE = 0;parameter PAY = 1;//jie shou zhi fu shu liangparameter BIJIAO = 2;//pan duanparameter SIREN_ON = 3;//bao jingparameter CHUHUO = 4;//chu huoreg [2:0] state;always @ (posedge clock or negedge k3 )if (!k3)           //复位beginstate <= PRICE;cnt_40<=0;cnt_50<=0;coin_20<=0; coin_10<=0;
endelse         begincase (state)PRICE:         begin               //K1和K2按键决定cnt_40和cnt_50的购买数量,并输出到数码管显示;led <= 0;          //k4按键确认时,进入投币付费状态PAYsiren <= 0;if(!k1)begincnt_40 <= cnt_40 + 1;endif(!k2)begincnt_50 <= cnt_50 + 1;endif(!k4)beginstate <= PAY;endelsestate<=state;endPAY:      begin                       //投币付费状态,K1,K2按键决定10和20的硬币投入数量,并输出到数码管显示if(!k1)        //K4按键确认后,进入比较状态BIJIAO begincoin_10 <= coin_10 + 1;endelse if(!k2)begincoin_20 <= coin_20 + 1;endelse  if(!k4)state<=BIJIAO;elsestate<=state;endBIJIAO:  begin      //比较输入的货物价值和投入硬币价值是否相等,若相等,出货CHUHUO状态,否则报警状态SIREN_ONif((4 * cnt_40+ 5 * cnt_50) == (2*coin_20  + coin_10))beginstate <= CHUHUO;endelsebeginstate <= SIREN_ON;endendCHUHUO:     begin   //出货,led=1使能LED模块,LED模块后面介绍,开启两个led闪烁,闪烁次数等于两个货物的数量led <= 1;siren <= 0;endSIREN_ON:       begin    //报警,siren控制SIREN模块,使蜂鸣器报警led <= 0;siren <= 1;enddefault:       state <= PRICE;endcase
endendmodule

5.Seg显示模块

接受来自状态机FSM的货物数量信号cnt_40,cnt_50,和投入10元20元硬币数量coin_10和coin_20;并使用4个数码管将其显示出来;
数码管显示的程序讲解已经有很多了,这里就不赘述了

module display(input                clk,input                rst,input        [15:0]  data,output  reg  [5:0]   seg_sel,output  reg  [7:0]   seg_led
);localparam  CLK_DIVIDE = 4'd10     ;
localparam  MAX_NUM    = 13'd5000  ;reg    [3:0]              clk_cnt  ;
reg                       dri_clk  ;
reg    [12:0]             cnt0     ;
reg                       flag     ;
reg    [2:0]              cnt_sel  ;
reg    [3:0]              num_disp ; always @(posedge clk or negedge rst) beginif(!rst) beginclk_cnt <= 4'd0;dri_clk <= 1'b1;endelse if(clk_cnt >= CLK_DIVIDE/2 - 1'd1) beginclk_cnt <= 4'd0;dri_clk <= ~dri_clk;endelse beginclk_cnt <= clk_cnt + 1'b1;dri_clk <= dri_clk;end
endalways @ (posedge dri_clk or negedge rst) beginif (rst == 1'b0) begincnt0 <= 13'b0;flag <= 1'b0;endelse if (cnt0 < MAX_NUM - 1'b1) begincnt0 <= cnt0 + 1'b1;flag <= 1'b0;endelse begincnt0 <= 13'b0;flag <= 1'b1;end
endalways @ (posedge dri_clk or negedge rst) beginif (rst == 1'b0)cnt_sel <= 3'b0;else if(flag) beginif(cnt_sel < 3'd4)cnt_sel <= cnt_sel + 1'b1;elsecnt_sel <= 3'b0;endelsecnt_sel <= cnt_sel;
endalways @ (posedge dri_clk or negedge rst) beginif(!rst) beginseg_sel  <= 6'b111111;num_disp <= 4'b0;           endelse begincase (cnt_sel)3'd0 :beginseg_sel  <= 6'b111101;num_disp <= data[3:0] ; end3'd1 :beginseg_sel  <= 6'b111011;num_disp <= data[7:4] ;end3'd2 :beginseg_sel  <= 6'b110111;num_disp <= data[11:8];end3'd3 :beginseg_sel  <= 6'b101111;num_disp <= data[15:12];enddefault :beginseg_sel  <= 6'b111111;num_disp <= 4'b0;endendcaseend
end
always @ (posedge clk or negedge rst) beginif (!rst)seg_led <= 8'b0;else begincase (num_disp)4'h0 :    seg_led <= 8'b1100_0000;4'h1 :    seg_led <= 8'b1111_1001;4'h2 :    seg_led <= 8'b1010_0100;4'h3 :    seg_led <= 8'b1011_0000;4'h4 :    seg_led <= 8'b1001_1001;4'h5 :    seg_led <= 8'b1001_0010;4'h6 :    seg_led <= 8'b1000_0010;4'h7 :    seg_led <= 8'b1111_1000;4'h8 :    seg_led <= 8'b1000_0000;4'h9 :    seg_led <= 8'b1001_0000;4'ha :    seg_led <= 8'b1000_1000;4'hb :    seg_led <= 8'b1000_0011;4'hc :    seg_led <= 8'b1100_0110;4'hd :    seg_led <= 8'b1010_0001;4'he :    seg_led <= 8'b1000_0110;4'hf :    seg_led <= 8'b1000_1110;default : seg_led <= 8'b1100_0000;endcaseend
endendmodule

6.Siren蜂鸣器报警模块

蜂鸣器报警没什么好讲的,低电平就不响,高电平就响,以一定的频率开关蜂鸣器,能产生不同的声音,该蜂鸣器模块功能:

  • start信号为1时,开启蜂鸣器报警
  • 开启蜂鸣器报警时,蜂鸣器以一定的频率发出声音
module siren(input clk,input rst,input start,output reg sir);
reg [24:0] T;
reg [24:0] cnt;
reg [24:0] cnt1;
reg clk1;
always@(posedge clk)
if(cnt1>1000_0000)
begin
cnt1<=0;
clk1<=!clk1;
end
else
cnt1<=cnt1+1;always@(posedge clk1)
if(!rst)
T<=0;
else if(T<50000 || T>100000)
begin
T<=50000;
end
else begin
T<=T+10000;
endalways@(posedge clk or negedge rst)
if(!rst)
begin
sir<=0;
cnt<=0;
end
else if(start==1 && cnt<T)
cnt<=cnt+10;
else if(start==1)
begin
cnt<=0;
sir<=!sir;
end
else begin
sir<=0;
cnt<=0;
end
endmodule

7. Led灯闪烁模块

该模块功能:

  • 控制信号为1时,控制两个led灯闪烁
  • 闪烁的次数等于输入的两个信号代表的数量
module led(input clk,input [3:0] cnt_40,input [3:0] cnt_50,input led,input rst,input wave,output reg led1,output reg led0);
reg  led0_twinkle;
reg  led1_twinkle;
reg  [3:0]    num1;
reg  [3:0]    num2;
always@(posedge clk or negedge rst)if(!rst)beginled0 <=1'b0;led1 <=1'b0;endelse if(!led)beginled0 <=1'b0;led1 <=1'b0;endelsebeginled0 <=led0_twinkle;led1 <=led1_twinkle;endalways@(posedge wave)
if(!rst)
begin
led0_twinkle <=0;
num1<=0;
end
else if (led==1 && num1<2*cnt_40)
begin
led0_twinkle <=!led0_twinkle;
num1<=num1+1;
end
else
begin
led0_twinkle <=0;
num1<=num1;
endalways@(posedge wave)
if(!rst)
begin
led1_twinkle <=0;
num2<=0;
end
else if (led==1 && num2<2*cnt_50)
begin
led1_twinkle <=!led1_twinkle;
num2<=num2+1;
end
else
begin
led1_twinkle <=0;
num2<=num2;
endendmodule

总结

这里对文章进行总结,这篇博客用FPGA的状态机的概念,做了一个自动售货机,并详细介绍了各个模块的功能及代码,仅供参考。

基于FPGA状态机的自动售货机功能实现相关推荐

  1. FPGA系统性学习笔记连载_Day15【状态机、自动售货机】 【原理及verilog仿真】篇

    FPGA系统性学习笔记连载_Day15[状态机.自动售货机] [原理及verilog仿真]篇 本系列为FPGA系统性学习学员学习笔记整理分享,如有学习或者购买开发板意向,可加交流群联系群主. 连载&l ...

  2. 基于verlog的简单自动售货机设计

    课程设计:基于verlog的简单自动售货机设计 1.设计目的: (1)了解DE2-70开发板的硬件构成: (2)熟悉开发板可用资源的硬件电路: (3)掌握EDA开发流程: (4)熟悉Quartus I ...

  3. 基于AT89C51单片机的自动售货机系统设计(附仿真+C程序+原理图+论文等)

    注意:获取全套设计,请见文末说明- 概述 本文设计了一款以AT89C51单片机为核心的自动售货机系统,并且着重详细地介绍了自动售货机的整体系统设计方案.硬件选择基础.软件使用方法及技巧.以AT89C5 ...

  4. 自动售货机 顺序图_基于UML的饮料自动售货机系统设计

    基于 UML 的饮料自动售货机系统设计 1 . 问题描述 1.1 关于自动售货机 自动售货机像磁卡电话.银行柜员机一样,以方便.新颖.文明.昼夜服务等特点, 成为发达国 家不可缺少的便民配套设施.如今 ...

  5. 连载《叁芯智能fpga设计与研发-第15天》 【状态机、自动售货机】 【原理及verilog仿真】

    一.状态机基本概念 状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调 相关信号动作.完成特定操作的控制中心.有限状态机简写为FSM(Finite State ...

  6. 基于51单片机的自动售货机系统设计

    目录 一.自动售货机的控制子系统概述 二.自动售货机的功能简介 1 自动售货机的功能概述 2 自动售货机的设计思路 三.自动售货机的硬件设计 1. 80C51的简介 (1) 80C51的基本概述 (2 ...

  7. 基于AM5728 DSP+ARM自动售货机智能控制单元

    自动售货机智能控制单元 信迈推出的自动售货机控制单元是一款集自动售货机的控制.通讯与显示等功能于一体的嵌入式一体化产品.使用本 控制单元可以帮助您快速搭建出自动售货机的成套方案.   快速搭建 ,不应 ...

  8. 状态机——饮料自动售货机

    一. 状态模式概述 1.1 什么是状态模式 状态模式是在不同状态下,执行相同的方法,具有不同的实现方式.而每个不同的状态会被封装为一个类,这个类实现了不同状态间共同的方法,只是方法的实现方式各不相同. ...

  9. 基于51单片机的自动售货机Proteus仿真(源码+仿真+设计报告)

    资料编号:137 视频讲解: 137-基于51单片机的自动售货机Proteus仿真(源码+仿真+设计报告) 功能介绍: 基本原理:通过矩阵键盘来选择货物的种类与数量过后自动售货机提示投币.自动售货机的 ...

最新文章

  1. sqlserver 获取当前年_CVE-2020-0618: 微软 SQL Server 远程代码执行漏洞通告
  2. LeetCode 6 Z 字形变换
  3. dnscat2搭建dns隧道
  4. 洛谷P4762: [CERC2014]Virus synthesis(PAM)
  5. 【转】Dynamics 365Online 如何启用手机端APP的离线功能
  6. 有关单元测试的 5 个建议
  7. vue项目打包部署到Tomcat上,一刷新就报错404
  8. 《光剑文集》春心沁透: 99首
  9. excel合并两列内容_比Excel公式快10倍,史上最牛合并表格工具来了!!
  10. 也许黎曼猜想是错误的
  11. Ogre 3DMax导出插件的制作
  12. 北京跑步入夏--妞妞跑步长大
  13. QRCode.js:使用 JavaScript 生成二维码
  14. 苟富贵倒萨忽然他确实
  15. IMPL1. all_fanin/all_fanout命令解析
  16. 机电和计算机专业怎么选,计算机专业怎么选城口_竟成学校
  17. 对称加密 非对称加密
  18. 脚注交叉引用序号不一样_不为人知的Word交叉引用设置
  19. 2019 NIPS | Variational graph recurrent neural network
  20. 如何看待区块链游戏,避免陷入区块链游戏骗局

热门文章

  1. 浅析Flash游戏架构
  2. 创建了steam服务器无响应,steam打不开没反应怎么办_steam打不开没反应解决方法 - 系统家园...
  3. 送给她超浪漫的表白信——她感动哭了(.html)
  4. 解决冲突(避免冲突)
  5. 博基计划(5)---模型交叉验证方法讨论
  6. 匿名信V1.4.5.1版本更新“数据大屏”功能
  7. 面对前端六年历史代码,如何接入并应用ES6解放开发效率
  8. ThreadLocal作用、原理以及问题
  9. 【Docker】安装Docker以及配置阿里云Docker镜像仓库
  10. C++ std::string 转换为 UTF-8 编码