课程设计-简易电梯系统verilog实现

一.设计要求

1、实现2层楼的简易电梯控制系统

2、电梯有4个按键
1楼外只有向上按键(KEY0),2楼外只有向下按键(KEY1),电梯内还有2个按键分别为1楼按键(KEY2)和2楼按键(KEY3)。所有楼层外和电梯内的按键产生的信号作为给电梯的运行请求信号。

3、电梯有4个指示灯(LED0、 LED1 、 LED2 、 LED3)
LED0: 按下KEY0键,若电梯不在1楼,则LED0亮。
LED1: 按下KEY1键,若电梯不在2楼,则LED1亮。
LED2: 电梯在2楼,按KEY2键, 则LED2亮,电梯到1楼后LED2灭。
LED3: 电梯在1楼,按KEY3键, 则LED3亮,电梯到2楼后LED3灭。

4、有2个数码管,分别显示当前运行状态及楼层
(1)1个数码管显示当前运行状态,电梯有三个运行状态:待机、上行、下行。
待机:电梯停在1楼或2楼且无请求信号时均为待机状态。
上行状态:电梯停在1楼,有KEY1或KEY3被按下,进入上行状态。
下行状态:电梯停在2楼,有KEY0或KEY2被按下,进入下行状态。
(2)1个数码管显示所在楼层,显示1或2;每一层楼之间的运行时间间隔为4秒。

5、有2个拨码开关
(1)复位开关:向下拨动后,电梯复位回到1楼。
(2)启动开关:向上拨动后,按键有效,电梯正常工作。

6、额外实现要求(选做)

(1)

电梯上行时,LED11至LED7五个指示灯从左到右每隔一秒点亮一个;
电梯下行时,LED7至LED11五个指示灯从右到左每隔一秒点亮一个。

(2)

电梯运行到达新楼层时,蜂鸣器发出一声清晰“嘀”声。

(3)

电梯开始上行或下行时,在最左边两个数码管上倒计时显示运行时间3.9~0.0(秒),精度为0.1秒。到达新楼层时显示0.0(秒)

(4)

电梯上行时,楼层显示数码管前3秒显示1,后1秒显示2;
电梯下行时,楼层显示数码管前3秒显示2,后1秒显示1。

二.实现思路

(读代码最能理解,只需阅读核心代码即可)

1.模块化实现,主要包括时钟配置、按键输入信号处理、状态信号控制数码管、状态信号控制LED、蜂鸣器驱动

2.时钟配置主要需要用于:

【实验板内部固定50Mhz晶振,分频时使用计数器,计数增1一次是1/50MHz】

1KHz、50Hz送给按键模块,前者扫描行列键盘,后者按键消抖;

0.25Hz(4s)用于电梯上行下行所需时间;

数码管动态显示直接使用晶振50MHz即可;

使用了个1MHz送给LED内部使用,可以直接用50MHz;

3.按键输入信号处理:

【行列4*4键盘,需要按键消抖】

拨码开关输入信号;

4.电梯核心控制:

(1)需求分析:

最主要的是电梯状态机的控制,包括state(上行、下行、待机),floor(一楼、二楼),对应的四个KEY(一楼外、二楼外、内部去一楼、内部去二楼)。
因此按键扫描模块需要引入两个时钟,分别做按键扫描和按键消抖(1KHz、50Hz);数码管状态显示根据state变量进行改变,数码管楼层显示根据floor变量进行改变,具体为在1KHz的扫描时钟下,判断变量是否由变化,并通过动态显示将楼层显示在第一位,将状态显示在第二位;蜂鸣器根据lock变量,在每次新楼层产生时发出1KHz信号驱动蜂鸣器;流水灯根据state变量改变,并使用1Hz信号依次点亮。

 

(2)状态机设计:

 

(3)特殊之处详解:

(1.如何实现运行状态也能接收按键信号?
答:在运行状态的4s计数时间中加入判断逻辑,如果按键按下且目标楼层和按键不一致,则存储这个按键信号并点亮对应的按键LED。
(2.怎么处理所谓的存储下来的按键信号?
答:在状态为待机状态时需要固定扫描按键信号和存储信号,此时可以处理存储下来的信号,即改变对应的运行状态。
(3.lock信号有什么用处?
Lock信号一方面是源于实际生活,可以说是为了开关门信号做了一个备用的信号,在日常生活中电梯到达之后需要固定的一段时间供人们出入;另一方面,本次实验引入lock信号正好可以用于新楼层到达时驱动蜂鸣器。

三.具体代码

 

复制代码
module top_module(
  input clk,
  input set,    //T9启动信号
  input reset,  //f3 复位信号
  input [3:0]col,
  output reg buzzlock,
  output  [3:0]row,
  output  [3:0]led,
  output [4:0]led_o,
  output [5:0]dig,
  output [7:0]seg
    );
    wire clk_1k;
    wire clk_50;
    //wire clk_4s;
 
  clk_div u1(.clk(clk),
         .clk_1k(clk_1k),
         .clk_50(clk_50)
         );
         wire buzz;
         wire k0;
         wire k1;
         wire k3;
         wire k2;
  keyboard u2(
         .clk_1k(clk_1k),//键盘扫描
         .clk_50(clk_50),//按键消抖
         .col(col),
         .row(row),//行初值
         .key0_upButton(k0),//对应一楼按键
         .key1_downButton(k1),//对应二楼按键
         .key2_upstair(k3),
         .key3_downstair(k2));//对应电梯内1 2按键  
         
        wire [1:0]state;
        wire [1:0]floor;      
        wire gate;
  elevator u3(
    .clk(clk),
    .set(set),
    .reset(reset),
    .lock(buzz),
    .key0(k0),
    .key1(k1),
    .key3(k3),
    .key2(k2),
   
    .led(led),//指示灯
    .state(state),//00待机状态 01上行状态 10下机状态
    .floor(floor) ); //楼层 01一楼 10二楼 
    
   dynamic_led u4(
    .floor(floor),
    .state(state),
    .gate(gate),
    .clk(clk_1k),
    .seg(seg),
    .dig(dig)
    );
    
    always@(clk)
    begin
    if(buzz)
    buzzlock = clk_1k;
    else
    buzzlock = 0;
    end

    running u5(
    .clk_i(clk),
    .state(state),
     .reset(reset),
    //.m(m),//state状态,1时候表示上行,2表示下行,处理一下将state_new输进来(0表示下行 1表示上行)
    .led_o(led_o)
    );
endmodule
复制代码
复制代码
module clk_div(clk,clk_1k,clk_50);
      input clk;
      output reg clk_1k=0;
      output reg clk_50=0;
      
      reg[24:0] clk_div_cnt0=0;
      reg[24:0] clk_div_cnt1=0;
      //1khz
      always @ (posedge clk)
              begin
                  if (clk_div_cnt0==24999)//分频
                  begin
                      clk_1k=~clk_1k;
                      clk_div_cnt0=0;
                  end
                  else 
                      clk_div_cnt0=clk_div_cnt0+1;
             end
    //50hz         
       always @ (posedge clk)
             begin
                 if (clk_div_cnt1==499999)//分频
                         begin
                           clk_50=~clk_50;
                           clk_div_cnt1=0;
                          end
                  else 
                       clk_div_cnt1=clk_div_cnt1+1;
                          end 
endmodule
复制代码
复制代码
module keyboard(
input clk_1k,//键盘扫描
input clk_50,//按键消抖
input [3:0]col,
output reg [3:0]row=4'b0001,//行初值
output  key0_upButton,//对应一楼按键
output  key1_downButton,//对应二楼按键
output  key2_upstair,
output  key3_downstair);//对应电梯内1 2按键
 
reg [15:0] btn=0;//初始化为0
always @ (posedge clk_1k)
    begin
        if (row[3:0]==4'b1000)
             row[3:0]=4'b0001;//到了1000,下一个是0001
        else
             row[3:0]=row[3:0]<<1; //向左移一位。0001-0010-0100-1000-0001
   end
 
always @ (negedge clk_1k)
    begin
        case (row[3:0])
        4'b0001:
           begin
               btn[3:0]=col;   //列输入值存至4位寄存器
           end
        4'b0010:
           begin
           btn[7:4]=col;
           end
        4'b0100:
           begin
           btn[11:8]=col;
           end
        4'b1000:
           begin
           btn[15:12]=col;
           end 
        default:btn=0;              
        endcase
    end 
   
  ajxd u0(
        .btn_in(btn[0]), 
        .clk(clk_50),
        .btn_out(key0_upButton)
        );   
   ajxd u1(
         .btn_in(btn[1]), 
         .clk(clk_50),
         .btn_out(key1_downButton)
          ); 
  ajxd u2(
         .btn_in(btn[3]), 
         .clk(clk_50),
         .btn_out(key2_upstair)
           );  
  ajxd u3(
         .btn_in(btn[2]), 
         .clk(clk_50),
         .btn_out(key3_downstair)
           );  
                                                        
endmodule
复制代码
复制代码
module ajxd(
    input btn_in, 
    input clk,
    output btn_out
    );  
    reg  btn0=0;//定义了btn0寄存器
    reg  btn1=0;//定义了btn1寄存器
    reg  btn2=0;//定义了btn2寄存器
    reg[24:0] clk_div_cnt=0;
    reg btn_clk=0;
 
 always@ (posedge clk)
      begin
          btn0<=btn_in;
          btn1<=btn0;
         btn2<=btn1;
      end
      assign btn_out=(btn2&btn1&btn0)|(~btn2&btn1&btn0);
endmodule
复制代码
复制代码
module elevator(
input clk,
input set,
input reset,//复位信号
input key0,//对应一楼按键
input key1,//对应二楼按键
input key2,//对应电梯内按键
input key3,
output reg lock,
output reg [3:0]led=0,
output reg [1:0]state=0,//00待机状态 01上行状态 10下机状态
output reg [1:0]floor=1  //楼层 01一楼 10二楼 
    );

reg [27:0]clk_count=0;
//reg [27:0]clk_count3=0;
reg [27:0]clk_lock=0;
reg [27:0]clk_reset=0;
reg [5:0]key_memory=0;

reg stop=0;
//assign loc = lock;
always@(posedge clk)
begin
if(reset==0)//复位信号有效时
       begin
        if(stop==0)
        begin
       // lock = 0;199999999 49999999
        if(clk_reset==199999999)//计数到4s
        begin
        led = 4'b0000;
        state=0;
        lock = 1;
        floor=1;
        clk_reset=0;
        stop = 1;
        end
        else
        begin
        clk_reset = clk_reset+1;
        state = (floor==2)? 2:0;
        stop = 0;
        if(clk_reset>=190999999)
        lock = 1;
        end
       end
       else
       lock=0;
       end
/*
    if(!reset)//复位信号有效时
       begin
        if(clk_count3==199999999)//计数到2s
        begin
        clk_count3=0;
        led=4'b0000;
        state=0;
        floor=1;
        end
        else
        clk_count3=clk_count3+1;
      end*/
else if(reset && set)//启动信号有效时
begin
    stop = (reset==1)? 0:1;
    if(state==0 && lock==1)
    begin
            if(clk_lock==24999999)//计数
            begin
            clk_lock=0;
            lock = 0;
            end
            
            else
            begin
            clk_lock=clk_lock+1;
            if( (key0==1 || key_memory[0]==1) && (floor!=1 || led[1] || led[3]) )
            led[0] = 1;
            else if ((key1==1 || key_memory[1]==1) && (floor!=2 || led[0] || led[2]))
            led[1] = 1;
            else if ((key2==1 || key_memory[3]==1) && (floor!=1 || led[1] || led[3]) )
            led[2] = 1;
            else if ((key3==1 || key_memory[4]==1) && (floor!=2 || led[0] || led[2]))
            led[3] = 1;
            end
          end
//(***上行下行模式配置)灯一旦是点亮状态,那么意味着进入运行模式,且4s之后楼层到达,灭灯,门开
    else if( (  ((led!=0))&&(state!=0)&&(key_memory==0)&&(lock==0)    ) || (clk_count!=0)   )
    begin
      if(clk_count==199999999)//计数到4s
       begin
         if((floor!=1)&&((led[2]==1)|(led[0]==1)))
         begin
         clk_count=0;
         state = 0;
         floor = 1;
         lock = 1;
         led[0] = 0;
         led[2] = 0;
         end
         else if((floor!=2)&&((led[3]==1)|(led[1]==1)))
         begin
         clk_count=0;
         state = 0;
         lock = 1;
         led[1] = 0;
         led[3] = 0;
         floor = 2;
         end
       end
    else
    begin
    clk_count=clk_count+1;
      if( (key0) && ((~led[2])&(~led[0])) )
      begin
      key_memory[0] = 1;
      led[0] = 1;
      end
      else if( (key2) && ((~led[2])&(~led[0])) )
      begin
      key_memory[3] = 1;
      led[2] = 1;
      end
      else if( (key1) && ((~led[3])&(~led[1])) )
      begin
      key_memory[1] = 1;
      led[1] = 1;
      end
      else if( (key3) && ((~led[3])&(~led[1])) )
      begin
      key_memory[4] = 1;
      led[3] = 1;
      end
    end
  end
    //else if((state==0)&((key_floor1 && key_floor2 && key_floor3 && key_lift1 && key_lift2 && key_lift3)==0))
    //else if((state==0)&&(gate==1)&&(key_gateoff==0)&&(key_gateon==0))  //&&((key_floor1 && key_floor2 && key_floor3 && key_lift1 && key_lift2 && key_lift3)==0))
    //根据外部按键情况改变运行模式
   else if((led[0] || led[1] || key0 || key1 ||  key_memory[0] || key_memory[1] ) && (state==0) && (lock == 0))  //一楼按下key0且电梯待机
   begin
        if( (led[0] || key0==1 || key_memory[0]==1) && floor!=1)
        begin
        led[0] = 1; //一楼电梯外灯亮
        key_memory[0]=0;
        state = 2;  //下行状态        
        end
        else if((led[0] || key0==1 || key_memory[0]==1) && floor==1)
        begin
        led[0] = 0;
        key_memory[0]=0;
        state = 0;
        end
       
        else if((led[1] || key1==1 || key_memory[1]==1) && floor!=2)
        begin
        led[1] = 1; //er楼电梯外灯亮
        key_memory[1]=0;
        state = ((floor>2)? 2:1);  //状态
        end
        else if((led[1] || key1==1 || key_memory[1]==1) && floor==2)
        begin
        led[1] = 0;
        key_memory[1]=0;
        state = 0;
        end
    end
    //根据内部按键情况改变运行模式
    else if((led[2] || led[3] || key2 || key3 ||  key_memory[3] || key_memory[4] ) && (state==0) &&(lock == 0))
    begin
            if((led[2] || key2==1 || key_memory[3]==1) && floor!=1)
            begin
            key_memory[3]=0;
            led[2] = 1; //一楼电梯nei灯亮
            state = 2;  //下行状态
            end
           
            else if((led[2] || key3==1 || key_memory[4]==1) && floor!=2)
            begin
            key_memory[4]=0;
            led[3] = 1; //er楼电梯外灯亮
            state = ((floor>2)? 2:1);  //状态
            end
    end
end
end
endmodule
复制代码
复制代码
module dynamic_led(
input [1:0]floor,//楼层
input [1:0]state,//状态
input gate,//
input clk,
output reg [7:0] seg,
output reg [5:0] dig
);
    reg [1:0] num=0;//二进制计数器
    always @ (posedge clk)
    begin
        if (num>=1)
            num=0;
        else
            num=num+1;
    end
    //译码器
    always @ (num)
    begin    
        case(num)
        0:dig=6'b111110;
        1:dig=6'b111101;
        
        default: dig=0;
        endcase
    end
    //选择器,确定显示数据
    reg [3:0] disp_data;
    always @ (num)
    begin    
        case(num)
        0:disp_data=floor;
        1:disp_data=state+3'b011;
    
        default: disp_data=0;
        endcase
    end
    //显示译码器
    always@(disp_data)
    begin
        case(disp_data)
        4'h1: seg=8'h06;
        4'h2: seg=8'h5b;
        4'h3: seg=8'h40;//待机
        4'h4: seg=8'h01;//上行
        4'h5: seg=8'h08;//下行
        4'h6: seg=8'h06;//关门**'1'
        4'h7: seg=8'h5b;//开门**'2'
        default: seg=0;
        endcase
    end
endmodule
复制代码
复制代码
module running(
input clk_i,
input [1:0]state,
input reset,
//input m,//state状态,1时候表示上行,2表示下行,处理一下将state_new输进来(0表示下行 1表示上行)
output reg[4:0]led_o
);
reg[31:0] clkcount = 0;//对50M时钟1M分频的计数器
reg clk_o = 0;//50Hz信号,周期20ms,初值为0 
always@(posedge clk_i) //系统时钟上升沿时 
       begin
            if(clkcount==24999999)//499or2499999
               begin
                    clk_o=~ clk_o;
                    clkcount = 0;
               end
            else
                begin
                   clkcount = clkcount+1'b1;
                end
            end
reg[3:0]s_present1 = 0;
reg[3:0]s_next1;//up
reg[3:0]s_present2 = 0;
reg[3:0]s_next2;//down
reg m;

always@(clk_o)
begin
if(state==1)
m = 1;
else if(state==2)
m = 0;
end

always@(m,s_present1,s_present2)
if((state == 1)&&(s_present1<=4))
s_next1 = s_present1+1;
else if((state == 2)&&(s_present2<=4))
s_next2 = s_present2+1;
else
begin
s_next1 = 0;
s_next2 = 0;
end

always@(negedge clk_o)
begin
s_present1<=s_next1;
s_present2<=s_next2;
end

always@(m,s_present1,s_present2)
if(state==1)//up
case(s_present1)
0:led_o = 5'b10000;
1:led_o = 5'b01000;
2:led_o = 5'b00100;
3:led_o = 5'b00010;
4:led_o = 5'b00001;
default:led_o = 5'bxxxxx;
endcase
else if(state==2)//down
case(s_present2)
0:led_o = 5'b00001;
1:led_o = 5'b00010;
2:led_o = 5'b00100;
3:led_o = 5'b01000;
4:led_o = 15'b10000;
default:led_o = 5'bxxxxx;
endcase
else if(state==0)
led_o = 5'b00000;
endmodule
复制代码
 

四.RTL分析结果

 

 五.实验结果

1.基础功能全部实现,拓展功能实现了两个(蜂鸣器和上行下行状态的流水灯表示)

2.具体实现情况:

六.附件

 https://wwe.lanzouj.com/i6KKIyrbdpa

(失效请及时联系我,尽快更新)

 

posted @   charonplus  阅读(2131)  评论(7编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示