|
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
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.
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.
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.
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.
|
|