本帖最后由 dgsggpga 于 2020-7-3 15:45 編輯
1.總體設計
采用FPGA來設計的原理圖如圖1.1所示.它由控制輸入電路、FPGA、顯示電路電路組成。
圖1.1 采用FPGA設計的自動售貨機原理方框圖
控制輸入電路主要是為用戶設計的,起到一個輸入控制的作用。FPGA是現(xiàn)場可編程邏輯器件,也是本設計方案的核心內(nèi)容,它是實現(xiàn)自動售貨機運作的主要控制模塊。將編寫好的HDL程序燒制到現(xiàn)場可編程邏輯器件FPGA中,然后通過控制輸入電路把信號輸入到FPGA,由八個開關控制輸入信號即消費者選擇商品和消費者投幣及確認消費,動態(tài)數(shù)碼管顯示輸出信號即找零環(huán)節(jié)和所選擇的商品、消費者投幣。
2、設計說明
本設計是以現(xiàn)場可編程邏輯器件(FPGA)為核心的自動售貨機,利用Modesim軟件編寫verilog硬件描述語言程序以實現(xiàn)自動售貨功能。
1.1、系統(tǒng)設計描述
(1)用四個發(fā)光二極管分別模擬售出價值為2元、5元、7元和10元的商品,購買者可以通過開關選擇任意一種標價中的小商品;
(2)燈亮時表示該小商品售出;
(3)用開關分別模擬1元、5元,10元和20元貨幣投入,用四支發(fā)光二極管代表投入的貨幣的面值;
(4)每次只能售出一種小商品,當所投硬幣達到或超過購買者所選面值時,售出貨物并找回剩余的硬幣,回到初始狀態(tài);
(5)當所投硬幣值不足面值時,可通過一個復位鍵退回所投硬幣,回到初始狀態(tài)。
系統(tǒng)框圖如圖1.1所示:
圖1.1 系統(tǒng)
3、詳細狀態(tài)描述
3.1 初始狀態(tài)
rst為復位鍵,低電平有效,實現(xiàn)系統(tǒng)復位。
3.2 選商品狀態(tài)
分別有價格為2元、5元、7元和10元的商品,每次選擇商品前,設置一個標志位btn_sel_goods表示選擇商品狀態(tài)。此自動售貨機每一次售貨時只能一次選擇一種商品,當同時選擇兩種以上時,選擇商品無效,數(shù)碼管顯示清零,重新進行商品選擇。選擇商品后,數(shù)碼管顯示所選商品價格。
3.3 投幣狀態(tài)
當選好商品后,開始投幣。同樣有一標志位btn_price表示投幣金額。投幣口只接受面值為1元、5元10元和20元的貨幣,可以同時投入多種面值錢幣。投完幣后,先有一個確認買商品的過程,若投了幣但又不購買商品了,就將全部投幣金額退回;若確認購買商品,則進入下一狀態(tài)。
3.4 找零狀態(tài)
投完幣,并確認購買商品后,進入找零狀態(tài)。首先要將所投的金額與所選商品的價格做比較,若所投金額小于商品價格,則退回所投錢幣;若大于等于商品價格,則兩者做差,得到需要找零的錢。
4、仿真結(jié)果分析
設置測試程序各參數(shù),運行tb文件,仿真結(jié)果如下圖3.1、3.2所示。
圖3.1
圖3.1所示,商品價格選擇為7元,即btn_sel_goods=2'b10,投幣總額大于商品價格的情況,上圖中btn_mony從右到左依次代表投幣1元、10元、20元、10元、20元、1元、20元和10元,共92元。red燈實時顯示所投貨幣的面值。dis_price顯示為0000001_0001111,對應數(shù)碼管顯示數(shù)字為07,即7元。 dis_mony為0000000_0100100,對應數(shù)碼管顯示數(shù)字為85�?梢钥闯�,實驗結(jié)果很理想,說明代碼符合設計要求。
圖3.2
圖3.2所示,商品價格選擇為7元,即btn_sel_goods=2'b10,投幣總額小于商品價格的情況,上圖中btn_mony從右到左依次代表投幣1元、5元,共6元。red燈實時顯示所投貨幣的面值。dis_price顯示為0000001_0001111,對應數(shù)碼管顯示數(shù)字為07,即7元。 dis_mony為0000001_0100000,對應數(shù)碼管顯示數(shù)字為06,即6元,可以看出,實驗結(jié)果很理想,說明代碼符合設計要求。
附錄:
/////////////////////////////////////////////////
//自動售貨機
//btn_sel_goods 為所選商品,由于實驗條件的限制,本實驗中只給出4種價格的商品
//btn_ok 購買確認鍵
//led[3:0] 客戶單次投幣幣值
//beep 客戶所投金額或購買商品后剩余金額大于所選商品價格時,該燈亮,表示可以繼續(xù)購買
//led_warn 客戶所投金額或購買商品后剩余金額小于所選商品價格時,該燈亮,表示不可以繼續(xù)購買
//charge 找零按鍵,按下后找零
/////////////////////////////////////////////////
`timescale 1ns / 1ps
module auto_machine(rst,clk,charge,dis_mony,dis_price,
btn_ok,btn_mony,btn_sel_goods,led_warn,led,beep);
input clk,rst;
input charge,btn_ok; //找零/確定
input [3:0] btn_mony; //選擇放入的錢1元5元10元20元
input [1:0] btn_sel_goods; //選擇2元5元7元10元商品
output [3:0] led; //分別顯示投入的是1元5元10元還是20元貨幣
output led_warn; //錢不足,指示燈
output [13:0] dis_mony; //數(shù)碼管顯示投入總金額
output [13:0] dis_price; //數(shù)碼管顯示價錢
output beep; //交易完成提醒
reg [3:0] led;
reg led_warn;//投入錢幣不夠時警告
reg [13:0] dis_mony;
reg [13:0] dis_price;
reg beep;
parameter S2=2'b00,S5=2'b01,S7=2'b10,S10=2'b11;
parameter M1=4'b0001,M5=4'b0010,M10=4'b0100,M20=4'b1000;
wire[3:0] btn_mony_buf0;
wire[3:0] btn_mony_buf1;
wire btn_ok_b0;
wire btn_ok_b1;
wire[1:0] btn_sel_goods_b;
wire charge_buf;
reg [6:0] price,price_all;
key_down uut4(.rst(rst),.clk(clk),.det(btn_mony[0]),.key_don(btn_mony_buf0[0]));
key_down uut5(.rst(rst),.clk(clk),.det(btn_mony[1]),.key_don(btn_mony_buf0[1]));
key_down uut6(.rst(rst),.clk(clk),.det(btn_mony[2]),.key_don(btn_mony_buf0[2]));
key_down uut7(.rst(rst),.clk(clk),.det(btn_mony[3]),.key_don(btn_mony_buf0[3]));
edge_det uut0(.rst(rst),.clk(clk),.det(btn_mony_buf0[0]),.pos_edge(btn_mony_buf1[0]));
edge_det uut1(.rst(rst),.clk(clk),.det(btn_mony_buf0[1]),.pos_edge(btn_mony_buf1[1]));
edge_det uut2(.rst(rst),.clk(clk),.det(btn_mony_buf0[2]),.pos_edge(btn_mony_buf1[2]));
edge_det uut3(.rst(rst),.clk(clk),.det(btn_mony_buf0[3]),.pos_edge(btn_mony_buf1[3]));
key_down uut8(.rst(rst),.clk(clk),.det(btn_ok),.key_don(btn_ok_b0));
edge_det uut9(.rst(rst),.clk(clk),.det(btn_ok_b0),.pos_edge(btn_ok_b1));
key_down uut10(.rst(rst),.clk(clk),.det(btn_sel_goods[0]),.key_don(btn_sel_goods_b[0]));
key_down uut11(.rst(rst),.clk(clk),.det(btn_sel_goods[1]),.key_don(btn_sel_goods_b[1]));
key_down uut12(.rst(rst),.clk(clk),.det(charge),.key_don(charge_buf));
always @(negedge rst or posedge clk)
begin
if(!rst)
begin
led <= 4'b0;
led_warn <=1'b0;
beep <=1'b0;
price_all =7'd0;
price <= 7'd0;
dis_mony <=14'h3fff;
dis_price <=14'h3fff;
end
else
begin
case(btn_mony_buf1)
M1: //所投錢幣+1
price_all =price_all + 7'd1;
M5: //所投錢幣+5
price_all =price_all + 7'd5;
M10: //所投錢幣+10
price_all =price_all+ 7'd10;
M20: //所投錢幣+20
price_all =price_all + 7'd20;
default: led <= 4'b0;
endcase
case(btn_mony)
M1: //顯示所投錢幣幣值
led <= M1;
M5:
led <= M5;
M10:
led <= M10;
M20:
led <= M20;
default:
led <= 4'b0;
endcase
case(btn_sel_goods_b)
S2:begin price <= 7'd2;
end
S5:begin price <= 7'd5;
end
S7:begin price <= 7'd7;
end
S10:begin price <= 7'd10;
end
default:begin price <= 7'd0;
end
endcase
if(!charge_buf)
price_all = 7'd0; //退回零錢
else
begin
if(btn_ok_b1)
begin
if(price_all < price)
led_warn = 1'b1;
else
price_all = price_all-price;
end
else
begin
led_warn <= 1'b0;
beep <= 1'b0;
end
end
if(price_all<price)
led_warn <= 1'b1; //投幣差額小于商品價格時警告
else
begin
led_warn <= 1'b0;
beep <= 1'b1; //所投金額大于商品價格時,亮燈表示可以購買
end
dis_mony[6:0] <= led7(price_all%10);//找零金額個位顯示
dis_mony[13:7] <= led7(price_all/10);//找零金額十位顯示
dis_price[6:0] <= led7(price%10);//商品價格個位顯示
dis_price[13:7] <= led7(price/10);//商品價格十位顯示
end
end
/*數(shù)碼管段碼表*/
function [6:0] led7;
input [6:0] dis_input;
begin
case (dis_input)
0 : led7 = 7'b1000000;
1 : led7 = 7'b1111001;
2 : led7 = 7'b0100100;
3 : led7 = 7'b0110000;
4 : led7 = 7'b0011001;
5 : led7 = 7'b0010010;
6 : led7 = 7'b0000011;
7 : led7 = 7'b1111000;
8 : led7 = 7'b0000000;
9 : led7 = 7'b0011000;
default : led7 = 7'b111_1111;
endcase
end
endfunction
endmodule
/////////////////////////////////////
//實現(xiàn)邊沿檢測的功能
//det為原輸入需檢測信號
//pos_edge為輸出的一個脈沖長度的上升沿信號
//
/////////////////////////////////////
module edge_det(rst,clk,det,pos_edge);
input rst,clk;
input det;
output pos_edge;
wire pos_edge;
reg p_edge1;
reg p_edge2;
assign pos_edge = (!p_edge1 & p_edge2);
always @(negedge rst or posedge clk)
begin
if (!rst)
begin
p_edge1<=1'b0;
p_edge2<=1'b0;
end
else
begin
p_edge1<= det;
p_edge2<=p_edge1;
end
end
endmodule
/////////////////////////////////////
//實現(xiàn)按鍵消抖工功能
//det為原輸入信號
//key_don為輸出確認信號
//
//CONT實現(xiàn)計數(shù),經(jīng)過CONT個脈沖的延時
//
/////////////////////////////////////
module key_down(rst,clk,det,key_don);
input rst,clk;
input det; //
output key_don; //
reg p_edge1;
reg p_edge2;
reg[24:0] cont;
parameter CONT = 25'd050;
assign key_don = (det & p_edge1 & p_edge2);
always @(negedge rst or posedge clk)
begin
if (!rst)
begin
p_edge1<=1'b0;
p_edge2<=1'b0;
cont<=25'b0;
end
else
begin
if(cont==CONT)
begin
cont<=0;
p_edge1 <= det;
p_edge2 <=p_edge1;
end
else
cont<=cont+1'b1;
end
end
endmodule
///////////////////////////////////////////////////////////////////////
//tb文件
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module tb_mb;
reg clk,rst,btn_ok;
reg [3:0] btn_mony; //選擇放入的錢1元5元10元20元
reg [1:0] btn_sel_goods; //選擇商品2、5、7、10元
wire [3:0] led; //led_5,led_10,led_15,led_20
wire led_warn; //錢不足,指示燈
wire [6:0] dis_mony; //數(shù)碼管顯示投入面值
wire [6:0] dis_price; //數(shù)碼管顯示價錢
wire beep;
auto_machine uut(.clk,.rst,.dis_mony,.dis_price,
.btn_ok,.btn_mony,.btn_sel_goods,
.led_warn,.led,.beep);
initial begin
clk = 1'b0;
rst = 1'b0;
btn_ok=1'b0;
#20 rst=1;
#10 btn_sel_goods=2'b10;
#20 btn_mony=4'b0001;
#30 btn_mony=4'b0100;
#50 btn_mony=4'b0010;
#100 btn_ok=1'b1;
end
always #2 clk=~clk;
endmodule
|