PLEASE VIEW IN MOZILLA FIREFOX v2.0.0.3

_____________________

INTERACTIVE MATERIALS

PRESENTATION

PHOTOS  ||
 VIDEO
 

_____________________

CIRCUIT DIAGRAMS

MAIN

REMOTE

_____________________

CODE LISTINGS

MAIN

REMOTE

_____________________

 

CRANE INDUSTRIES

ESE 350, Spring 2007

Riya Abraham, Anujit Shastri, Darren Wang


 

ABSTRACT

This project was designed to utilize the versatility of the Motorola 68HC11 and topics learned in the Spring 2007 semester of ESE350 through the construction of a crane.  Constructed out of k'Nex, the crane rotates via a servo motor.  The movement of the head of the crane is also controlled by a servo motor.  Input was taken from the keypad remote via infrared communication to control movement of the crane; a 4-digit LED display indicated the direction of movement; and a speaker sounds when the crane hits its weight and its structural limitations of lift. 


HARDWARE CONFIGURATION

The overall crane is comprised of two separate microcontroller systems, one concerned with the wireless transmission of IR signals to control operation, and the other primarily controlling principle crane actions (hereby referred to as remote circuit and main circuit respectively).

  Main Circuit

 The main circuit consists fundamentally of two H-bridges used to control vertical motion (raising / lowering of the crane) and lateral motion (rotation of the crane fixture). Bi-directional rotation of the motors is achieved by alternating the input values to IN1 and IN2 of the H-bridges: with IN1 high and IN2 low, M+ and M- outputs the external high and low values respectively; reversing the values to have IN1 low and IN2 high produces the same change on M+ and M-, effectively reversing the direction of the motor. This functionality, of course, is only activated when EN of the H-bridge is high, controlled via OC2 and OC3 from the HC11 microcontroller (here OC2 responsible for lateral motion, OC3 for vertical). From the hardware schematic of the main circuit, it can be seen that both H-bridges share IN1 and IN2 inputs from PD2 (HC11 pin 1) and PB7 (HC11 pin 14) respectively; EN for the lateral motion H-bridge connected to OC2 (HC11 pin 7) and EN for vertical motion H-bridge connected to OC3 (HC11 pin 8). External supplies for both H-bridges have values 9V and ground.

The crane also includes an alarm system to indicate loads in excess of the crane's ability to lift. The motor responsible for vertical motion has generator wire connections that can be measured via pulse accumulator overflow interrupt of the HC11 at the ratio of 8 pulses per motor revolution. Essentially, should the number of pulses received during operation fall below a certain threshold (trigger variable not reset in time), the piezo-speaker setup will go off. Specifically, one generator wire is grounded while the other is input to pin 1 of the 7404 Hex Inverter (Schmitt Trigger usage). The Schmitt Trigger imposes two thresholds on the signals received from the motor; only when the higher threshold is crossed does the Schmitt Trigger output high, and only when the signal then falls below the lower threshold does the Schmitt trigger output low. This setup is thus robust against noisy single signals that might otherwise be considered as multiple pulses. Output from inverter (pin 2) is input to microcontroller PA7 (HC11 pin 6). The inverter package is also powered 5V on pin 14 and grounded on pin 7. The alarm speaker setup is identical to that used in previous labs: 5kΩ resistor connected over OC4 (HC11 pin 9) and base of the 2N3904 BJT, with collector connected to 5V and emitter in series with piezo-speaker to ground.

Reception of the IR signal from the remote is enabled by the HT12D decoding circuit. For simplicity, the address bits A(0-7) are all grounded on both encoder and decoder (to ensure for successful transmission from encoder to decoder - differing address bit configurations will produce no change on the decoder output pins). Thus each packet received (as well as transmitted) contains 8 'zero' address bits and 4 data bits (based on remote input). Physical construction is as seen in the main circuit schematic: 33kΩ resistor connected over OSC2 and OSC1, 10kΩ resistor connected over VCC and DIN, with VCC node connected to pin 3 of the PNA4602M receiver module and DIN node connected to the collector of the 2N3904 BJT. Pin 2 of the PNA4602M grounded, with pin 1 connected to base of said transistor via 1kΩ resistor. Emitter of the NPN BJT grounded, VCC pin connected to 5V. Each of the decoder data bits D(8-11) are connected via 1kΩ resistors to PC(4-7) (HC11 pins 39-42) respectively.

