将电梯分为两个模块,一个为上升的模块,一个为下降的模块,通过电梯的方向来判断。设置电梯方向判断模块,用来通过对当前的位置和按键信息来判断电梯方向的。之后还要设置矛盾状态,在电梯上的时候,按了向下的方向键,在电梯下的时候按了电梯向上的方向键。之后还需要一个按键暂存的模块。系统设计结构图如下所示。其中按键模块1是处理按键下行模块与电梯向上运行方向发生冲突时的控制模块,按键模块2是处理按键上行模块与电梯向下运行方向发生冲突时的控制模块。
代码:
module _z(clk,res,int,wz_led,ou,dt_fx,led);
parameter led1 = 8'b01100000, led2 = 8'b11011010, led3 = 8'b11110010; //led123
input clk,res;
input [3:0]int; //输入的按键值
output reg [2:0]wz_led; //外部电梯位置灯
output reg [7:0]led; //7段数码管
reg [3:0]in; //按键暂存值
reg flag1,flag2; //矛盾信号
reg [7:0] led_reg [2:0]; //数码管译码寄存器
output reg [3:0]ou; //按键灯
reg [2:0]in1,in2; //下行的按键和上行的按键
output reg dt_fx; //电梯方向
reg [1:0]wz; //电梯位置
integer j;
reg[4:0]kai,sx; //开门计数,
initial //将灯值存入存储器
begin
led_reg[0] = led1; led_reg[1] = led2; led_reg[2] = led3;
end
always @(posedge clk or negedge res) //总模块
begin
if(!res)
begin
wz = 0;
in = 0; ou = 0;
in1 = 0; in2 = 0;
end
else
begin
//按键状态暂存
for(j = 0;j < 4;j = j + 1)
if(int[j] == 0 && in[j] != 1) in[j] = 1;
else if(in[j] != 1) in[j] = 0;
//设置矛盾状态
//矛盾1 当电梯方向为上时, 按了下的按钮
if((wz == 0 && in == 4) || (wz == 1 && in == 4)) flag1 = 1;
else flag1 = 0;
//矛盾1 当电梯方向为下时, 按了上的按钮
if((wz == 2 && in == 2) || (wz == 1 && in == 2)) flag2 = 1;
else flag2 = 0;
//分模块运行 in1 为电梯下模块参数;in2 为电梯上模块参数
in1 = {in[3],in[2],in[0]};
in2 = {in[3],in[1],in[0]};
//如果电梯方向为下
if(dt_fx == 0)
begin
if(in1[wz] == 1) //当楼层有按,执行开门动作
begin
if(kai == 16)
begin
kai = 0; sx = 0; in1[wz] = 0;
in = {in1[2]&in2[2],in1[1],in2[1],in1[0]&in2[0]};
end
else kai = kai + 1;
end
else if(wz != 0 && in1[wz-1] == 1) //当楼层不为0时,下一层有人按,即下一楼
begin
if(sx == 22)
begin
sx = 0; wz = wz - 1;
end
else sx = sx + 1;
end
else if(wz == 2 && in1[0] == 1) //当楼层在三楼,一楼有人按,即跳到1楼,不在2楼停留
begin
if(sx == 31)
begin
sx = 0; wz = 0;
end
else sx = sx + 1;
end
else if(wz == 0 && flag1 == 1) //矛盾1状态 其一 在一楼电梯为上时按了下,电梯方向改为下,进入此模块运行此程序
begin
if(sx == 22)
begin
sx = 0;
wz = 1;
end
else sx = sx + 1;
end
end
//如果电梯方向为上
if(dt_fx == 1)
begin
if(in2[wz] == 1) //当楼层有按,执行开门动作
begin
if(kai == 16)
begin
kai = 0; sx = 0; in2[wz] = 0;
in = {in1[2]&in2[2],in1[1],in2[1],in1[0]&in2[0]};
end
else kai = kai + 1;
end
else if(wz != 2 && in2[wz+1] == 1)//如果电梯不在3楼,电梯上一楼有人按,即
begin
if(sx == 22)
begin
sx = 0; wz = wz + 1;
end
else sx = sx + 1;
end
else if(wz == 0 && in2[2] == 1) //电梯在一楼,有人在电梯三楼按
if(sx == 31)
begin
sx = 0; wz = 2;
end
else sx = sx + 1;
else if(wz == 2 && flag2 == 1) //矛盾2
if(sx == 22)
begin
sx = 0; wz = 1;
end
else sx = sx + 1;
end
ou = in;
end
end
always @(wz or in) //电梯方向判断
begin
if(wz == 2) dt_fx = 0;//在三楼时,电梯方向为下
if(wz == 0) dt_fx = 1; //在一楼时电梯方向为上
if(flag1 == 1) dt_fx = 0;//如果电梯处于矛盾1 状态 电梯为下
if(flag2 == 1) dt_fx = 1; //如果电梯处于矛盾2状态 电梯为上
if(wz == 1 && in == 1) dt_fx = 0; //如果电梯在2楼,只有一楼按了,电梯方向为下
if(wz == 1 && in == 8) dt_fx = 1; //如果电梯在2楼,只有三楼按了,电梯方向为上
end
always @(wz) //数码显示管输出 与 电梯位置灯亮
begin
for(j = 0;j < 3;j = j + 1) //循环判断电梯在哪,哪的灯就亮
if(j == wz) wz_led[j] = 1;
else wz_led[j] = 0;
led = led_reg[wz]; //数码管显示输出
end
endmodule
解释代码都贴了,这里就简单说一下吧,就是将代码分为两个模块,电梯上升和电梯下降模块,有电梯的方向来决定,但1楼和3楼同属于两个模块,在信号合并的时候使用&符号。
但这样的设计会出现矛盾,有两个矛盾状态:
矛盾1:电梯停止的时候,电梯方向往上,却按了电梯往下的按键
矛盾2:电梯停止的时候,电梯方向往下,却按了电梯往上的按键
处理方法改变电梯方向,送至该楼层。
int:输入的按键值
ou:电梯按键灯
res:复位
clk:时钟信号
led:数码管
dt_fx:电梯方向
wz_led:电梯楼层灯
由系统仿真图可知,当按下四个按键时,电梯处于一楼时,电梯先熄灭一楼按键灯,再升到二楼,熄灭二楼电梯按键上行灯,再升到三楼,熄灭三楼按键灯,之后将电梯方向改为向下,再到二楼,熄灭二楼电梯按键下行灯。