小白创作,请多指教。
设计要求:
1、实现 2 层楼的简易电梯控制系统。
2、电梯有 4 个按键。1 楼外只有向上按键(KEY0),2 楼外只有向下按键(KEY1),电梯内还
有 2 个按键分别为 1 楼按键(KEY2)和 2 楼按键(KEY3)。所有楼层外和电梯内的按键产生的信
号作为给电梯的运行请求信号。电梯在 1 楼时,只有 KEY1、KEY3 有效,在 2 楼时只有 KEY0、
KEY2 有效。电梯在上升过程中只有 KEY0、KEY2 有效,且到达 2 楼后会自动运行回到 1 楼。
在下降过程中只有 KEY1、KEY3 有效,且到达 1 楼后会自动运行回到 2 楼。
3、电梯有 4 个指示灯(LED0、LED1、LED2、LED3)。
LED0(P9): 按下 KEY0 键,若电梯不在 1 楼,则 LED0 亮。
LED1(R8): 按下 KEY1 键,若电梯不在 2 楼,则 LED1 亮。
LED2(R7): 电梯在 2 楼,按 KEY2 键, 则 LED2 亮,电梯到 1 楼后 LED2 灭。
LED3(T5): 电梯在 1 楼,按 KEY3 键, 则 LED3 亮,电梯到 2 楼后 LED3 灭。
4、有 2 个数码管,分别显示当前运行状态及楼层。
(
1)1 个数码管(H13)显示当前运行状态,电梯有三个运行状态:待机、上行、下行。待机:
电梯停在 1 楼或 2 楼且无请求信号时均为待机状态。
上行状态:电梯停在 1 楼,有 KEY1 或 KEY3 被按下,进入上行状态。
下行状态:电梯停在 2 楼,有 KEY0 或 KEY2 被按下,进入下行状态。
(
2)1 个数码管(G12)显示所在楼层,显示 1 或 2;每一层楼之间的运行时间间隔为 5 秒。
5、有 2 个拨码开关。
(
1)复位开关 SW11(F3),向下拨动后,电梯复位回到 1 楼。
(
2)启动开关 SW0(T9),向上拨动后,按键有效,电梯正常工作。
6、数码管 N14、N11 显示电梯运行剩余时间,精确到 0.1 秒。
7、电梯在 1 楼时,只有 KEY1、KEY3 有效,在 2 楼时只有 KEY0、KEY2 有效。电梯在上升
过程中只有 KEY0、KEY2 有效,且到达 2 楼后会自动运行回到 1 楼。在下降过程中只有 KEY1、
KEY3 有效,且到达 1 楼后会自动运行回到 2 楼。
8、电梯到达新楼层后蜂鸣器会发出“嘀”声。
设计方案:
Vivado代码:
约束文件:
约束文件 #ajxd set_property PACKAGE_PIN K3 [get_ports {row[0]}] set_property PACKAGE_PIN M6 [get_ports {row[1]}] set_property PACKAGE_PIN P10 [get_ports {row[2]}] set_property PACKAGE_PIN R10 [get_ports {row[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {row[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {row[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {row[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {row[3]}] set_property PACKAGE_PIN R12 [get_ports {col[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {col[0]}] set_property PACKAGE_PIN T12 [get_ports {col[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {col[1]}] set_property PACKAGE_PIN R11 [get_ports {col[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {col[2]}] set_property PACKAGE_PIN T10 [get_ports {col[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {col[3]}] set_property PULLDOWN true [get_ports {col[3]}] set_property PULLDOWN true [get_ports {col[2]}] set_property PULLDOWN true [get_ports {col[1]}] set_property PULLDOWN true [get_ports {col[0]}] #dynamic_led2 set_property PACKAGE_PIN G12 [get_ports {dig[0]}] set_property PACKAGE_PIN H13 [get_ports {dig[1]}] set_property PACKAGE_PIN M12 [get_ports {dig[2]}] set_property PACKAGE_PIN N13 [get_ports {dig[3]}] set_property PACKAGE_PIN N14 [get_ports {dig[4]}] set_property PACKAGE_PIN N11 [get_ports {dig[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {dig[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {dig[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {dig[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {dig[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {dig[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {dig[5]}] set_property PACKAGE_PIN L13 [get_ports {seg[7]}] set_property PACKAGE_PIN M14 [get_ports {seg[6]}] set_property PACKAGE_PIN P13 [get_ports {seg[5]}] set_property PACKAGE_PIN K12 [get_ports {seg[4]}] set_property PACKAGE_PIN K13 [get_ports {seg[3]}] set_property PACKAGE_PIN L14 [get_ports {seg[2]}] set_property PACKAGE_PIN N12 [get_ports {seg[1]}] set_property PACKAGE_PIN P11 [get_ports {seg[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}] #led set_property PACKAGE_PIN P9 [get_ports {led[0]}] set_property PACKAGE_PIN R8 [get_ports {led[1]}] set_property PACKAGE_PIN R7 [get_ports {led[2]}] set_property PACKAGE_PIN T5 [get_ports {led[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}] set_property PACKAGE_PIN D4 [get_ports clk] #SW set_property PACKAGE_PIN F3 [get_ports reset] set_property PACKAGE_PIN T9 [get_ports start] set_property IOSTANDARD LVCMOS33 [get_ports clk] set_property IOSTANDARD LVCMOS33 [get_ports reset] set_property IOSTANDARD LVCMOS33 [get_ports start] #蜂鸣器 set_property PACKAGE_PIN L2 [get_ports buzzer_out] set_property IOSTANDARD LVCMOS33 [get_ports buzzer_out]
1.顶层模块lift.v
`timescale 1ns / 1ps
module lift(
input clk, //50M时钟
input [3:0] col, //按键消抖后的信号
input reset, //复位
input start, //启动
output [3:0] row, //矩阵键盘行线
output [7:0] seg, //数码管显示
output [5:0] dig, //数码管使能
output [3:0] led, //LED灯
output buzzer_out //蜂鸣器标志信号
);
wire [3:0] btn_out,r0,r4,r5;
wire [1:0] r1;
wire btn_clk,buzzer;
//分频,50Hz
clk_div l1(.clk(clk),
.btn_clk(btn_clk));
//按键消抖
ajxd l2(.col(col),
.row(row),
.btn_clk(btn_clk),
.btn_out(btn_out));
//数码管显示
dynamic_led l3(.r0(r0),
.r1(r1),
.r4(r4),
.r5(r5),
.clk(clk),
.seg(seg),
.dig(dig));
//蜂鸣器
buzzer l4(.clk(clk),
.buzzer(buzzer),
.buzzer_out(buzzer_out));
//电梯控制
lift_ctrl l5(.clk(clk),
.key_in(btn_out),
.reset(reset),
.start(start),
.r1(r1),
.r0(r0),
.r4(r4),
.r5(r5),
.led(led),
.buzzer(buzzer)
);
endmodule
2.电梯控制模块lift_ctrl.v
`timescale 1ns / 1ps
module lift_ctrl(
input clk,
input [3:0] key_in,
input reset,
input start,
output [1:0] r1,
output [3:0] r0,
output [3:0] r4,
output [3:0] r5, //数码管显示
output [3:0] led,
output buzzer
);
//定义寄存器
reg f=0,i=0,flag=0,buzzer_reg=0,rst_reg=1;
reg key_flag=1; //按键允许标志
reg nd_2=0; //是否按下第二次标志
reg buzzer_flag=0; //蜂鸣器发声标志
reg [1:0] k=0,state=0;
reg [3:0] key=0,key1=0,key2=0,led_o=0,floor=1;
reg [5:0] show_time=0;
reg [30:0] count=0;
assign led=led_o;
assign r0=floor;
assign r1=state;
assign r4=show_time%10;//将show_time分为
assign r5=(show_time-(show_time%10))/10;//十位和个位
assign buzzer=buzzer_reg;
always@(posedge clk)
begin
//检测复位信号,转化为单周期脉冲
if((f==0)&&(reset==0))
begin
rst_reg<=reset;
f<=1;
end
else if((f==1)&&(rst_reg==0))
begin
rst_reg<=1;
end
else if((f==1)&&(rst_reg==1)&&(reset==1))
begin
f<=0;
end
//检测按键信号,转化为单周期脉冲
if((start==1)&&(i==0)&&(key_in!=4'b0000))
begin
key<=key_in;
i<=1;
end
else if((i==1)&&(key!=4'b0000))
begin
key<=4'b0000;
end
else if((i==1)&&(key==4'b0000)&&(key_in==4'b0000))
begin
i<=0;
end
//检测按键、复位脉冲,控制输出
if((rst_reg==0)&&(floor==2)&&(state==0))
begin
state<=2;
flag<=1;
key_flag<=0; //复位期间按键无效
end
else if((key!=0)&&(rst_reg==1)&&(key_flag==1))
begin
if(key[0])//检测KEY0
begin
if((key1==4'b0000)&&(floor==2))
begin
flag<=1;
led_o[0]<=1;
key1[0]<=1;
state<=2;
end
else if((key1[1]==1)||(key1[3]==1))
begin
led_o[0]<=1;
key2[0]<=1;
key_flag<=0;
end
end
else if(key[1])//检测KEY1
begin
if((key1==4'b0000)&&(floor==1))
begin
flag<=1;
led_o[1]<=1;
key1[1]<=1;
state<=1;
end
else if((key1[0]==1)||(key1[2]==1))
begin
led_o[1]<=1;
key2[1]<=1;
key_flag<=0;
end
end
else if(key[2])检测KEY2
begin
if((key1==4'b0000)&&(floor==2))
begin
flag<=1;
led_o[2]<=1;
key1[2]<=1;
state<=2;
end
else if((key1[1]==1)||(key1[3]==1))
begin
led_o[2]<=1;
key2[2]<=1;
key_flag<=0;
end
end
else if(key[3])//检测KEY3
begin
if((key1==4'b0000)&&(floor==1))
begin
flag<=1;
led_o[3]<=1;
key1[3]<=1;
state<=1;
end
else if((key1[0]==1)||(key1[2]==1))
begin
led_o[3]<=1;
key2[3]<=1;
key_flag<=0;
end
end
end
else无按键按下
begin
if(count==1)
begin
show_time<=50;
count<=count+1;
end
else if((count>0)&&(count<250000000)&&(count%5000000==0))
begin
show_time<=50-count/5000000;
count<=count+1;
end
else if((count>250000000)&&(count<500000000)&&(count%5000000==0))
begin
count<=count+1;
show_time<=100-count/5000000;
end
else if(count==30'd250000000)
begin
buzzer_reg<=1;
show_time<=0; //显示回零,蜂鸣器"嘀"
k[0]<=1;
count<=count+1;
end
else if(count==30'd250000002)
begin
k[0]<=0;
count<=count+1;
end
else if(count==30'd500000000)
begin
k[1]<=1;
buzzer_reg<=1;
show_time<=0; //显示回零,蜂鸣器"嘀"
count<=count+1;
end
else if(k[0]==1)/检测5s
begin
count<=count+1;
buzzer_reg<=0;
if(floor==1) floor<=2;
else if(floor==2) floor<=1;
if(led_o==4'b0000) //复位完成
begin
state<=0;
k[0]<=0;
flag<=0;
count<=0;
key_flag<=1;
end
else if((led_o==4'b0001)||(led_o==4'b0010)||(led_o==4'b0100)||(led_o==4'b1000))
//没有按第二次,将灯熄灭
begin
key1<=4'b0000;
key2<=4'b0000;
led_o<=4'b0000;
state<=0;
k[0]<=0;
flag<=0;
count<=0;
key_flag<=1;
end
else //按了第二次,将第一次按的灯熄灭
begin
count<=count+1;
nd_2<=1; //按了第二次
if(state==1) state<=2;
else if(state==2) state<=1; //运行状态反转
case(key1)
4'b0001:led_o[0]<=0;
4'b0010:led_o[1]<=0;
4'b0100:led_o[2]<=0;
4'b1000:led_o[3]<=0;
default:led_o<=4'b0000;
endcase
end
end
else if(k[1]==1)/检测10s
begin
if(floor==1) floor<=2;
else if(floor==2) floor<=1;
key1<=4'b0000;
key2<=4'b0000;
led_o<=4'b0000;
state<=0;
k[1]<=0;
key_flag<=1;
flag<=0;
count<=0;
buzzer_reg<=0;
end
else计数
begin
if(flag==1) count<=count+1;
end
end
end
endmodule
3.分频模块clk_div.v
`timescale 1ns / 1ps
module clk_div( clk,btn_clk);
input clk;
output btn_clk;// 20ms两个输出
reg[31:0] btn_clk_cnt = 0;//对50M时钟1M分频的计数器
reg btn_clk = 0;//50Hz信号,周期20ms,初值为0
always@(posedge clk) //系统时钟上升沿时,20ms,50Hz,50M/50=1000000 ,1M分频
begin
if(btn_clk_cnt==499999)
begin
btn_clk =~ btn_clk;
btn_clk_cnt = 0;
end
else
btn_clk_cnt = btn_clk_cnt+1'b1;
end
endmodule
4.按键消抖模块ajxd.v
`timescale 1ns / 1ps
//按键消抖模块
module ajxd(
input [3:0] col,
output [3:0] row,
input btn_clk,
output [3:0] btn_out);
reg [2:0] btn0,btn1,btn2,btn3;
assign row=4'b0001;
assign btn_out[0]=(btn0[2]&btn0[1]&btn0[0])|(~btn0[2]&btn0[1]&btn0[0]);
assign btn_out[1]=(btn1[2]&btn1[1]&btn1[0])|(~btn1[2]&btn1[1]&btn1[0]);
assign btn_out[2]=(btn2[2]&btn2[1]&btn2[0])|(~btn2[2]&btn2[1]&btn2[0]);
assign btn_out[3]=(btn3[2]&btn3[1]&btn3[0])|(~btn3[2]&btn3[1]&btn3[0]);
always@ (posedge btn_clk)
begin
//KEY0
btn0[0]<=col[0];
btn0[1]<=btn0[0];
btn0[2]<=btn0[1];
//KEY1
btn1[0]<=col[1];
btn1[1]<=btn1[0];
btn1[2]<=btn1[1];
//KEY2
btn2[0]<=col[2];
btn2[1]<=btn2[0];
btn2[2]<=btn2[1];
//KEY3
btn3[0]<=col[3];
btn3[1]<=btn3[0];
btn3[2]<=btn3[1];
end
endmodule
5.数码管显示模块dynamic_led.v
`timescale 1ns / 1ps
module dynamic_led(
input [3:0] r0,
input [1:0] r1,
input [3:0] r4,
input [3:0] r5,
input clk,
output reg [7:0] seg,
output reg [5:0] dig);
//分频
reg[24:0] clk_div_cnt=0;
reg clk_div=0;
always @ (posedge clk)
begin
if (clk_div_cnt==25000)
begin
clk_div=~clk_div;
clk_div_cnt=0;
end
else
clk_div_cnt=clk_div_cnt+1;
end
//6进制计数器
reg [2:0] num=0;
always @ (posedge clk_div)
begin
if (num>=5)
num=0;
else
num=num+1;
end
//译码器
always @ (num)
begin
case(num)
0:dig=6'b111110;
1:dig=6'b111101;
2:dig=6'b111011;
3:dig=6'b110111;
4:dig=6'b101111;
5:dig=6'b011111;
default: dig=6'b111111;
endcase
end
//选择器,确定显示数据
always @ (num)
begin
if(num==0)
begin
case(r0)
4'h0: seg=8'h3f;// DP,GFEDCBA
4'h1: seg=8'h06;
4'h2: seg=8'h5b;
4'h3: seg=8'h4f;
4'h4: seg=8'h66;
4'h5: seg=8'h6d;
4'h6: seg=8'h7d;
4'h7: seg=8'h07;
4'h8: seg=8'h7f;
4'h9: seg=8'h6f;
4'ha: seg=8'h77;
4'hb: seg=8'h7c;
4'hc: seg=8'h39;
4'hd: seg=8'h5e;
4'he: seg=8'h79;
4'hf: seg=8'h71;
default: seg=0;
endcase
end
else if(num==1)
begin
case(r1)
2'b00: seg=8'h40;
2'b01: seg=8'h01;
2'b10: seg=8'h08;
2'b11: seg=8'h00;
default:seg=0;
endcase
end
else if(num==4)
begin
case(r4)
4'h0: seg=8'h3f;// DP,GFEDCBA
4'h1: seg=8'h06;
4'h2: seg=8'h5b;
4'h3: seg=8'h4f;
4'h4: seg=8'h66;
4'h5: seg=8'h6d;
4'h6: seg=8'h7d;
4'h7: seg=8'h07;
4'h8: seg=8'h7f;
4'h9: seg=8'h6f;
4'ha: seg=8'h77;
4'hb: seg=8'h7c;
4'hc: seg=8'h39;
4'hd: seg=8'h5e;
4'he: seg=8'h79;
4'hf: seg=8'h71;
default: seg=0;
endcase
end
else if(num==5)
begin
case(r5)
4'h0: seg=8'hbf;// DP,GFEDCBA,显示小数点
4'h1: seg=8'h86;
4'h2: seg=8'hdb;
4'h3: seg=8'hcf;
4'h4: seg=8'he6;
4'h5: seg=8'h6d;
4'h6: seg=8'hfd;
4'h7: seg=8'h87;
4'h8: seg=8'hff;
4'h9: seg=8'hef;
4'ha: seg=8'hf7;
4'hb: seg=8'hfc;
4'hc: seg=8'hb9;
4'hd: seg=8'hce;
4'he: seg=8'hf9;
4'hf: seg=8'hf1;
default: seg=0;
endcase
end
else
seg=8'h00;
end
endmodule
6.蜂鸣器模块buzzer.v
`timescale 1ns / 1ps
module buzzer(
input clk,
input buzzer,
output buzzer_out
);
reg buzzer_clk=0,buzzer_out_flag;
reg [30:0] buzzer_clk_cnt=0;
reg [30:0] buzzer_out_cnt=0;
assign buzzer_out=buzzer_out_flag&&buzzer_clk;
always@(posedge clk) //系统时钟上升沿时
begin
//5kHz,50M/5000=10000 ,1M分频
if(buzzer_clk_cnt==4999)
begin
buzzer_clk =~ buzzer_clk;
buzzer_clk_cnt = 0;
end
else
begin
buzzer_clk_cnt = buzzer_clk_cnt+1'b1;
end
//当buzzer脉冲到来时,将buzzer_out_flag置高0.5秒,即蜂鸣器"嘀"0.5秒
if(buzzer==1)
begin
buzzer_out_flag<=1;
end
else if((buzzer==0)&&(buzzer_out_cnt>=25000000))
begin
buzzer_out_flag<=0;
end
if(buzzer_out_flag==1)
begin
buzzer_out_cnt<=buzzer_out_cnt+1;
end
else
begin
buzzer_out_cnt<=0;
end
end
endmodule
RTL分析: