標(biāo)題: FPGA自動(dòng)售貨機(jī)設(shè)計(jì) 僅供交流 [打印本頁]

作者: dgsggpga    時(shí)間: 2020-7-3 15:42
標(biāo)題: FPGA自動(dòng)售貨機(jī)設(shè)計(jì) 僅供交流
本帖最后由 dgsggpga 于 2020-7-3 15:45 編輯

1.總體設(shè)計(jì)

采用FPGA來設(shè)計(jì)的原理圖如圖1.1所示.它由控制輸入電路、FPGA、顯示電路電路組成。



圖1.1 采用FPGA設(shè)計(jì)的自動(dòng)售貨機(jī)原理方框圖

控制輸入電路主要是為用戶設(shè)計(jì)的,起到一個(gè)輸入控制的作用。FPGA是現(xiàn)場可編程邏輯器件,也是本設(shè)計(jì)方案的核心內(nèi)容,它是實(shí)現(xiàn)自動(dòng)售貨機(jī)運(yùn)作的主要控制模塊。將編寫好的HDL程序燒制到現(xiàn)場可編程邏輯器件FPGA中,然后通過控制輸入電路把信號(hào)輸入到FPGA,由八個(gè)開關(guān)控制輸入信號(hào)即消費(fèi)者選擇商品和消費(fèi)者投幣及確認(rèn)消費(fèi),動(dòng)態(tài)數(shù)碼管顯示輸出信號(hào)即找零環(huán)節(jié)和所選擇的商品、消費(fèi)者投幣。



2、設(shè)計(jì)說明

本設(shè)計(jì)是以現(xiàn)場可編程邏輯器件(FPGA)為核心的自動(dòng)售貨機(jī),利用Modesim軟件編寫verilog硬件描述語言程序以實(shí)現(xiàn)自動(dòng)售貨功能。

1.1、系統(tǒng)設(shè)計(jì)描述

(1)用四個(gè)發(fā)光二極管分別模擬售出價(jià)值為2元、5元、7元和10元的商品,購買者可以通過開關(guān)選擇任意一種標(biāo)價(jià)中的小商品;

(2)燈亮?xí)r表示該小商品售出;

(3)用開關(guān)分別模擬1元、5元,10元和20元貨幣投入,用四支發(fā)光二極管代表投入的貨幣的面值;

(4)每次只能售出一種小商品,當(dāng)所投硬幣達(dá)到或超過購買者所選面值時(shí),售出貨物并找回剩余的硬幣,回到初始狀態(tài);

(5)當(dāng)所投硬幣值不足面值時(shí),可通過一個(gè)復(fù)位鍵退回所投硬幣,回到初始狀態(tài)。

系統(tǒng)框圖如圖1.1所示:



                        圖1.1 系統(tǒng)

3、詳細(xì)狀態(tài)描述

3.1 初始狀態(tài)

rst為復(fù)位鍵,低電平有效,實(shí)現(xiàn)系統(tǒng)復(fù)位。

3.2 選商品狀態(tài)

分別有價(jià)格為2元、5元、7元和10元的商品,每次選擇商品前,設(shè)置一個(gè)標(biāo)志位btn_sel_goods表示選擇商品狀態(tài)。此自動(dòng)售貨機(jī)每一次售貨時(shí)只能一次選擇一種商品,當(dāng)同時(shí)選擇兩種以上時(shí),選擇商品無效,數(shù)碼管顯示清零,重新進(jìn)行商品選擇。選擇商品后,數(shù)碼管顯示所選商品價(jià)格。

3.3 投幣狀態(tài)

當(dāng)選好商品后,開始投幣。同樣有一標(biāo)志位btn_price表示投幣金額。投幣口只接受面值為1元、5元10元和20元的貨幣,可以同時(shí)投入多種面值錢幣。投完幣后,先有一個(gè)確認(rèn)買商品的過程,若投了幣但又不購買商品了,就將全部投幣金額退回;若確認(rèn)購買商品,則進(jìn)入下一狀態(tài)。