The 4-digit 7-segment LED display provides additional functionality in actively displaying the crane's direction of motion. The entire display only has a single digit active at a time since anode segment connections are shared over the 4 digits (chosen via PC(0-3) output as determined by rtiphase in the real-time interrupt) although this is not a problem since RTI cycles every 4ms and thus produces the effect of a constant display of multiple digits. Active digit selection determined by cathode value low, where LED-display cathode pins (2, 5, 8, 10) are connected to PC(0-3) (HC11 pins 35-38) respectively. The 7-segment connections are made using current-limiting resistors between PB(0-6) (HC11 pins 21-15) and LED display pins (15, 19, 20, 3, 11, 18, 22) respectively. Here, connections are made according to the encoding system 'gfedcba' with 'a' least significant and mapped to PB0.

 Remote Circuit

The remote circuit is primarily concerned with the input and transmission of signals to control operation of the crane, and to that end is designed minimally, consisting of just keypad and encoder module. Eight keypad buttons are used, four mapped for crane motion and four for vertical lifting speed (via setting of t_high3 and t_low3, varying the duty cycle of OC3). Button '4' moves the crane laterally left, button '6' laterally right, button '2' raises the crane and button '8' lowers the crane. Lifting speeds are set via buttons A, B, C and D, in increasing magnitude of duty cycle. In the same manner as previous labs, the keypad had all pins connected to 5V through 1kΩ resistors (to limit the current), where the real-time interrupt would continually cycle through keypad rows to detect for low input to PC(4-7), equating to the depression of a button. Output selected PC(0-3) (HC11 pins 35-38) connected to keypad pins (8, 1, 2, 4) respectively, and input selected PC(4-7) (HC11 pins 39-42) connected to keypad pins (3, 5, 6, 7) respectively.

Signal transmission via IR LED is driven by the HT12A encoder taking input from the HC11 based on user-input to the keypad. All address bits are arbitrarily grounded on the encoder (similar to the decoder) to ensure that data bits are successfully transmitted (different address signatures will not process the data bits on the decoder end). The 455kHz crystal used is divided by a factor of 12 to generate trains of 12 pulses (8 address bits, 4 data bits) each modulated at 38kHz. These ‘packets’ drive the IR LED for transmission of data from emitter to decoder. Signal modulation is used as a means of shielding against unwanted interference, where the receiving end will only operate on signals modulated at a determined frequency (in this case 38kHz). Encoder data bits D(8-11) connected directly to PB(0-3) respectively. The 455kHz crystal is connected in parallel with the 10MΩ resistor over encoder pins X1 and X2, with 100pF capacitors connected from both nodes to ground. Encoder pin VCC is connected to 5V, with a 100Ω resistor in series with the IR LED coming from the VCC node to the collector of the ZTX603 Darlington transistor. Base of said transistor is connected to DOUT by 330Ω resistor, and emitter is grounded.

 

PROGRAM MODULES

Code Listing: Main || Remote

Main Circuit

Rotating Motor:

/* crane motor control (rotation) */
void OC2ISR() { // output compare interrupt 2
  TFLG1 &= 0x40; // clears OC2 flag
  if (TCTL1 & 0x40) {
    TOC2 += t_high2; // next interrupt after t_high2
    TCTL1 &= 0xBF; // high to low transition
  }
  else {
    TOC2 += t_low2; // next interrupt after t_low2
    TCTL1 |= 0x40; // low to high transition
  }
}

This interrupt controls the rotating motor on the OC2 port.  It first clears the flag for the interrupt.  It then checks if the previous output on OC2 was low by checking if the control flag was set to set or clear.  If the previous output was low (TCTL1 & 0x40 is true), then TOC2 is incremented by t_high2, the time for which the output should be high.  TCTL1 & 0xBF then changes the control bits so that the output will be high.  If the previous output was not low, then TOC2 is incremented by t_low2, the time for which the output should be low.  TCTL1 is then changed again for an output of low.  This all comes together to create a variable duty cycle output to the rotation DC motor.  For our project, we used a static t_high2 of 13000 and t_low2 of 27000, for a period of 20ms and a duty cycle of 32.5%.  This provided a speed of rotation that was not too fast or too slow. 


Lifting Motor:

/* crane motor control (lifting) */
void OC3ISR() { // output compare interrupt 3
  TFLG1 &= 0x20; //clears OC3 flag
  if (TCTL1 & 0x10) {
    TOC3 += t_high3; // next interrupt after t_high3
    TCTL1 &= 0xEF; // high to low transition
  }
  else {
    TOC3 += t_low3; // next interrupt after t_low3
    TCTL1 |= 0x10; // low to high transition
  }
}

