电梯控制系统的实现(代码简洁优质、易懂)

目录

设计目的与要求

设计原理及方案

下面是设计的细节,再这里,笔者的注释都写得很清楚,因此不会啰嗦的一段段解释,只介绍关键的部分,其余的详见代码注释即可(此处建议直接看代码更好,上面的知识一个框架而已):

附页(源代码)

TOP

u0: clk_div

u1: ajxd

u2: control

u3: displine

附页(约束文件)


 

设计目的与要求

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;每一层楼之间的运行时间间隔为秒

5、有2个拨码开关。

(1)复位开关。向下拨动后电梯复位回到1楼

(2)启动开关。向上拨动后,按键有效,电梯正常工作

6、附加功能

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

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

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

 

设计原理及方案

先看模块之间的关系:

f0d5108f31494215a4a19b8b74f622ed.png

 

Top:顶层模块

U0 (clk_div): 时钟分频模块,产生20ms时钟

U1 (ajxd)  按键消抖模块

U2 (control):控制模块,控制LED[3:0]按键灯和LEDOUT[4:0]流水灯、电梯运行状态、所处楼层以及开启和复位

U3 (displine)动态显示模块,显示电梯所在楼层、运行状态以及4.9~0.0s倒计时计数

ca003454fe6b407e951fb90933d10f35.png

 RTL分析:

46926d02e3944e79a460a8ccb583f684.png

 

下面是设计的细节,再这里,笔者的注释都写得很清楚,因此不会啰嗦的一段段解释,只介绍关键的部分,其余的详见代码注释即可(此处建议直接看代码更好,上面的知识一个框架而已):

 

1)按键的检测

input [3:0]col           // 定义4个按键KEY0、1、2、3输入

output [3:0]row         //定义一行[3:0]row,

assign row[3:0]=4'b0001  //固定这一行

 

2)按键消抖

检测到按键[3:0]col,输入消抖模块的btn_in
module ajxd(
    input [3:0]btn_in,
    input btn_clk,
    output [3:0]btn_out
    );  
    reg  [3:0]btn0=0;//定义了btn0寄存器
    reg  [3:0]btn1=0;//定义了btn1寄存器
    reg  [3:0]btn2=0;//定义了btn2寄存器
  //按键btn_in的消抖程序
  assign btn_out=(btn2&btn1&btn0)|(~btn2&btn1&btn0);//btn_out信号 每按下一次按键,只产生一个上升沿                                               
    always@ (posedge btn_clk)
      begin
          btn0<=btn_in;
          btn1<=btn0;
          btn2<=btn1;
      end           
endmodule

需要注意的是上面的寄存器用的是4位的,这样就能一一对应4个按键,避免后面需要例化4次按键消抖模块

 

2)控制模块

在控制模块中,主要的思路就是设置一个32位的[31:0]number主计数器(clk时钟为50M),number计数250M次就是5秒、500M次就是10秒,需要控制的东西就可以在这个过程中被执行,这个执行的过程时间是忽略不计的,对整体的5秒计数是不影响的,这里只举例部分的代码作为说明,具体的可以参考附页上的代码注释说明

因为按键消抖产生的信号[3:0]btn_out相对CLK时钟周期很长,所以要想按照这个思路进行下去就得把[3:0]btn_out缩短位一个CLK周期的单稳态信号[3:0]keyout.

9e14ac27867c451a9a31db3f22ac5bbd.png

 

always@(posedge clk)
    
    begin                
        if((SW0==1)&&(i==0)&&(keyin!=4'b0000))      //将长的按键信号缩短位1个CLK时钟周期
                begin
                  keyout<=keyin;
                  i<=1;
                end
        else if((i==1)&&(keyin!=4'b0000))
                begin
                  keyout<=4'b0000;
                end
        else if((i==1)&&(keyout==4'b0000)&&(keyin==4'b0000)) i<=0;

 

4)按键LED灯、楼层、运行状态变化

主要是靠判断[3:0]keyout是否有输出(按键被按下),同时也要判断是否有第二次按下,并且禁止第三次按下按键

5)流水灯控制

 //LED11--7控制
    always@(number)
    begin
            if (state==2'b01)
                case(number)
                1:        LEDOUT<=5'b10000;
                50000000: LEDOUT<=5'b11000;
                100000000:LEDOUT<=5'b11100;
                150000000:LEDOUT<=5'b11110;
                200000000:LEDOUT<=5'b11111;
                250000000:if(second_press==0)LEDOUT<=5'b00000;
                   
                
                250000002:LEDOUT<=5'b10000; //此处要特别注意必须为250M+1以上
                300000000:LEDOUT<=5'b11000;
                350000000:LEDOUT<=5'b11100;
                400000000:LEDOUT<=5'b11110;
                450000000:LEDOUT<=5'b11111;
                500000000:LEDOUT<=5'b00000;
                
                default:;
                endcase
另外一个state==2’b10是对称的,此处没写出来,具体可参见附页的源代码

 

6)动态显示模块

在这个模块中输入了楼层[1:0]floor、运行状态[1:0]state

    input clk,        //50M时钟
    input [1:0]floor,   //从控制模块中输入楼层[1:0]floor
    input [1:0]state,   //从控制模块中输入运行状态[1:0]state
    input EN,		    //从控制模块中输入使能计数4.9s~0.0秒
    output reg [7:0] seg,  //段码输出
    output reg [3:0] dig  //位码输出

倒计时计数4.9s~0.0秒采用一个10进制和一个5进制计数器级联构成,注意显示的时候小数点得加上,因此seg输出时需要注意

//10进制计数器器
    reg[3:0]Q1=0;
    wire cy;
    always@(posedge clk_10HZ)
    begin
        if(EN==1)
            begin
                if(Q1==0)Q1<=9;
                else    Q1<=Q1-1;                   
            end
        else Q1<=0;
    end
    assign cy=((EN==1)&&(Q1==0))?1'b1:1'b0;
    //5进制计数器
    reg[3:0]Q2=0;
    always@(posedge clk_10HZ)
    begin
        if(cy==1)
            begin
                if(Q2==0)Q2<=4;
                else     Q2<=Q2-1;
            end
        
end                            //两个计数器已经通过cy级联

 

 

 

附页(源代码)

TOP


module Top(

    input clk,                 //50M时钟

    input [3:0]col,          // 定义时钟和4个按键输入

    input SW0,               //定义SW0启动开关

    input SW11,             //定义SW11复位开关

    output [7:0] seg,      //段码输出

    output [3:0] dig,      //位码输出

    output [3:0]row,      // 定义行

    output [3:0]led,      //LED0---LED4按键灯

    output [4:0]LEDOUT //LED11----LED7流水灯

           );

 

    assign row[3:0]=4'b0001;  //固定一行row3

    wire clk_20ms;          // 20ms clk

    wire [3:0]keyin;

    reg [3:0]keyout;         //脉宽变换后的按键信号

    wire [1:0]floor;         //定义楼层

    wire [1:0]state;         //定义电梯的状态

    wire enable;

   

//

C++源代码 注重类的交互 片段 #include using namespace std; #include "elevator.h" //Elevator class definition #include "person.h" //Person class definition #include "floor.h" //Floor class definition //constants that represent time required to travel //between floors and direction of the elevator const int Elevator::ELEVATOR_TRAVEL_TIME = 5; const int Elevator::UP = 0; const int Elevator::DOWN = 1; //constructor Elevator::Elevator( Floor &firstFloor, Floor &secondFloor) : elevatorButton( * this ), currentBuildingClockTime( 0 ), moving( false ), direction( UP ), currentFloor( Floor::FLOOR1 ), arrivalTime( 0 ), floor1NeedsService( false ), floor2NeedsService( false ), floor1Ref( firstFloor ), floor2Ref( secondFloor ), passengerPtr( 0 ) { cout << "elevator constrcuted" <<endl; }// end Elevator constructor //destructor Elevator::~Elevator() { delete passengerPtr; cout << "elevator destructed" << endl; }//end Elevator destructor //give time to elevator void Elevator::processTime( int time ) { currentBuildingClockTime = time; if ( moving ) //elevator is moving processPossibleArrival(); else processPossibleDeparture(); if ( !moving ) cout << "elevator at rest on floor " << currentFloor << endl; }// end function processTime // when elevator is moving, determine if it should stop void Elevator::processPossibleArrival() { //if elevator arrives at destination floor if ( currentBuildingClockTime == arrivalTime ) { currentFloor = ( currentFloor == Floor::FLOOR1 ? Floor::FLOOR2 : Floor::FLOOR1); //update current floor direction = ( currentFloor == Floor::FLOOR1 ? UP : DOWN ); //update direction cout << "elevator arrives on floor " << currentFloor <<endl; // process arrival at currentFloor arriveAtFloor( currentFloor == Floor::FLOOR1 ? floor1Ref : floor2Ref); return; }//end if //elevator still moving cout << "elevator moving " << ( direction == UP ? "UP" : "DOWN"
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值