課程設計-簡易電梯系統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

(失效請及時聯系我,盡快更新)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM