1. 程式人生 > >使用Verilog實現FPGA雙列電梯控制系統

使用Verilog實現FPGA雙列電梯控制系統

設計目的及要求

實現28層電梯升降控制設計,該設計模擬完成8層樓的載客服務,同時示電梯執行情況和電梯外請求資訊,具體要求如下:

1)       每層電梯設有請求開關,電梯可響應按鍵操作,到達指定樓層;

2)       當有請求時,該樓層的指示燈亮;

3)       電梯執行時,各樓層有執行模式指示,顯示目前電梯是上升或下降。

4)       

各樓層均有電梯樓層顯示,告知等待者電梯當前處於哪一層樓;

5)       響應動作完成後,即電梯到達該樓層後該樓層的指示燈滅,完成一次響應操作。

6)       可以通過相關顯示模組提示升降資訊。

 

總體設計思路

根據系統設計要求,並考慮到系統的可檢驗性,結合實際情況,雙列電梯控制的相對於單列電梯控制的主要區別也是設計難點在於兩列電梯的相互配合,在多個請求觸發的情況下能夠儘可能快的完成響應,減少乘客等待時間。針對這一設計需求,對雙列電梯做了主從電梯區分,融合優先順序響應控制的方法,完成電梯的自主判斷。

 

3硬體設計思路

3.1電源電路 

改電源電路是給按鍵電路供電電路,輸出為3.3V。

1 電源電路

 

3.2按鍵電路

根據設計需要,本設計硬體電路一共包含16個外接按鍵,分別是一棟八層的電梯內建樓層選擇按鍵KEY[108...101];二棟八層的電梯內建樓層選擇按鍵KEY[208...201];通過上拉電阻接入3.3V電壓,晶片引腳檢測到按鍵低電平有效。設計原理圖如圖2

3.3指示燈電路

根據設計需要,本設計硬體電路一共包含20個外接LED燈,分別是一棟八層的電梯外部樓層響應指示燈LED[1_8...1_1];二棟八層的電梯外部樓層響應指示燈

LED[2_8...2_1];電梯上行指示燈兩個,和電梯下行指示燈兩個。通過查閱EP2C8Q208C8N開發板晶片手冊,晶片引腳輸出電壓達到3.3V,輸出電流為20mA,所以可以直接給LED高電平來點亮LED。設計原理圖如圖3

2 按鍵電路                                                                                 3 指示燈電路

4 硬體實物圖


軟體設計分析

4.1程式框圖

1. 按鍵掃描,當有鍵按下時,先判斷主電梯繁忙標誌位,從而選擇電梯工作。

2. 判斷上升、下降標誌位,根據情況控制流水燈移位方向,指示燈亮滅,及數碼管顯示樓層。

3. 當目標樓層等於當前樓層時,標誌位都清零,流水燈停止移位,開始閃爍,指示燈全滅,數碼管顯示當前樓層。

5 程式流程圖

4.2介面引數

@param(in)rst(復位訊號),CLOCK(基礎時鐘訊號),key(按鍵訊號輸入);

@param(out)DIG(段選訊號),SEL(位選訊號),

         LED1(一棟指示燈),LED2(二棟指示燈),

         BUZZER(蜂鳴器輸出訊號);

         sign_up(一棟電梯上行訊號),sign_down(一棟電梯下行訊號),

         sign_up2(一棟電梯上行訊號),sign_down2(一棟電梯下行訊號);

4.3部分程式碼


4.3.1主程式

/***********************************************/
/*                雙列八層電梯設計           
/*  實現功能:                           
/*      %每層電梯設有請求開關,按鍵到達指定樓層 
/*      %當有請求時,指定樓層燈亮             
/*      %電梯執行時,各樓層有執行狀態指示      
/*      %各樓層均有電梯樓層顯示               
/*      %電梯到達樓層後,該樓層指示燈滅        
/***********************************************/
module elevator_sun(rst,CLOCK,key,
                    DIG,SEL,LED1,LED2,
                    BUZZER,
                    sign_up,sign_down,sign_up2,sign_down2
                    );
	input rst;                 //復位訊號
	input CLOCK;               //時鐘訊號
    input [23:0]key;
    
    output [7:0]LED1;          //指示燈訊號
    output [7:0]LED2;          //指示燈訊號
	output [7:0]SEL;           //位選訊號
	output [6:0]DIG;           //段選訊號
    output BUZZER;
    output sign_up,sign_down;
    output sign_up2,sign_down2;
	
    wire count_clk;            //分頻新時鐘
    wire c_clk;		           //掃描時鐘
	wire [3:0]data;            //計數傳遞暫存器
    wire [3:0]level;           //計數傳遞暫存器
    wire [3:0]level2;          //計數傳遞暫存器
    wire [3:0]number;          //計數傳遞暫存器
    wire [3:0]number2;         //計數傳遞暫存器

    
	parameter N_1S=10000,N_SCAN=10000000;
                //N_1S 秒分頻係數,分出週期為一秒的時鐘訊號
                //N_SCAN 掃描分頻係數,分出數碼管掃描的時鐘訊號
                
	clock #(N_1S) a1(CLOCK,rst,count_clk);                                                       //呼叫分頻器,一秒時鐘訊號
    clock #(N_SCAN) a2(CLOCK,rst,c_clk);                                                         //呼叫分頻器,掃描時鐘訊號
	display a3(number,number2,count_clk,DIG,SEL);                                                //呼叫數碼管顯示函式
    key_test a4(CLOCK,c_clk,rst,key,level,sign_up,sign_down,level2,sign_up2,sign_down2);         //呼叫按鍵預置函式
    control a5(c_clk,level,LED1,number,sign_up,sign_down);                                       //呼叫樓層控制函式
    control a6(c_clk,level2,LED2,number2,sign_up2,sign_down2);                                   //呼叫樓層控制函式
