设计目的及要求
实现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 实际运行图