This interrupt controls the lifting motor on the OC3 port.  It first clears the flag for the interrupt.  It then checks if the previous output on OC3 was low by checking if the control flag was set to set or clear.  If the previous output was low (TCTL1 & 0x20 is true), then TOC3 is incremented by t_high3, the time for which the output should be high.  TCTL1 & 0xEF then changes the control bits so that the output will be high.  If the previous output was not low, then TOC3 is incremented by t_low3, the time for which the output should be low.  TCTL1 is then changed again for an output of low.  This is completely identical to the code for the rotation motor on the OC2 port, but uses different numbers to create a variable duty cycle.  While they both have the same period of 20ms, instead of the duty cycle being a static 32.5% as for the rotation motor, the duty cycle is variable for the lifting motor.  This enables us to lift objects of varying weights at relatively smooth speeds.  By pressing the 4 letter buttons on the keypad, varying speeds are selected for lifting.  A corresponds to 10% duty cycle, B is 15%, C is 22.5%, and D is 30%. 

 

Weight Alarm:

/* excessive weight alarm */
void OC4ISR() {
    TFLG1 &= 0x10;
    TOC4 += alarm_half;

 This simple interrupt occurs when another part of the program enables it through its mask, by setting TMSK1 |= 0x10.  When it is locally enabled, the interrupt will create an output that causes a sound on the speaker, until the program disables the interrupt again through its mask, by setting TMSK1 &= 0xEF.  This interrupt begins by clearing its flag, and then increments TOC4 by alarm_half, a static variable in the program that is set to 3000.  The purpose of this interrupt is to make the speaker emit a sound when there is too much weight for the crane to lift, which is determined by detecting the motor not spinning despite power output to it.  This interrupt is set in another part of the program to toggle by default (TCTL1 |= 0x04).  Thus, the output is an alternating wave with period 3ms and a duty cycle of 50%. 

 

Pulse Accumulator: 

void PAOVISR() {
  TFLG2 &= 0x20;
  PACNT = 0xF0; // times for 16 pulses
  trigger = 0;
}

This is a simple interrupt to detect objects too heavy for the crane to lift.  This interrupt resets the variable trigger to 0 every time the lifting motor accumulates 16 pulses, or 2 rotations.  16 pulses are timed by setting PACNT to 0xF0, so that it takes 16 pulses for the interrupt to trigger after 0xFF.  Thus, while the motor is lifting, this interrupt is locally enabled in another part of the program.  Every time there are 2 revolutions of the motor, trigger is reset.  This enables the overall program to detect not enough revolutions in a given time period, meaning the motor cannot lift the object. 


Timer Overflow:

void TOFISR(){
  TFLG2 &= 0x80;
  overflow++;
  if ((dir == '2') || (dir == '8')){
    trigger++;
    if (trigger == 200) {
      TMSK1 |= 0x10; // enable alarm interrupt OC4
      TFLG1 &= 0x10; // clear OC4 flag
      TCTL1 |= 0x04; // set OC4 output to toggle
      TCTL1 &= 0xF7; // set OC4 output to toggle
    }
  }
  else{
    TCTL1 |= 0x08; // clear OC4 output line low
    TCTL1 &= 0xFB; // clear OC4 output line low
    TMSK1 &= 0xEF; // disable OC4
  }
}  

This interrupt occurs every time the onboard clock overflows, or every 32ms.  The interrupt first clears its flag (TFLG &= 0x80).  It then increments the variable overflow, which is used to track the number of overflows. 

Next, it checks the value of dir.  This variable holds the direction currently being pushed on the keypad.  2 corresponds to lifting the object with the crane, while 8 corresponds to dropping the object with the crane.  Thus, this if statement is only entered if the crane is currently lifting or dropping an object.  trigger is then incremented.  The next if statement is entered if trigger is 200, which occurs after about 6.5 seconds, if trigger is not reset in between.  What this does is allow the PAOVISR interrupt to reset trigger if the motor is indeed spinning while power is sent to the motor, as 2 or 8 is being pressed on the keypad.  If PAOVISR does not reset trigger because it does not detect revolutions, then after 6.5 seconds of waiting for revolutions to be detected, the if (trigger == 200) statement is true and it is entered.  TMSK1|= 0x10 enables the alarm interrupt OC4.  TFLG1 &= 0x10 clears OC4’s flag, and TCTL1 |= 0x04 combined with TCTL1 &= 0xF7 set OC4’s output to toggle.  The alarm is thus set to go off. 

If the value of dir is not 2 or 8, thus the crane is not currently trying to lift, the else statement is triggered.  This segment sets TCTL1 |= 0x08 and TCTL1 &= 0xFB, which combined clear the OC4 output line to low.  TMSK1 &= 0xEF then disables the OC4 interrupt. 

The TOFISR interrupt is mainly used for detecting whether the motor is trying to lift something too heavy.  Every 32ms, it is called, and if the crane is trying to lift something, trigger is incremented.  If 16 pulses do not make it to the pulse accumulator in 6.5 seconds, trigger does not get reset and reaches its value of 200, which triggers the alarm.  The interrupt then sets the alarm’s protocols so that OC4 is enabled and set to toggle.  Once the user releases 2 or 8, the alarm is turned off by clearing OC4’s output line and disabling it.  This is also the default occurrence of the interrupt if the crane is not trying to lift, but clearing OC4 and disabling it does not affect the rest of the program. 


LED Decoder:

/* decoder for LED display (port B7 reserved) */
void decode(char dir){
  PORTB &= 0x80;
  switch(dir){
  case '0': PORTB &= 0x80; break;
  case 'u': PORTB |= 0x3E; break;
  case 'p': PORTB |= 0x73; break;
  case 'd': PORTB |= 0x5E; break;
  case 'n': PORTB |= 0x54; break;
  case 'l': PORTB |= 0x38; break;
  case 'f': PORTB |= 0x71; break;
  case 'r': PORTB |= 0x50; break;
  case 'h': PORTB |= 0x76; break;
  }
}

This function accepts a character as a parameter and decodes it to PORTB, which is hooked up to the 4 digit LED display.  It initially sets PORTB’s right 7 bits to 0 by doing PORTB &= 0x80.  It then enters a switch statement that takes the parameter dir and examines which case it is.  The possible values are 0, u, p, d, n, l, f, r, h.  They correspond to outputs of turning the LED off, up, dn, lf, rh, which stand for up, down, left, right.  The LED displays the direction of the current rotation / lifting, where lifting is up or down, and rotation is left or right.  Each case has a corresponding PORTB configuration, whose bits represent a segment of the LED digit.  For example, if the case is ‘u’, PORTB is configured so that the LED digit displays u.  If the case is ‘0’, the LED is turned off.  This function provides an easy way to quickly change the value of an LED without having to repeat code. 


RTI:

// RTI mainly keypad + LED display (for direction)
// lateral motion via OC2, vertical motion via OC3
void RTIISR() {
  TFLG2 &= 0x40; // clears RTI flag
 
  if (rtiphase==0){
    PORTC=0x0E;        // LED cathode 1 'on' (MSD)
    // '2' pushed, motion vertical (UP)----------------
    if (PORTC==0x4E) {
      TMSK1 |= 0x20; // turns on lifting motor
      dir = '2';
      PORTD |= 0x04; // turns lifting direction to up 
      PORTB &= 0x7F; // turns lifting direction to up
      count = 5;
    } //-----------------------------------------------
    /* vertical speed 1 (A) */
    else if (PORTC==0x9E){t_high3 = 4000; t_low3 = 36000;}
    decode('0');
  }
 
  else if (rtiphase==1){
    PORTC=0x0D; // LED cathode 2 'on'
    // '4' pushed, motion lateral (LEFT)---------------
    if (PORTC==0x1D) {
      TMSK1 |= 0x40; // turns on rotation motor
      dir = '4';
      PORTD |= 0x04; // turns rotation direction to left
      PORTB &= 0x7F; // turns rotation direction to left
      count = 5;
    } //-----------------------------------------------
    // '6' pushed, motion lateral (RIGHT)--------------
    else if (PORTC==0x2D) {
      TMSK1 |= 0x40; // enables rotation motor
      dir = '6';
      PORTD &= 0xFB; // turns rotation direction to right
      PORTB |= 0x80; // turns rotation direction to right
      count = 5;
    } //-----------------------------------------------
    /* vertical speed 2 (B) */
    else if (PORTC==0xAD){t_high3 = 6000; t_low3 = 34000;}
 
    if (dir != '0'){
      if (dir == '2') decode('u');
      else if (dir == '8') decode('d');
      else if (dir == '4') decode('l');
      else if (dir == '6') decode('r');
    }
    else decode('0');
  }
 
  else if (rtiphase==2){
    PORTC=0x0B; // LED cathode 3 'on'
    // '8' pushed, motion vertical, (down)-------------
    if (PORTC==0x8B) {
      TMSK1 |= 0x20; // enables lifting motor
      dir = '8';
      PORTD &= 0xFB; // turns lifting direction to down
      PORTB |= 0x80; // turns lifting direction to down
      count = 5;
    } //-----------------------------------------------
    /* vertical speed 3 (C) */
    else if (PORTC==0xCB) {t_high3 = 9000; t_low3 = 31000;}
   
    if (dir != '0'){
      if (dir == '2') decode('p');
      else if (dir == '8') decode('n');
      else if (dir == '4') decode('f');
      else if (dir == '6') decode('h');
    }
    else decode('0');
  }
 
  else if (rtiphase==3){
    PORTC=0x07; // LED cathode 4 'on'
    /* vertical speed 4 (D) */
    if (PORTC==0xD7) {t_high3 = 12000; t_low3 = 28000;}
    decode('0');
  }
 
  if (++rtiphase > 3) rtiphase = 0;
  if (--count <= 0){
    dir = '0';
    TCTL1 &= 0xAF; // clears output from OC2 & OC3 low
    TMSK1 &= 0x9F; // disconnects output compare interrupts
    count = 0;
    trigger = 0;
  }
}
 

This interrupt occurs constantly and controls the interfacing of the IR system and keypad to the program.  It also controls the interfacing with the LED display.  It begins by clearing its flag (TFLG2 &= 0x40).  In the main program, the statement DDRC = 0x0F sets the left 4 bits of PORTC to inputs and the right 4 bits of PORTC to outputs.  DDRC = FF sets all digits of PORTD to outputs.

Next, it checks the value of rtiphase.  If it is 0, it enters the first segment.  PORTC=0x0E sets the LSB of PORTC low.  It then checks PORTC’s first 4 bits by checking the truth of PORTC==0x4E.  The left 4 bits of PORTC are inputs and are controlled by the IR decoder.  They come from the remote’s IR encoder and correspond to the encoded value.  When a button on the remote’s keypad is pressed, an encoded value is sent through IR to the decoder at the current HC11 and it is decoded, then sent to PORTC.  Thus, the left 4 bits of PORTC correspond to various button presses on the remote’s keypad.  PORTC==0x4E is true if the 2 button is pressed on the keypad.  Since this button is supposed to lift the object, the code following this if statement does just that.  TMSK1 |= 0x20 turns on the lifting motor.  dir is given the value 2, as dir always holds the value of the button being pressed.  The next two lines, PORTD |= 0x04 and PORTB &= 0x7F control the 3rd bit of PORTD and the 8th bit of PORTB.  These ports connect to the two H-Bridges and control the direction of the motor.  10 for these bits corresponds to left / up, while 01 corresponds to right / down.  They can be connected for both since the motors are never on simultaneously.  The next else if statement, else if (PORTC==0x9E), occurs if the A button is pressed.  The letter buttons control the speed of the lifting motor, so they change the value of t_high3 and t_low3.  Finally, decode(‘0’) makes the value of the left most LED digit off, since it is never used. 

If rtiphase is 1, 2, or 3, similar occurrences happen as if rtiphase was 0.  It checks whether buttons 2, 4, 6, or 8 are pressed, and turns on the corresponding motor in the correct direction.  If A, B, C, or D is pressed, the values of t_high3 and t_low3 are changed accordingly.  In addition, the 4 digit LED display receives different decoded bits for each part of rtiphase.  Since only 1 bit of PORTC’s output pins is low at a time, that LED digit is changed at that time.  Thus, each iteration of rtiphase controls 1 digit on the LED display.

At the bottom of the interrupt, rtiphase is incremented and if it is incremented to 4, it is reset to 0.  Additionally, there is a variable count that is set to 5 each time a directional key is pushed.  This value is decremented each time the interrupt is called and if it reaches 0, the motors are turned off and trigger and count are reset.  The reason for this variable is that the directional button on the keypad will only be detected every 4 iterations of the interrupt, as rtiphase does not try to detect the corresponding number of the button press each time.  This ensures that the motor is not turned off prematurely, as if count were not there, the motor would turn off for 3 out of every 4 iterations of the interrupt’s calling. 

 

Remote Circuit

Timer Overflow:

void TOFISR(){
  TFLG2 &= 0x80;
  overflow++;
}

This simple interrupt keeps track of time in overflows.  It begins by clearing its flag, and then increments overflow. 

 

RTI:

/* keypad control for remote */
void RTIISR() {
  TFLG2 &= 0x40; // clears RTI flag
 
  if (rtiphase==0){
    PORTC=0x0E;
    // '2' pushed, motion vertical (UP)----------------
    if (PORTC==0xDE) {
      dir = '2';
      PORTB = 0x04;
      count = 5;
    } //-----------------------------------------------
    /* vertical speed 1 (A) */
    else if (PORTC==0x7E){PORTB = 0x09; count = 5; dir = 'A';}
  }
 
  else if (rtiphase==1){
    PORTC=0x0D;
    // '4' pushed, motion lateral (LEFT)---------------
    if (PORTC==0xED) {
      dir = '4';
      PORTB = 0x01;
      count = 5;
    } //-----------------------------------------------
    // '6' pushed, motion lateral (RIGHT)--------------
    else if (PORTC==0xBD) {
      dir = '6';
      PORTB = 0x02;
      count = 5;
    } //-----------------------------------------------
    /* vertical speed 2 (B) */
    else if (PORTC==0x7D){PORTB = 0x0A; count = 5; dir = 'B';}
  }
 
  else if (rtiphase==2){
    PORTC=0x0B;
    // '8' pushed, motion vertical, (down)-------------
    if (PORTC==0xDB) {
      dir = '8';
      PORTB = 0x08;
      count = 5;
    } //-----------------------------------------------
    /* vertical speed 3 (C) */
    else if (PORTC==0x7B) {PORTB = 0x0C; count = 5; dir = 'C';}
  }
 
  else if (rtiphase==3){
    PORTC=0x07;
    /* vertical speed 4 (D) */
    if (PORTC==0x77) {PORTB = 0x0D; count = 5; dir = 'D';}
  }
 
  if (++rtiphase > 3) rtiphase = 0;
  if (--count <= 0){
    dir = '0';
    PORTB = 0;
    count = 0;
  }

This RTI interrupt is called constantly.  It begins by clearing its flag (TFLG2 &= 0x40).  Next, it checks the value of rtiphase.  If it is 0, it enters the first if statement segment.  In the main program, DDRC = 0x0F has already assigned C0-C3 as outputs and C4-C7 as inputs.  Therefore, PORTC=0x0E sets port C0 low and C1-C3 high.  Since ports C0-C3 are assigned to rows of the keypad and C4-C7 are assigned to columns of the keypad, the button being pressed can be detected by setting a row low and checking which column is low.  Since C0 is low, if PORTC=0xDE, that means the second column in the first row, or key 2, is being pushed.  dir is assigned the button, 2 in this case.  The next line, PORTB = 0x04, sets the value of PORTB to 0x04.  PORTB’s 4 right bits, B0-B3, are connected to the IR circuit’s encoder.  Thus, each unique combination of PORTB corresponds to a different signal sent by the remote to the main HC11.  count is set to 5, so like in the other program, PORTB isn’t reset to 0 even if the rtiphase value prevents the current button being pressed from being detected.  count must decrement in each rtiphase value for PORTB to turn off. 

This same process is repeated to check if 2, 4, 6, 8, A, B, C, or D is being pressed.  Each of these keys then assigns a unique value to PORTB, which is encoded in a signal that is sent to the main circuit’s decoder via IR. 

At the end of the RTI interrupt, rtiphase is incremented.  If it goes higher than 3, it is reset to 0.  This ensures that rtiphase cycles through 0, 1, 2, 3, 0, 1, etc.  If count decrements to 0, that means it has been through all the rtiphase iterations and no button press has been detected, so dir, PORTB, and count are reset. 

 

CONCLUSION

Participants of this project gained experience working with the circuitry of the motherboard, keypad, servo motor, h-bridges, electret microphone, 4-digit LED display, and C Programming. By means of accurate programming and proper circuitry, participants of this lab utilized several interrupts and functions which are summarized below.
 

  • OC2 – Rotating tower

  • OC3 – Vertical Motion

  • OC4 – Sound

  • Pulse Overflow – Load Over Maximum Weight Limit

  • Wireless

  • LED directional movement