Hades logoHades applet banner
PIC16F84 elevator controller

applet icon

The image above shows a thumbnail of the interactive Java applet embedded into this page. Unfortunately, your browser is not Java-aware or Java is disabled in the browser preferences. To start the applet, please enable Java and reload this page. (You might have to restart the browser.)

Circuit Description

This applet demonstrates the 5 floor elevator controller, realized as a software program running on a PIC16F84 microcontroller. To motivate and illustrate the elevator controller design, the applet contains a special simulation component that visualizes the elevator and its floor button.

The in this applet implements the 'elevator-algorithm', already presented as a state-machine in one of the previous applets. Once the elevator car has started, it keeps its current direction until all ongoing requests in that direction have been processed. For example, if the elevator is parked at floor1 and someone presses the button on level2 (modeled by state PARKED_1). Naturally, the elevator starts going up to level2 (state UP_TO_2). Now, assume that another person first pressed the button on level0 while the elevator is still moving, and a second person presses the button on level4 shortly afterwards. In this case, the elevator keeps going up to level2, but then continues going upwards to level4, before going down to level0.

Use the popup-menu ('edit') on the elevator component to open the window with the elevator visualization. Press any floor button and watch the behavior of the elevator controller. You can also open the PIC user-interface window to watch (and edit) the controller program.

The elevator has five buttons, one on each floor. In addition, there are floor level sensors. When the elevator is on the ground floor, the ground sensor is ON. If the elevator moves up, the ground sensor is OFF, and the K level sensor will be switched ON when the elevator arrives on the K floor. The engine and direction are elevator inputs.

Inputs:

engine: ON and OFF

direction: move up (ON), move down (OFF)

Outputs:

Sensor: 5-bit vector, where the bit K will be ONE if the elevator is on K floor, otherwise OFF

Button: 5-bit vector, Switch the bitk ON if pressed, and stay ON until the elevator arrives at K floor.

Component written by André Bigonha, Ulisses Chippe, Giliardo Freitas and Ricardo Ferreira, DPI, Universidade Federal Vicosa, Brazil, cacau@dpi.ufv.br

// Elevator controller (5 floors) with PIC16F84 for Hades webdemos.
// Also demonstrates how to implement state-machines as C programs.
//
// 22.12.05 - first version (picclite+hitide)
// 
// (c) 2005 fnh  hendrich@informatik.uni-hamburg.de

#include "htc.h"


// the push-buttons that request the elevator target floor
// we map BUTTON_0=RA4 etc. to keep the schematics simple..
//
#define BUTTON_0  RA4
#define BUTTON_1  RA3
#define BUTTON_2  RA2
#define BUTTON_3  RA1
#define BUTTON_4  RA0

// the sensors that indicate which floor the elevator car
// has reached. Again we map 0-4 1-3 etc. to avoid signal
// crossing in the schematics.
//
#define SENSOR_0  RB4
#define SENSOR_1  RB3
#define SENSOR_2  RB2
#define SENSOR_3  RB1
#define SENSOR_4  RB0

// two output ports used to control the elevator motor
// (on/off) and motor direction (up/ndown).
//
#define MOTOR_ON  RB6
#define UP_NDOWN  RB7

// the elevator states: parked means waiting (at floor < i >),
// up_to and down_to imply moving to the corresponding floor.
// We force an encoding that allows you to watch the state
// during the simulation (upper nibble=1/2/4: parked/up/down),
// lower nibble=floor index, 0xff=error
// 
enum elevator_state {
  PARKED_0  = 0x10,
  PARKED_1  = 0x11,
  PARKED_2  = 0x12,
  PARKED_3  = 0x13,
  PARKED_4  = 0x14,
  
  UP_TO_1   = 0x21,
  UP_TO_2   = 0x22,
  UP_TO_3   = 0x23,
  UP_TO_4   = 0x24,

  DOWN_TO_3 = 0x43,
  DOWN_TO_2 = 0x42,
  DOWN_TO_1 = 0x41,
  DOWN_TO_0 = 0x40,
  
  UNKNOWN   = 0xff,
};

enum motor_state {
  STOP      = 0x00,
  MOVE_UP   = 0xc0,
  MOVE_DOWN = 0x80,
};


// global variables for state-machine state and motor control
// 
unsigned char state = PARKED_0;
unsigned char motor = STOP;



// inidicate an error by lighting the LED on port B.5
// (note that RB5 is also used to reset the SR-flipflops,
// but the short strobes should not be visible on a real LED.
void 
error(void) 
{
  motor = STOP;
  for(;;) {
  	RB5 = 1;
  }	
}