endmodule

4.3.2分頻器

module clock(CLOCK,rst,out_clock);
    parameter flag;          //計數標誌
	input CLOCK;             //時鐘訊號
	input rst;               //復位訊號
	output out_clock;        //時鐘輸出
	reg [30:0] count=0;      //計數暫存器 
	reg out_clock_reg=0;     //時鐘輸出暫存器
   
	
	assign out_clock = out_clock_reg;    //連結時鐘訊號
	
	[email protected](posedge CLOCK or negedge rst)
	begin
	
		if(!rst)
			begin
				count<=0;
				out_clock_reg<=0;
			end
		else
			begin
				count<=count+1'b1;
			if(count==flag)                         //當時鍾暫存器數值等於計數標誌
				begin
					out_clock_reg<=~out_clock_reg;  //時鐘輸出電平反轉
					count<=0;
				end
			end

	end
Endmodule

4.3.3顯示

module display(in,in2,c_clk,DIG,SEL);
	input [3:0] in;          //樓層1輸入
    input [3:0] in2;         //樓層2輸入
	input c_clk;             //掃描時鐘
	output [7:0] SEL;        //位選訊號
	output [6:0] DIG;        //段選訊號
    
	reg [7:0] SEL_R;         //位選訊號暫存器
	reg [6:0] DIG;           //段選訊號暫存器
    reg [3:0] nature;        //顯示數字暫存器
	
	assign SEL = SEL_R;      //連結位選訊號

    reg [2:0]count=0;             //計數暫存器賦初值
			
	[email protected](posedge c_clk)   //產生掃描訊號
		begin
			count<=count+1'b1;
		end
		
	[email protected](count)
		begin
			case(count)
				//0:begin nature<=10;  SEL_R<=8'b1111_1110; end
                1:begin nature<=in; SEL_R<=8'b1111_1101; end
                2:begin nature<=9;  SEL_R<=8'b1111_1011; end
                //3:begin nature<=0; SEL_R<=8'b1111_0111; end
                //4:begin nature<=10;  SEL_R<=8'b1110_1111; end
				5:begin nature<=in2;SEL_R<=8'b1101_1111; end
                6:begin nature<=9;  SEL_R<=8'b1011_1111; end
                //7:begin nature<=0; SEL_R<=8'b0111_1111; end
			endcase
		end
     
	[email protected](nature)
		begin                //數碼管顯示數碼
			case(nature)
				0:DIG=7'b1001_110;//(
                1:DIG=7'b1111_001;//1
				2:DIG=7'b0100_100;//2
				3:DIG=7'b0110_000;//3
				4:DIG=7'b0011_001;//4
				5:DIG=7'b0010_010;//5
				6:DIG=7'b0000_010;//6
				7:DIG=7'b1111_000;//7
				8:DIG=7'b0000_000;//8
				9:DIG=7'b0001_110;//F
                10:DIG=7'b1110_001;//)
			endcase
		end
		
Endmodule

4.3.4按鍵

含按鍵消抖及busy標誌位判斷,選擇賦值

module key_test(CLOCK,c_clk,rst,key,level,sign_up,sign_down,level2,sign_up2,sign_down2);
    input CLOCK,c_clk,rst;
    input [23:0]key;
    input sign_up,sign_down;
    input sign_up2,sign_down2;
    	
    output reg[3:0] level = 1;
    output reg[3:0] level2 = 1;
    
    reg busy;
    reg busy2;
    reg [3:0]state;  //狀態暫存器
    reg [3:0]keyr;

    wire key1;
    wire key_neg = ~keyr[2] & keyr[3];                                                          //有按鍵按下
    wire key_pos = keyr[2] & ~keyr[3];                                                          //有按鍵釋放 
    assign key1 =   !key[23]&!key[22]&!key[21]&!key[20]&!key[19]&!key[18]&!key[17]&!key[16]&
                    !key[15]&!key[14]&!key[13]&!key[12]&!key[11]&!key[10]&!key[9]&!key[8]&
                    !key[7]&!key[6]&!key[5]&!key[4]&!key[3]&!key[2]&!key[1]&!key[0];            //所有按鍵相與判斷是否有按鍵觸發
    
    always @ (posedge CLOCK or negedge rst)
        if(!rst) keyr <= 3'b111;
        else keyr <= {keyr[2:0],key1};
    
    //定時計數邏輯,對按鍵消抖判斷
    reg[19:0] cnt;
	//定時計數器
    always @ (posedge CLOCK or negedge rst )
        if(!rst) cnt <= 20'd0;
        else if(key_neg || key_pos) cnt <= 20'd0;
        else if(cnt < 20'd999_999) cnt <= cnt + 1'b1;
        else cnt <= 20'd0;
	
    //定時採集按鍵值
    reg [23:0] key_v [1:0];
    always @ (posedge CLOCK or negedge rst)
        if (!rst) begin
            key_v[0] <= 24'b1111_1111_1111_1111_1111_1111;
            key_v[1] <= 24'b1111_1111_1111_1111_1111_1111;
        end
        else begin 
            key_v[1] <= key_v[0];		
            if(cnt == 20'd999_999) key_v[0] <= key;	//定時鍵值採集
            else key_v[0] <= key_v[0];	
        end    
    wire [23:0] key_out = key_v[1] & ~key_v[0];  //消抖後按鍵變化值
        
    always @ (posedge CLOCK or negedge rst )
        if (!rst) busy = 0;
        else if(!(sign_up||sign_down))  busy = 0;
        else busy =1;
    
    always @ (posedge CLOCK or negedge rst )
        if (!rst) busy2 = 0;
        else if(!(sign_up2||sign_down2))  busy2 = 0;
        else busy2 =1;    
        
    always @ (posedge CLOCK)    //樓層請求
    begin
        if (!rst) 
            begin 
                level <= 1;
                level2 <= 1; 
            end
        else if(key_out[0])
            begin
                if(busy==0) level<=1;
                else if((busy2==0)&&(busy==1)) level2<=1;
            end
        else if(key_out[1]) 
            begin 
                if(busy==0) level<=2;
                else if((busy2==0)&&(busy==1)) level2<=2;
            end
        else if(key_out[2]) 
            begin 
                if(busy==0) level<=3;
                else if((busy2==0)&&(busy==1)) level2<=3;                	
            end
        else if(key_out[3]) 
            begin 
                if(busy==0) level<=4;
                else if((busy2==0)&&(busy==1)) level2<=4;
            end
        else if(key_out[4]) 
            begin 
                if(busy==0) level<=5;
                else if((busy2==0)&&(busy==1)) level2<=5;
            end
        else if(key_out[5]) 
            begin 
                if(busy==0) level<=6;
                else if((busy2==0)&&(busy==1)) level2<=6;
            end
        else if(key_out[6]) 
            begin 
                if(busy==0) level<=7;
                else if((busy2==0)&&(busy==1)) level2<=7;
            end
        else if(key_out[7]) 
            begin 
                if(busy==0) level<=8;
                else if((busy2==0)&&(busy==1)) level2<=8;
            end
    end    
Endmodule

4.3.5樓層控制

比較目標樓層與當前樓層,控制顯示外設的工作。

module control(c_clk,number_new,
                LED,number_old,sign_up,sign_down);
    input c_clk;
    input [3:0]number_new;
    output [7:0] LED;
    output number_old;
    output sign_up,sign_down;
    reg [3:0]number_old=1;
    reg [7:0]LED_reg=8'b0000_0001;
    reg sign_up_reg = 0;
    reg sign_down_reg = 0; 
    assign LED = LED_reg;
    assign sign_up = sign_up_reg;
    assign sign_down = sign_down_reg;
    
    [email protected](negedge c_clk)
        begin
            if(number_new>number_old)
                begin
                    sign_up_reg<=1;
                    sign_down_reg<=0;
                    LED_reg <= LED_reg << 1'b1;
                    number_old<=number_old+'b1;
                end
            else if(number_new<number_old)
                begin
                    sign_up_reg<=0;
                    sign_down_reg<=1;
                    LED_reg <= LED_reg >> 1'b1;
                    number_old<=number_old-1'b1;
                end
            else
                begin
                    sign_up_reg<=0;
                    sign_down_reg<=0; 
                    LED_reg[number_new-1] <= ~LED_reg[number_new-1]; 
                end
        end
endmodule

5設計結果與分析

      此雙列電梯能根據電梯運作情況來選擇電梯響應,有流水燈顯示、指示燈顯示及數碼管顯示來標明電梯工作情況,兩列電梯共用一套按鍵,節省硬體,更加智慧。

        不足之處:

1.       未能實現電梯運作工程中對同一方向需求的按鍵判斷;

2.       兩電梯都空閒時,未能根據時間最短原則選擇電梯響應請求。

 

6 實際執行圖