設計目的及要求
實現2個8層電梯升降控制設計,該設計模擬完成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; //鏈接時鐘信號
always@(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; //計數寄存器賦初值
always@(posedge c_clk) //產生掃描信號
begin
count<=count+1'b1;
end
always@(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
always@(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;
always@(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 實際運行圖