void
main(void)
{
	
  GIE   = 0;    // disable interrupts
  TRISA = 0x1f; // all inputs
  TRISB = 0x1f; // RB7..RB5 outputs, RB4..RB0 inputs	
  
  for( ;; ) {
  	
  	switch( state ) {
  	  case PARKED_0:
  	    if (BUTTON_1 | BUTTON_2 | BUTTON_3 | BUTTON_4) {
  	      state = UP_TO_1;
  	      motor = MOVE_UP;
  	    }
  	    else {
  	      motor = STOP;	
  	    }
  	    break;
  	    
      case PARKED_1:  	
        if (BUTTON_2 | BUTTON_3 | BUTTON_4) {
          state = UP_TO_2;
          motor = MOVE_UP;
        }
        else if (BUTTON_0) {
          state = DOWN_TO_0;
          motor = MOVE_DOWN;	
        }
        else {
          motor = STOP;
        }                 
  	    break;

      case PARKED_2:  	
        if (BUTTON_3 | BUTTON_4) {
          state = UP_TO_3;
          motor = MOVE_UP;
        }
        else if (BUTTON_0 | BUTTON_1) {
          state = DOWN_TO_1;
          motor = MOVE_DOWN;	
        }
        else {
          motor = STOP;
        }                 
  	    break;

      case PARKED_3:  	
        if (BUTTON_4) {
          state = UP_TO_4;
          motor = MOVE_UP;
        }
        else if (BUTTON_0 | BUTTON_1 | BUTTON_2 ) {
          state = DOWN_TO_2;
          motor = MOVE_DOWN;	
        }
        else {
          motor = STOP;
        }                 
  	    break;
  	       	
      case PARKED_4:  	
        if (BUTTON_0 | BUTTON_1 | BUTTON_2 | BUTTON_3) {
          state = DOWN_TO_3;
          motor = MOVE_DOWN;
        }
        else {
          motor = STOP;
        }                 
  	    break;
  	    
  	  case UP_TO_1:
  	    if (SENSOR_2 | SENSOR_3 | SENSOR_4) {
  	      error();
  	    }
  	    if (BUTTON_2 | BUTTON_3 | BUTTON_4) {
  	      state = UP_TO_2;
  	      motor = MOVE_UP;
  	    }
  	    else if (SENSOR_1) {
  	      state = PARKED_1;
  	      motor = STOP;	
  	    }
  	    else {
  	      motor = MOVE_UP;	
  	    }
  	    break;

  	  case UP_TO_2:
  	    if (BUTTON_3 | BUTTON_4) {
  	      state = UP_TO_3;
  	      motor = MOVE_UP;
  	    }
  	    else if (SENSOR_2) {
  	      state = PARKED_2;
  	      motor = STOP;	
  	    }
  	    else {
  	      motor = MOVE_UP;	
  	    }
  	    break;

  	  case UP_TO_3:
  	    if (BUTTON_4) {
  	      state = UP_TO_4;
  	      motor = MOVE_UP;
  	    }
  	    else if (SENSOR_3) {
  	      state = PARKED_3;
  	      motor = STOP;	
  	    }
  	    else {
  	      motor = MOVE_UP;
  	    }
  	    break;

  	  case UP_TO_4:
  	    if (SENSOR_4) {
  	      state = PARKED_4;
  	      motor = STOP;	
  	    }
  	    else {
  	      motor = MOVE_UP;
  	    }
  	    break;
  	    
  	  case DOWN_TO_3:
  	    if (BUTTON_2 | BUTTON_1 | BUTTON_0) {
  	      state = DOWN_TO_2;
  	      motor = MOVE_DOWN;
  	    }
  	    else if (SENSOR_3) {
  	      state = PARKED_3;
  	      motor = STOP;
  	    }
  	    else {
  	      motor = MOVE_DOWN;
  	    }
        break;

  	  case DOWN_TO_2:
  	    if (BUTTON_1 | BUTTON_0) {
  	      state = DOWN_TO_1;
  	      motor = MOVE_DOWN;
  	    }
  	    else if (SENSOR_2) {
  	      state = PARKED_2;
  	      motor = STOP;
  	    }
  	    else {
  	      motor = MOVE_DOWN;
  	    }
        break;

  	  case DOWN_TO_1:
  	    if (BUTTON_0) {
  	      state = DOWN_TO_0;
  	      motor = MOVE_DOWN;
  	    }
  	    else if (SENSOR_1) {
  	      state = PARKED_1;
  	      motor = STOP;
  	    }
  	    else {
  	      motor = MOVE_DOWN;
  	    }
        break;

  	  case DOWN_TO_0:
  	    if (SENSOR_0) {
  	      state = PARKED_0;
  	      motor = STOP;
  	    }
  	    else {
  	      motor = MOVE_DOWN;
  	    }
        break;
  		
      default:
        error();
          		
  	} // end switch(state)
 
  	// a variant of the elevator circuit uses extra SR-flipflops
  	// to make sure that the (short) pulses generated by the
  	// floor-sensors are picked up by this program loop.
  	// To reset the flipflops, we generate a short-pulse on RB5
  	// now. We can do this here, because we have just handled
  	// one iteration of the state-machine state update.
  	// The single pulse is too short to make the error LED
  	// light up visibly.
  	RB5   = 1;
  	RB5   = 0;
  	
  	// now activate the motor corresponding to the current
  	// state. We just need RB7 and RB6, but the other bits
  	// are inputs anyway.
  	PORTB = motor;

    // finally, reset the watchdog timer.   	
  	CLRWDT();  
  }
	
}

// we don't use interrupts in this program.
// 
static void interrupt
isr(void)
{
 if(T0IF) {        // timer interrupt
  	error();
  }
  else if(INTF) {  
  	error();
  }	
}

Print version | Run this demo in the Hades editor (via Java WebStart)
Usage | FAQ | About | License | Feedback | Tutorial (PDF) | Referenzkarte (PDF, in German)
Impressum http://tams.informatik.uni-hamburg.de/applets/hades/webdemos/95-dpi/pic16f84-elevator5/elevator.html