3.4 找零狀態(tài)

投完幣,并確認(rèn)購買商品后,進(jìn)入找零狀態(tài)。首先要將所投的金額與所選商品的價(jià)格做比較,若所投金額小于商品價(jià)格,則退回所投錢幣;若大于等于商品價(jià)格,則兩者做差,得到需要找零的錢。



4、仿真結(jié)果分析

設(shè)置測試程序各參數(shù),運(yùn)行tb文件,仿真結(jié)果如下圖3.1、3.2所示。

圖3.1

圖3.1所示,商品價(jià)格選擇為7元,即btn_sel_goods=2'b10,投幣總額大于商品價(jià)格的情況,上圖中btn_mony從右到左依次代表投幣1元、10元、20元、10元、20元、1元、20元和10元,共92元。red燈實(shí)時(shí)顯示所投貨幣的面值。dis_price顯示為0000001_0001111,對(duì)應(yīng)數(shù)碼管顯示數(shù)字為07,即7元。 dis_mony為0000000_0100100,對(duì)應(yīng)數(shù)碼管顯示數(shù)字為85?梢钥闯觯瑢(shí)驗(yàn)結(jié)果很理想,說明代碼符合設(shè)計(jì)要求。



圖3.2

圖3.2所示,商品價(jià)格選擇為7元,即btn_sel_goods=2'b10,投幣總額小于商品價(jià)格的情況,上圖中btn_mony從右到左依次代表投幣1元、5元,共6元。red燈實(shí)時(shí)顯示所投貨幣的面值。dis_price顯示為0000001_0001111,對(duì)應(yīng)數(shù)碼管顯示數(shù)字為07,即7元。 dis_mony為0000001_0100000,對(duì)應(yīng)數(shù)碼管顯示數(shù)字為06,即6元,可以看出,實(shí)驗(yàn)結(jié)果很理想,說明代碼符合設(shè)計(jì)要求。



附錄:

/////////////////////////////////////////////////

//自動(dòng)售貨機(jī)

//btn_sel_goods 為所選商品,由于實(shí)驗(yàn)條件的限制,本實(shí)驗(yàn)中只給出4種價(jià)格的商品

//btn_ok 購買確認(rèn)鍵

//led[3:0] 客戶單次投幣幣值

//beep 客戶所投金額或購買商品后剩余金額大于所選商品價(jià)格時(shí),該燈亮,表示可以繼續(xù)購買

//led_warn 客戶所投金額或購買商品后剩余金額小于所選商品價(jià)格時(shí),該燈亮,表示不可以繼續(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ù)碼管顯示價(jià)錢

output beep;              //交易完成提醒



reg [3:0] led;

reg led_warn;//投入錢幣不夠時(shí)警告

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;     //投幣差額小于商品價(jià)格時(shí)警告

         else

           begin

            led_warn <= 1'b0;      

            beep <= 1'b1;          //所投金額大于商品價(jià)格時(shí),亮燈表示可以購買

           end





dis_mony[6:0] <= led7(price_all%10);//找零金額個(gè)位顯示

dis_mony[13:7] <= led7(price_all/10);//找零金額十位顯示

dis_price[6:0] <= led7(price%10);//商品價(jià)格個(gè)位顯示

dis_price[13:7] <= led7(price/10);//商品價(jià)格十位顯示        



         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









/////////////////////////////////////

//實(shí)現(xiàn)邊沿檢測的功能

//det為原輸入需檢測信號(hào)

//pos_edge為輸出的一個(gè)脈沖長度的上升沿信號(hào)

//

/////////////////////////////////////

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









/////////////////////////////////////

//實(shí)現(xiàn)按鍵消抖工功能

//det為原輸入信號(hào)

//key_don為輸出確認(rèn)信號(hào)

//

//CONT實(shí)現(xiàn)計(jì)數(shù),經(jīng)過CONT個(gè)脈沖的延時(shí)

//

/////////////////////////////////////

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ù)碼管顯示價(jià)錢

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






歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1