赞
踩
先陈述下本次设计实现的功能:用FPGA实现了自动贩卖机。首先可以通过拨码开关选择货物,货物价格有三种,分别为2元,2.5元,3元,然后还是通过拨码开关,输入投币金额,面额为0.5元,1元,2元。当投币金额小于货物价格时,数码管显示所投金额,当投币金额大于货物价格时,数码显示找零的金额,同时蜂鸣器报警。
先给张实物图:
接下来介绍设计的思路。本次开发板是基于EP4CE6E22C8N的Cyclone IV系列的FPGA、(型号)的FLASH芯片和50MHz的晶振,通过对板子的元器件进行控制,从而实现特定功能。拨动开关的管脚配置和电路原图如下:
从图中可以看出,当拨码开关拨上时,管脚电平为1。所以可以根据检测电平变换,来决定货物的价格。 本次代码的接口定义如下:
其中三位宽的chose用于选择货物价格。选择价格的代码如下:
接下来,程序执行的核心是一个二段式状态机。状态机代码如下:
状态机执行流程:首先s0状态是输入投币金额,用三个变量分别保存并且记录输入的金额,最后用一个加法式子算出总的投币金额
s1状态是判断所投金额有没有大于货物价格,如果没有大于货物价格,那么继续回到s0状态,继续进行投币。如果所投金额大于货物价格,那么就执行到s2状态。
s2状态,主要执行蜂鸣器响的操作,然后在数码管上显示出找零的金额。
在本模块调用了数码管显示模块,将要显示的数据(货物价格、投币金额/找零金额)显示在数码管上。
在这个模块,取出要显示数据的各个位。举个例子,要显示的货物价格是25(2.5元),那么首先取出十位数字2,再取出个位数字5。将数字传递给显示模块,接下来的任务就是显示模块显示数据了。
显示模块的代码:
- module seg(
- input sys_clk,sys_rest,
- input [15:0] data,
- output reg [3:0] sel,
- output reg [6:0] seg_led
- );
-
- parameter CLK_NUM=4'd10;
- parameter MSNUM=14'd5000;
- reg [3:0] CNT_NUM;
- reg CLK;
-
- reg [12:0] MSCNT;
- reg MS_flag;
- reg [3:0] num_display;
-
- reg [15:0] num;
- reg [2:0] sel_num; //选择哪一位数码管被点亮
- //wire define
- wire [3:0] data0 ; // 个位数
- wire [3:0] data1 ; // 十位数
- wire [3:0] data2 ; // 百位数
- wire [3:0] data3 ; // 千位数
-
-
- //提取显示数值所对应的十进制数的各个位
- assign data0 = data[3:0]; // 个位数
- assign data1 = data[7:4]; // 十位数
- assign data2 = data[11:8]; // 百位数
- assign data3 = data[15:12]; // 千位数
-
-
- always @(posedge sys_clk or negedge sys_rest) begin
- if(!sys_rest)
- begin
- CNT_NUM<=4'd0;
- CLK<=1'd1;
- end
- else if(CNT_NUM<=CLK_NUM/2-1'b1)
- begin
- CLK<=~CLK;
- CNT_NUM<=4'd0;
- end
- else
- begin
- CNT_NUM<=CNT_NUM+1;
- CLK<=CLK;
- end
- end
-
- always @(posedge CLK or negedge sys_rest) begin
- if(!sys_rest)
- num<=16'd0;
- else
- begin
- num[15:12] <= data3; //则依次给4位数码管赋值
- num[11:8] <= data2;
- num[ 7:4] <= data1;
- num[ 3:0] <= data0;
- end
- end
- always @(posedge CLK or negedge sys_rest) begin //产生1ms脉冲
- if(!sys_rest)
- begin
- MSCNT<=13'd0;
- MS_flag<=1'b0;
- end
- else if(MSCNT==MSNUM-1)
- begin
- MSCNT<=13'd0;
- MS_flag<=1'b1;
- end
- else
- begin
- MSCNT<=MSCNT+1;
- MS_flag<=1'b0;
- end
- end
-
-
- always @(posedge CLK or negedge sys_rest) begin
- if(!sys_rest)
- sel_num<=0;
- else if(MS_flag)
- begin
- if(sel_num<3'd3)
- sel_num<=sel_num+1;
- else
- sel_num<=0;
- end
- else
- sel_num<=sel_num;
- end
- always @(posedge CLK or negedge sys_rest) begin
- if(!sys_rest)
- sel<=4'b1111;
- else
- begin
- case(sel_num)
- 3'd0: begin
- sel<= 4'b1110; //显示数码管最低位
- num_display<=num[3:0];
- end
- 3'd1: begin
- sel<= 4'b1101; //显示数码管第1位
- num_display<=num[7:4];
- end
- 3'd2: begin
- sel<= 4'b1011; //显示数码管第2位
- num_display<=num[11:8];
- end
- 3'd3: begin
- sel<= 4'b0111; //显示数码管第3位
- num_display<=num[15:12];
- end
- default sel<= 4'b1111;
- endcase
- end
- end
- always @(posedge CLK or negedge sys_rest) begin
- if(!sys_rest)
- seg_led<=7'b100000;
- else
- begin
- case(num_display)
- 4'h0 : seg_led <= 7'b1000000;
- 4'h1 : seg_led <= 7'b1111001;
- 4'h2 : seg_led <= 7'b0100100;
- 4'h3 : seg_led <= 7'b0110000;
- 4'h4 : seg_led <= 7'b0011001;
- 4'h5 : seg_led <= 7'b0010010;
- 4'h6 : seg_led <= 7'b0000010;
- 4'h7 : seg_led <= 7'b1111000;
- 4'h8 : seg_led <= 7'b0000000;
- 4'h9 : seg_led <= 7'b0010000;
- 4'd10: seg_led <= 7'b1111111; //不显示任何字符
- default : seg_led <= 7'b1000000;
- endcase
- end
- end
- endmodule
这样就大功告成啦。后续会给出完整工程项目!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。