electromechanical arithmetic logic unit · an arithmetic logic unit (alu) is a component of any...
TRANSCRIPT
Electromechanical Arithmetic Logic Unit
Design Report
5/8/2009
David Bober
E90: Senior Design
Advised by:
Prof. Cheever
Prof. Moreshet
Abstract
The Electromechanical Arithmetic Logic Unit (EmALU) implements a 4‐bit ripple carry adder
using mechanical logic gates. Its primary functions are education and amusement, providing a highly
visual and physically intuitive representation of digital logic. Binary values are represented by the flow of
ball bearings through the device. Each logic gate is entirely controlled by the forces exerted by these ball
bearings. A microcontroller regulates both the mechanical adder and a user interface, the latter being
composed of a keypad and Liquid Crystal Display (LCD). This unusual adder implementation should help
illustrate the abstract principals of digital logic and provide an interesting comparison to more
conventional integrated circuit approaches. Mechanical logic also has strong parallels in microfluidic
technology.
Table of Contents
Abstract ......................................................................................................................................................... 2
Introduction .................................................................................................................................................. 4
Background ................................................................................................................................................... 5
Design ............................................................................................................................................................ 8
Mechanical Adder ................................................................................................................................. 8
Electromechanically Adder Actuation ................................................................................................. 12
Microelectronic Adder Controller ....................................................................................................... 15
Microcontroller Programming ............................................................................................................ 20
Testing and Results ..................................................................................................................................... 22
Conclusions ................................................................................................................................................. 22
Bibliography ................................................................................................................................................ 23
Appendix A .................................................................................................................................................. 24
Introduction
An arithmetic logic unit (ALU) is a component of any microprocessor, being responsible for
logical evaluations and arithmetic computations, such as addition, subtraction, division and
multiplication. An ALU is typically constructed as an integrated circuit, which implements the desired
functionality with Boolean logic created by transistor gates. The design of such Boolean logic is the focus
of E15/CS24: Fundamentals of Digital Systems, which studies logic abstracted from its physical
implementation. This device seeks to compliment the ideas of E15 with a physical model of digital logic.
The operation of the mechanical gates is clearly visible and the centerpiece of the project. The user can
visually track the flow of bearings and see the operation of half, full, and ripple carry adders.
At the beginning of an operation, the user enters the desired operands using a keypad (see label
1 on figure 1), connected to the microcontroller (2), and the input is displayed on a small LCD (3). When
input is complete, the device allows bearings to drop into the mechanical logic array (4), starting the
computation. The input of ball bearing is controlled by a row of solenoids (5) that retract to allow ball
bearings to fall. The balls complete the operation by flowing downward under the force of gravity. As
Figure 2: MeALU SchematicFigure 1: Complete EmALU
the ball bearings approach the bottom of the device, their flow is electronically measured by their
passage through photointerrupter slots (6). An Auger (7) then lifts the ball bearings to the top of the
device to reset for the next calculation. These steps are illustrated schematically in figure 2.
Background
The addition of binary numbers follows a simple algorithm nearly identical to more familiar
decimal addition. Starting with the least significant bits, the operands are added and the most significant
bit of their sum is carried over and added to the next most significant operand bits, while the least
significant sum bit becomes the output sum. While complicated to describe in words, the procedure is
easy to grasped with an example, such as shown in Table 1 for Sum=A+B where, A=0011 and B=1011.
The subscripts indicate the digit, with A0 being the least significant bit (20). Binary addition of one bit
numbers can be easily described with Boolean logic, as shown in Table 2. The logical expressions for the
carry ‘C’ and sum ‘S’ are can be written as Ci+1 = Ai*Bi and Si =Ai∆Bi.
Table 1: Binary Addition Example 0011+1011
Carryi 04 03 12 11
Ai 03 02 11 10
Bi 13 02 11 10
Sumi 04 13 12 11 00
Table 2:1‐bit Binary Addition (half adder)
Ai + Bi = Ci+1 Si 0i + 0i = 0 i+1 0 i 0i + 1i = 0 i+1 1 i 1i + 0i = 0 i+1 1 i 1i + 1i = 1 i+1 0 i
Itrepresentoperation
To
adder is u
single bit
4 and 5. M
simplest c
ripple car
significant
delay. In t
results fo
is also often ts a logical gans, whose sym
o add two sin
used, its logic
numbers to b
Multiple full a
configuration
ry adder is re
t bits be sum
the time befo
r more signifi
Fig
convenient tte. The logicambols and def
ngle bit numb
was shown in
be summed a
dders can be
, shown in fig
elatively slow
med first. Eac
ore all less sig
icant bits, cal
gure 4: Half Add
to represent tal system in thfining truth ta
Figure 3
bers and creat
n table 2. Com
nd yield a sum
e used to add
gure 6, is calle
because the
ch logical ope
nificant bits a
led propagati
er
this Boolean lhis device useable are show
3: Logic schema
te a two bit o
mbining two h
m and a carry
two n‐bit num
ed a ripple ca
accurate add
eration requir
are added, th
ion error.
logic as a schees only the ‘Xwn figure 3.
tic
output, the log
half adders in
y. Both types
mbers and pr
rry adder. Alt
dition of each
res some finit
e ripple carry
Figure 5: Fu
ematic, wherXOR’, ‘AND’ an
gical combina
nto a full adde
of adder are
roduce an (n+
though easy t
bit requires t
te time, called
y adder will p
ull Adder
re each symbond ‘OR’
ation called a
er allows thre
shown in figu
+1) bit output
to construct,
that all less
d propagation
roduce erron
ol
half
ee
ures
t. The
the
n
neous
Figure 6: 2 bit Ripple Carry Adder
Design
Mechanical Adder
The design of the mechanical ripple carry adder was the most novel aspect of the project. The
adder functions through the flow of ball bearings through logic gates. A major design goal was to have
electrical components only at the input and output of the adder, which requires each gate to operate
only by the force exerted by the balls flowing through it. To simplify the design, the decision was also
made to propel the ball bearings with only the force of gravity and no external pressure. A ripple carry
adder was selected because it is the simplest digital adder. This section will largely concern the design of
mechanical logic gates and their assembly into an adder.
Existing microfluidic technology was used as a starting point for design. These systems use fluid
flow through 1‐100 micrometer wide channels to perform a huge range of functions, including Boolean
logic. They are of current interest in a number of fields, particularly chemistry and biology where they
have the potential to dramatically shrink the scale of reactors. Microfluidic logic gates normally have no
moving parts and are operated by fluid pressure, inertia being irrelevant at the very low Reynolds
numbers found in micron scale channels (P. Tabeling 2005). Treating the ball bearings as a simple fluid,
the only types of force available to operate the gates will be inertial and hydrostatic, which simplifies the
Bernoulli equation to V2/2+gz=constant, where V=velocity, z=head, g=gravity. Unfortunately, the flow of
ball bearings is highly non‐Newtonian and the use of the Bernoulli equation is limited to helping
conceptualize the problem. Ball bearings flow as a granular material, which exhibit very complicated
dynamics that vary greatly with flow rate and pressure. Luckily, these flows are of significant interest to
several fields of engineering, including geotechnical, and are heavily studied. Among the relevant
granular flow phenomena is their ability to elastically resist small shear stresses before plastic flow
begins. Simply put, the material will act as a solid when under low shear stress and then begin to flow
under higher stress. Granular materials also exhibit a property called dilatancy, which means that the
bulk material must expand before motion can begin. The combined effect of these phenomena is to
cause granular materials to tend to clog when confined (Ristow 2000).
The design progressed by exploring the possible gates that could be used to construct a half
adder, the basic unit of a ripple carry adder. This required the selection of the proper logical basis.
While the AND/OR/INV logical basis is widely known, there are many other equivalent systems that are
often more convenient. Digital computers typically use NAND or NOR logic because it is easiest to
implement with transistors. For the mechanical adder, inverters were ruled out because of the obvious
difficulty of outputting a flow of ball bearings when there is no inflow. This suggested the choice of the
XOR/AND/OR, as shown in the preceding section. This basis is convenient because it was suspected that
each gate would be relatively simple to construct and only two gates per half adder would be required.
This system is also logically complete, which means that it can be used to express any Boolean function1.
This system is also particularly appealing because early prototypes showed the XOR/AND functions had
significant potential to be combined into a single gate, as will be discussed later. Assuming such a
combination of AND and XOR is possible, a half adder which functions as shown in figure 7 can be
produced.
Figure 7: XOR/AND Half Adder.
1 Given that AND/OR/INV is known to be complete, XOR/AND/OR can be shown to be complete by demonstrating its
equivalence to AND/OR/INV. This is proved by the fact that x’ =x∆1.
An iterative design process was used to implement this system. Initial gate sketches were
created in SolidWorks tm and then cut out of foam using the Roland Modela 3D Printer tm. ¼ inch Ball
bearings were selected because of their convenient size and very low cost. This rapid prototyping
allowed the easy assessment of many different designs. Gates without moving parts, similar to those
used in fluidics, were considered appealing because of their simplicity. These gates were to work by the
inertia of the ball bearings and the different trajectories produced when streams collided. They were
each intended to work as shown above in figures 8‐10. Although functional gates were produced, they
were unreliable and highly dependent on incoming ball velocity (as one could have predicted from
M=m*v and Ke=m*v^2). They were also limited by the highly elastic ball collisions and unpredictable
ricochets.
The next series of attempts introduced a pivoting bell shaped piece to separate the incoming
flows and control the unpredictable collisions. Under the new design, the movement of the bell was
produced by the force of the incoming balls and its resulting position controlled the output. This design
proved much more successful and is used in the final device. Figures 11 and 12 show the final half adder
design. Note that in the event of an AND operation, one of the inputs is discarded and the other
continues. This has no effect on the logical value but helps prevent jamming by lessening the
constriction of flow. All that remained to produce a full adder was the addition of another ‘OR’ gate.
‘OR’ gates operating on ball bearings are surprisingly difficult to design because of the tendency of the
balls to jam when constricted, as discussed earlier. Fortunately, in the ripple carry adder, there is never a
Figure 10: Half Adder ‐ XOR Figure 9: Half Adder ‐ ANDFigure 8: Half Adder ‐ XOR
case where both inputs to any OR gate are high. This greatly reduces the possibility of jamming and
allows for the full adder design shown in figures 13‐16. These Full Adders were then simply connected to
form a ripple carry adder.
Figure 13: A+B+B=CS where, A0=1, B0=0, C0=0 C1=0, S1=1
Figure 14: A+B+B=CS where, A0=1, B0=1, C0=0 C1=1, S1=0
Figure 12: Half Adder ‐ ANDFigure 11: Half Adder ‐ XOR
Electromechanical Adder Actuation
The mechanical adder requires several other supporting components to functions properly.
Mechanisms must be provided to release the ball bearings into the device, sense their passage at the
bottom of the device, and also the lift them back to the top once an operation is complete. Each of
these systems must also be able to be coordinated by the microcontroller. Their designs are discussed
below.
Each input control device must be capable of starting or stopping the flow of bearings very
quickly to ensure proper device timing. Solenoids are the ideal choice because of their fast response
time, low cost and simple operation. Solenoids, see figure 17, function by linear actuation of a ferrous
core with a magnetic field produced by a surrounding wire coil. With the bearings initially stored in
vertical columns above each input, solenoids with specially made plungers could be used to alternately
Figure 16: A+B+B=CS where, A0=1, B0=1, C0=1 C1=1, S1=1
Figure 15: A+B+B=CS where, A0=1, B0=0, C0=1 C1=1, S1=0
block or permit ball bearing input. This mechanism was initially prone to jamming, but was quickly fixed
by allowing more clearance between the plungers and the adder body.
Figure 17: Solenoid (Photo from: http://media.digikey.com/photos/Pontiac%20Coil%20Inc%20Photos/F0483A.jpg)
The output of the adder must be converted to an electrical signal for the controller to read it.
These transducers must register a low value unless a sufficient flow of bearings passes, in which case it
registers high. Initially, a row of mechanical snap‐lever switches was installed 1.25 inches from the
bottom of the output channel. If a flow of 5 or more bearing passed, the switches would be activated.
This approach was problematic because the highest sensitivity switches economically available produced
jams because of the force needed to activate their levers. Also, the high‐low threshold was fixed by their
position and limited the devices robustness. These mechanical switches were replaces with
photointerrupter slots. Each slot is composed of an infrared LED and phototransistor separated by 0.3
inches, see figure 18. When a balls pass through this slot the phototransistor changes state. Each slot
has a response rate of 3kH and is therefore capable of detecting the passage ball bearings in continuous
contact at any speed below 20mph. The microcontroller simply counts the number of balls which have
passed and compares it to a programmable high‐low threshold, which can be adjusted for maximum
accuracy.
Figure 18: Photointerrupter (Photo from: http://media.digikey.com/photos/Omron%20Elect%20Photos/EE‐SX3070,EE‐SX4070.jpg)
Once a computation is complete, the ball bearings must be lifted to the top of the device. This is
accomplished with a screw auger, similar to an Archimedes Screw. At the bottom of the device, the
balls fall into a channel whose bottom is formed by the top of a custom manufactured screw, see figure
19. The screw was cut with a .126” radius thread profile, allowing ball bearings to seat in the thread
root. Rotating the screw forces the balls above it to move horizontally. At the end of the screw is a
curved channel leading to the top of the device. The auger forces balls into this channel, which produces
an upward displacement of those balls already in the channel. The screw pitch is 4 threads per inch,
meaning that each ball is moved ¼” per revolution. This pitch was selected because it is the fastest helix
which can be produced in the Engineering Department shop. The maximum number of balls ever
released is 64, equivalent to 16 inches. This implies that a maximum of 64 revolutions will be needed to
reset the device. To keep reset time to below the arbitrary goal of 20 seconds, a motor capable of 300
RPM was selected. The motor is coupled to the auger with two small set screws. The auger is supported
by two ball bearing pillow blocks. Ball‐type bearings were selected because of the need to resist modest
thrust forces from the mass being lifted.
Figure 19: Auger
Microelectronic Adder Controller
The EmALU components require significant coordination and precise timing. The keypad and
LCD of the user interface also need processing to communicate with the adder. Some sort of
programmable microelectronic computer is the obvious choice for these requirements. Although a PC
could be used, a microcontroller is preferable because of its low cost and simple I/O. The ease with
which they can be re‐programmed is also invaluable. The decision to design and construct a custom
microcontroller board rather than use a prefabricated one was dictated by both practical and
educational reasons. Although microcontroller development boards are readily available, they are
expensive and would have required significant modification to interface with the required peripherals.
The additional educational value of starting from scratch made it an easy choice.
The design of the microcontroller board began by completing the specifications for the devices it
would control. This list of peripherals, shown in Table 3, was used to select the proper Microcontroller
to meet the I/O demands.
Table 3: Peripheral devices
Peripheral Requirements Number required
LCD 1 serial transmit pin 1
Keypad 8 pins with 4 pull‐ups 1
photointerrupter 1 pin with pull up 5
Solenoid On/Off 12V and 2oo mA 8
Motor On/Off 12V and 3oo mA 1
The Microchip PIC16f877 tm was selected because it supplied an ample number of I/O pins
without the need for complications such as multiplexing. This chip has the added advantage of being
identical to those used in E15 laboratories and is therefore well supported by the departments
development infrastructure and knowledge base. With the chip selection complete, the supporting
architecture was developed in Multisim. For a PIC to operate, it must be provided with proper power
and ground connections as well as the necessary programming connections, in this case with an RJ12
connector. This chip model also requires an external oscillator. Figure 20 shows the PIC with only these
supporting features in place.
Figure 20: Minimum PIC microcontroller circuit.
The LCD selected operates by serial transmission and therefore requires only 1 pin and is
relatively easy to program, see figure 21. The only significant drawback is that the only Serial Transmit
pin must be reserved for it. The remainder of the pins were assigned in blocks to operate the other
devices.
Figure 21: LCD
The photointerrupter connections required the addition of weak pull‐up resistors to ensure a
stable high signal, shown in figure 22. The purpose of these resistors is to maintain a high voltage to the
input pins until the switch is closed and they are grounded. This prevents the pins from floating at
intermediate values while the switch is open. Although the PIC contains several internal pull‐ups, there
were not a sufficient number. The photointerrupter slots also require one resistor be soldered to each
to limit the LED current, their internal circuit is shown in figure 23.
The keypad also requires that half of its inputs be connected to pull‐ups. It operates on a matrix
encoded system where pressing a key shorts two of the inputs, the schematic and decoding table are
included in figure 24 and figure 25. Input is sensed by successively setting each column high and
scanning the row outputs. The decoding table can then be used to determine which key has been
pressed.
Figure 24: Keypad schematic (from http://tntech.edu/me/courses/Canfield/me4370/labs/calculator/index.html) Figure 25: Keypad decoding table (from ACT‐07‐
30008‐000 data sheet)
Figure 23: Internal circuit of Photointerrupter. From Omron EE‐SX3070/‐SX4070 Manual Figure 22: Pull‐up Circuit
The solenoid and motor outputs all require significantly more current than the 25 mA each PIC
pin can supply. These pins were equipped with simple MOSFET amplifier circuits to boost the available
current, shown in figure 26. The diode, acting as a ‘snubber diode,’ prevents the high voltage created by
the inductive loads from damaging the system.
Figure 26: amplifier schematic.
After the entire microcontroller circuit was designed in schematic form, it had to be transferred
to the Ultiboard tm CAD tool to develop a design for the printed circuit board (PCB). Components from
the standard Multisim tm library contain their physical footprint, which is used by Ultiboard tm to place
the necessary thru‐holes. Custom components and footprints can also be defined. The user then places
each component footprint in the desired location on the PCB. The wire traces are generally routed
automatically, although the user can intervene. The trace thickness is calculated with any number of
simple online applets2. This design required the use of separate digital and analog ground networks
because of the high current sent to ground by the solenoids and motors. The completed layout is shown
in figure 27. The PCB design flies were then sent to Advanced Circuits for fabrication. Upon receipt of the
board, the requisite components were soldered into place. The assembled board, with keypad and LCD
attached, is shown in figure 28.
2 One such calculator is found at http://www.circuitcalculator.com/wordpress/2006/01/31/pcb‐trace‐width‐calculator/
Figure 27: PIC Board Layout
Figure 28: Assembled PIC Board
Once the board was fabricated and put into use, three small design errors surfaced. Firstly, one
of the pins assigned to the keypad is open drain and therefore unable to be set high. Although this is
stated in the PIC documentation, it is not emphasized and was overlooked. The addition of a pull‐up
resistor successfully solved the problem. Secondly, the linear voltage regulator used became excessively
hot when powering the LCD and receiving a 12 volt input. This problem was corrected by changing to a
more expensive switching regulator made by Dimension Engineering. Lastly, the photointerrupters
required a 5 volt input which had not been provided because the original design called for mechanical
switches. The problem was solved by soldering an addition group of header pins to the 5 volt trace.
Microcontroller Programming
The microcontroller requires programming to determine its behavior. This software was
developed in PIC C and served to coordinate the device. Figure 29 is a flow chart summarizing the basic
functioning of the software, with the full code found in Appendix A. The program’s default state is to
scan the keypad for input. When a key is pressed, the keypad determines which key it is and then acts
accordingly. While scanning the keypad, the software acts to ‘de‐bounce’ the signal, or filter noise
occurring when a key is pressed. This reduces the occurrence of unintended double key presses and
inaccurate readings. If a numeral or operand is pressed, then the program adds the character to a string.
If the clear key is pressed, then the input string is initialized to null values. Once the ‘Enter’ key is
pressed the software processes the input string and activates the correct solenoids. The solenoids are
activated with a precise timing to control the number of balls released and compensate for the adder’s
inherent propagation delay. The software also then begins to scan the photointerrupter slots to read the
devices output. After a set delay, the sum is returned. The Reset function turns on the auger motor to
lift the bearings to the top of the device.
Figure 29: Software Flowchart
Testing and Results
The device’s reliability was tested for a number of different scenarios. The cases tested and the
resulting reliability statistics are shown in table 4. In general, the device exhibits good reliability (>95%)
for the addition of two operand bits, regardless of their values (0000b +0001b and 0001b +0001b). The
carry function is also reliable when added to a bit equal to zero (0001b +0001b). The carry degrades in
accuracy when added to a non‐zero bit (0011b +0001b). This is because the carry often arrives at the next
full adder slightly ahead or behind the next operand bits because of the propagation delay. When the
ball bearings enter the AND/XOR gate non‐simultaneously, they tend to jam and not compute properly.
This problem cannot be corrected by delaying the input of the next operands because the random
variation in the time needed to compute the carry is greater than the tolerance of the full adder’s need
for simultaneous input. The serial carry probabilities are not independent because the timing errors
compound, leading to very poor reliability for multiple serial carries (0111b +0001b). Nonetheless, the
device performs well for operations that have a low number of Carry + non‐zero operand steps, such as
1010b+1001b.
Table 4: Reliability Statistics
Operation Reliability
0000b + 0001b 98%
0001b + 0001b 95%
0011b + 0001b 60%
0111b + 0001b 25%
Conclusions
The device accomplishes all of its major design goals, although with less reliability than hoped.
The EmALU successfully demonstrates a mechanical implementation of digital logic and a simple ALU.
The mechanism is clearly visible and hopefully relatively easy to comprehend. The user interface
provides an easy input and output, while the microcontroller adds significant flexibility. Were
development to continue, the mechanical portion would need to be improved to increase reliability.
Jamming could be prevented by introducing greater ball velocities with a taller device and less extreme
bends. Changing the adder’s material to a hard and smoother plastic would reduce wall friction and also
improve performance. One could also imagine a number of possible alternate gate designs.
Bibliography
P. Tabeling, Suelin Cheng. Introduction to Microfluidics. Oxford University Press, 2005.
Ristow, Gerald H. Pattern Formation in Granular Materials. Springer, 2000.
Appendix A: Microcontroller PIC C Code
/* this code controls the microcontroller for the mechanical ALU. created by DBober 2‐12‐2009 last modified Sunday April 26th E90 */ #include "H:\E90\software\version 2\PIC_control.h" /* move LCD cursor to bottom line */ void new_line() { delay_ms(5); fputc(0xFE, use_LCD); // move to second line delay_ms(5); fputc(0x45, use_LCD); delay_ms(5); fputc(0x40, use_LCD); delay_ms(5); } /* blink LCD cursor */ void crsr() { delay_ms(5); fputc(0xFE, use_LCD); // set cursor delay_ms(5); fputc(0x4B, use_LCD); delay_ms(5); } /* clear LCD */ void clc() { delay_ms(5); fputc(0xFE, use_LCD); //clear delay_ms(5); fputc(0x51, use_LCD); delay_ms(5); } /* display help file */ void help() { clc(); fprintf(use_LCD, "There is no help"); }
/*initializes ALU such that solenoids and motor are off */ void init() { int const sol_A[4] = {PIN_E2, PIN_C1, PIN_C3, PIN_D1}; int const sol_B[4] = {PIN_C0, PIN_C2, PIN_D0, PIN_D2}; int const motor = PIN_D3; int bit; output_low(motor); for (bit=0; bit<=4; bit++) { output_low(sol_A[bit]); output_low(sol_B[bit]); } clc(); crsr(); } /* clears entry string and entry index */ void clear_str(int *str) { int k = 0; for(k = 0; k<=6; k++) { str[k] = '\0'; } } /* converts string of characters into 1 decimal number */ int str2dec(int *str, int *L) { int i = 0; int power = 1; int dec = 0; for(i = L; i > 0; i‐‐) { dec = dec + (str[i‐1]‐'0')*power; power = 10 * power; } return dec; } /* parses input string into decimal operand and operator */ int str2op(int *key_str, int *dec_A, int *dec_B) { int a = 0; int b = 0;
int k = 0; int op = '\0'; int str_A[6] = {'\0','\0','\0','\0','\0','\0'}; int str_B[6] = {'\0','\0','\0','\0','\0','\0'}; for(k = 0; k <=6; k++) { if(key_str[k] == '\0') break; if(key_str[k] == '+') { op = '+'; k++; } if(op == 0) { str_A[a] = key_str[k]; a++; } if(op != 0) { str_B[b] = key_str[k]; b++; } } *dec_A = str2dec(str_A, a); *dec_B = str2dec(str_B, b); if(*dec_A > 15 || *dec_B > 15) return 0; else return 1; } /* activate proper solenoids and read photointerrupters */ int fire(int *dec_A, int *dec_B) { int const sol_A[4] = {PIN_E2, PIN_C1, PIN_C3, PIN_D1}; int const sol_B[4] = {PIN_C0, PIN_C2, PIN_D0, PIN_D2}; int const switches[5] = {PIN_B4, PIN_B2, PIN_B1, PIN_B0, pin_D7}; int off_bit = 0; int on_bit = 0; int period = 30; //ms (time between bits) int phase_shift = 60; //ms (time each solenoids is on) (4 balls at 140) int count_off; int count_on; int read_bit; int result = 0; int prev_state[5] = {0, 0, 0, 0, 0}; int ball_count[5] = {0, 0, 0, 0 0};
count_on = phase_shift; count_off = 0; setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); set_timer1(0); while( (on_bit < 4) || (off_bit < 4)) { if(get_timer1() >= 1000) { count_on++; count_off++; set_timer1(0); } if(count_on >= period) { if(bit_test(*dec_A, on_bit)) output_high(sol_A[on_bit]); if(bit_test(*dec_B, on_bit)) output_high(sol_B[on_bit]); on_bit++; count_on = 0; } if(count_off >= period) { output_low(sol_A[off_bit]); output_low(sol_B[off_bit]); off_bit++; count_off = 0; } for(read_bit = 0; read_bit<=4; read_bit++) { if(!input(switches[read_bit])) { if(prev_state[read_bit] == 1) { ball_count[read_bit]++; } prev_state[read_bit] = 0; } else { prev_state[read_bit] = 1; } }
} for(read_bit = 0; read_bit<=4; read_bit++) { if(ball_count[read_bit] >= 3) { bit_set(result, read_bit); } } return result; } /* resets ALU by turning on auger motor */ void reset() { int const motor = PIN_D3; int time; time = 0; output_high(motor); delay_ms(5000); output_low(motor); } /* scans keypad, returns only when valid (debounced) keystroke is detected.*/ int scan_keys() { int const cols[4] = {PIN_A0, PIN_A1, PIN_A2, PIN_A3}; int const rows[4] = {PIN_A4, PIN_A5, PIN_E0, PIN_E1}; int r; int c; char key_code[4][4] = {{'1', '2', '3', '+'}, {'4', '5', '6', '‐'},{'7', '8', '9', 'R'},{'C', '0', 'H', 'E'}}; while(true) { for (r=0; r<=3; r++) { output_low(rows[r]); for (c=0; c<=3; c++) { if (!input(cols[c])) { delay_ms(10); if (!input(cols[c])) return key_code[c][r]; } } output_high(rows[r]); } } }
/* coordinate device functions */ void main() { int key; int k=0; int key_str[6] = {'\0','\0','\0','\0','\0','\0'}; int dec_A = 0; int dec_B = 0; int result = 0; setup_adc_ports(NO_ANALOGS); setup_adc(ADC_OFF); setup_psp(PSP_DISABLED); setup_spi(SPI_SS_DISABLED); setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1); init(); while(1) { crsr(); delay_ms(250); //reduce double tap on keypad key = scan_keys(); switch(key) { //"Enter" parses input, activates solenoids and reports result case 'E': clc(); fprintf(use_LCD, "working... \n"); if(str2op(key_str, &dec_A, &dec_B)) { result = fire(&dec_A, &dec_B); clc(); fprintf(use_LCD, "Answer >> %d", result); clear_str(key_str); } else { clc(); fprintf(use_LCD, "Error:"); new_line(); fprintf(use_LCD, "Invalid Entry"); clear_str(key_str); } break; //"Clear" clears key sting and LCD case 'C': k = 0;
clear_str(key_str); clc(); break; //"Reset" clear key string and LCD. Also turns on screw motor. case 'R': clc(); fprintf(use_LCD, "reseting... \n"); delay_ms(5); reset(); k = 0; clear_str(key_str); clc(); break; //"Help" for non‐engineers. case 'H': help(); break; //Any other key is added to string of inputs (if str length <=5 ) default: key_str[k] = key; fprintf(use_LCD, "%c ", key_str[k]); if(k <= 4) k++; else { clc(); fprintf(use_LCD, "Error: "); new_line(); fprintf(use_LCD, "Invalid Input"); clear_str(key_str); } break; } } }