chip washer - department of computer science, …mren/projects/aer201.pdf · this report thoroughly...

238
CHIP WASHER Prepared by Team 40 – Tuesday Tianyu Li (99107149) Mengye Ren (998905430) Yuxiang Zhao Prepared for Prof. M.R. Emami A technical report submitted for AER201 – Engineering Design

Upload: phamtuyen

Post on 21-Jul-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

0

CHIP WASHER

Prepared by

Team 40 – Tuesday

Tianyu Li (99107149)

Mengye Ren (998905430)

Yuxiang Zhao

Prepared for

Prof. M.R. Emami

A technical report submitted for

AER201 – Engineering Design

1

ACKNOWLEDGEMENT Our team would like to acknowledge Professor M.R.Emami and Rene Rail-Ip for providing

assistance, suggestions and evaluation for the entire course of machine design and

manufacturing.

Sincerest thanks to Ping Gu for the space for sharing his own condo as the construction site with

us. Thanks to Ping and Joanna Gu, and their neighbours, for enduring the loud noises we made

during countless nights and early mornings.

Grateful appreciation to parents of the members for their emotional and financial support of the

project.

Special thanks to Shawn Fan, April Wang, Ivan Fu, Chauncy Liu, and Annie Cai for their technical

insights and spirit of working through the project.

2

ABSTRACT This report thoroughly introduces Chip washer, a machine prototype in response to the RFP

request [1] from a game company of packing backgammon chips into containers with patterns.

The problem consists of sorting the chips of different colours, loading the chips into containers,

covering the lid of the container, and counting the remaining chips in the machine. Chip washer

is able to provide a solution to the problem satisfactorily.

Chip washer is not only designed for the basic tasks described in the RFP. Many extra features

are added to the machine without violating any of the constraints. In the end, chip washer is

proven to pack at least two times as many chips and containers. No circuit was burnt during

debugging and system integration, which is a powerful indicator of the machine safety. Strong

software component of chip washer provides user greatest customizability and convenience.

Extra features of the software include customizable patterns, machine logs, and PC interface.

The machine did not fully perform the designated task in the competition, due to the

breakdown of the base motor ten minutes ago before the demonstration. Qualified runs were

recorded consistently before the demonstration. The failure of demonstration indicates the lack

of accuracy and the wrong choice of motor for the prototype. However, the qualified runs prove

that the machine concept works very well. Chip washer will perform better if more advanced

manufacturing tools are used to build the mechanical components, which could be assembled

more accurately and stably.

3

TABLE OF CONTENTS Acknowledgement ........................................................................................................................... 1

Abstract ........................................................................................................................................... 2

Notation & Abbreviations................................................................................................................ 6

1 Introduction ................................................................................................................................. 7

2 Perspectives: History, Theory, and Reference Designs ................................................................ 8

2.1 History ................................................................................................................................... 8

2.2 Reservoir Sorting and Couting ............................................................................................... 8

2.3 Motors and Sensors ............................................................................................................... 8

2.3.1 DC Motor and Microswitches ......................................................................................... 9

2.3.2 Stepper Motor ................................................................................................................ 9

2.3.3 Servo Motor .................................................................................................................... 9

2.4 Conveyor belt and Wheel ...................................................................................................... 9

2.4.1 Conveyor Belt ................................................................................................................. 9

2.4.2 Wheel ............................................................................................................................. 9

2.6 Microcontroller and other software platforms ..................................................................... 9

2.6.1 Microcontroller, FPGA, and Microprocessor .................................................................. 9

2.6.2 Assembly and C Programming Language ..................................................................... 10

3 Design Philosophy and Reasoning .............................................................................................. 11

3.1 Statement of the Problem ................................................................................................... 11

3.2 Constraints and Objectives .................................................................................................. 11

3.3 Design Decisions .................................................................................................................. 11

4 Description of the Machine ........................................................................................................ 13

4.1 Basic Information ................................................................................................................ 13

4.2 Operational Procedures ...................................................................................................... 14

4.3 Division of Work .................................................................................................................. 19

5 Electromechanical Subsystem .................................................................................................... 20

5.1 Problem Assessment ........................................................................................................... 20

Frame ..................................................................................................................................... 20

Wheel .................................................................................................................................... 20

Wall ........................................................................................................................................ 20

Height Limiter ........................................................................................................................ 21

Width limiter ......................................................................................................................... 21

4

Fin .......................................................................................................................................... 21

Loading Tunnel ...................................................................................................................... 21

Straight lane and Counting lane ............................................................................................ 21

Base ....................................................................................................................................... 21

Lid closing mechanism ........................................................................................................... 21

5.2 Solutions .............................................................................................................................. 22

5.2.1 Frame ............................................................................................................................ 22

5.2.2 Wheel ........................................................................................................................... 23

5.2.3 Fin ................................................................................................................................. 25

5.2.4 Wall ............................................................................................................................... 26

5.2.5 Height limiter ................................................................................................................ 28

5.2.6 Width Limiter ................................................................................................................ 28

5.2.7 Straight Lane and Outer Lane ....................................................................................... 29

5.2.8 Loading Tunnel ............................................................................................................. 30

5.2.9 Base .............................................................................................................................. 31

5.2.10 Lid closing ................................................................................................................... 34

6 Circuit Subsystem ....................................................................................................................... 35

6.1 Problem Assessment and Design Requirements ................................................................. 35

6.2 Solutions .............................................................................................................................. 37

6.1 Overview .......................................................................................................................... 37

6.2 Power board .................................................................................................................... 37

6.3 Power supply and Power supply connection board ........................................................ 39

6.4 Sensors ............................................................................................................................ 40

6.5 Actuator drivers ............................................................................................................... 41

6.6 Microcontroller and signal routing board ....................................................................... 43

6.7 Circuit Panel and Cable Management ............................................................................. 44

7 Microcontroller Subsystem (Software) ...................................................................................... 45

7.1 Overview .............................................................................................................................. 45

7.2 Problem assessment ............................................................................................................ 45

7.3 Solution ................................................................................................................................ 45

7.3.1 Pin Assignment ............................................................................................................. 46

7.3.2 File System .................................................................................................................... 46

7.3.3 Paging ........................................................................................................................... 48

5

7.3.4 Stack ............................................................................................................................. 48

7.3.5 Math ............................................................................................................................. 49

7.3.6 Data Table ..................................................................................................................... 50

7.3.7 LCD ................................................................................................................................ 50

7.3.8 Keypad .......................................................................................................................... 51

7.3.9 UI .................................................................................................................................. 51

7.3.9.1 Keystroke Validation .................................................................................................. 52

7.3.9.2 General Purpose Input Box ........................................................................................ 53

7.3.9.3 Input Number Parsing ............................................................................................... 56

7.3.9.4 Menu Routing (Pattern Selection) ............................................................................. 57

7.3.9.5 Pattern Parsing .......................................................................................................... 58

7.3.9.6 Real Time and timing ................................................................................................. 59

7.3.10 Sensor and Motor Control .......................................................................................... 59

7.3.10.1 Initialization ............................................................................................................. 61

7.3.10.2 Loading .................................................................................................................... 61

7.3.10.3 Lid Covering ............................................................................................................. 61

7.3.10.4 Chip Counting .......................................................................................................... 61

7.3.10.5 Chip Returning ......................................................................................................... 61

7.3.10.6 Sensors .................................................................................................................... 61

7.3.10.7 Motors ..................................................................................................................... 61

7.3.11 Emergency Stop .......................................................................................................... 61

7.3.12 Permanent Storage ..................................................................................................... 62

7.3.13 PC Interface ................................................................................................................ 63

7.4 Improvements and Suggestions .......................................................................................... 64

8 Integration .................................................................................................................................. 66

8.1 Overview .............................................................................................................................. 66

8.2 Integration between circuit and electromechanical components ...................................... 66

8.3 Integration between circuit and microcontroller ................................................................ 67

8.4 Accomplished Schedule ....................................................................................................... 67

9 System Issues and Improvements .............................................................................................. 68

10 Budget ...................................................................................................................................... 70

11 Conclusion ................................................................................................................................ 74

12 References ................................................................................................................................ 74

6

13 Appendix ................................................................................................................................... 75

13.1 Electromechanical Components ........................................................................................ 75

13.1.1 Lazy Susan Bearing ..................................................................................................... 75

13.2 Circuits ............................................................................................................................... 76

13.2.1 Schematics .................................................................................................................. 76

13.3 Microcontroller.................................................................................................................. 79

13.3.1 General Purpose Register Organization ..................................................................... 79

13.3.2 Microcontroller Original Source Code ........................................................................ 83

13.3.3 PC Interface Original Source Code ............................................................................ 226

NOTATION & ABBREVIATIONS RTC Real Time Clock EEPROM Electrical Erasable Programmable Read-Only Memory IC Integrated circuit LCD Liquid crystal display PIC Peripheral interface controller UI User interface DC Direct current RFP Request for Proposal

7

1 INTRODUCTION The problem describes in the RFP involves the packaging of 2 colour backgammon chips into

containers with patterns. Chip Washer is the solution presented by our team. It is a powerful

machine prototype that demonstrates the feasibility of solving the problem with extra

extensibility and capacity.

The general design of the Chip Washer is three horizontal layers distributed vertically connected

with a tunnel to drop chips. The upper two layers are reservoir layer of the same design for

chips of two different colours. Unlike other machine prototypes, Chip Washer allows chips to be

sorted completely on a horizontal layer with the torque of the wheel motor. After sorting the

chips into one lane, fin wheels at each reservoir layer controls the chips dropping sequence

according to the patterns entered by the user. Chips counting procedure is also done on the

horizontal layer with a pair of photo IR sensors. Lastly, all the remaining chips are elegantly

returned to the reservoir at the exact same location where the user placed the chips.

Chip Washer can carry at most 80 chips and 8 containers. Users can control the machine with a

2*16 LCD display and 4*4 keypad input. The following extra design features are highlighted and

will be discussed into detail in the report:

Maximum capacity of 80 chips and 8 containers

Extensibility of multiple colours of chips packing

Flexible chip shape

Customizable number of containers each run

Customizable patterns at runtime and at PC interface

Machine diagnosis log

This technical report includes the design perspectives, objectives and constraints, and technical

details on subsystems (electromechanical, circuit, and microcontroller subsystem), and

integration process between subsystem. Financial summary and project time management are

also present in the report. Datasheet and microcontroller/PC interface source code can be found

in the Appendix.

8

2 PERSPECTIVES: HISTORY, THEORY, AND REFERENCE DESIGNS

2.1 HISTORY Backgammon is an old board game for two players [2]. Two colours of the chips are present in

the rules of the game. The game company is in need of a automatic solution to package the

chips of two colours into various patterns in a plastic container. The term “Packaging” means

the technology of enclosing or protecting products for distribution, storage, sale, and use. In this

situation [3], there is a need to identify the product is the backgammon chips, and the method

of protection is to enclose all the chips into the plastic transparent cylindrical containers, and

some visual forms are applied to attract the consumers by packaging the chips into various

patterns. Packaging process is a simple labour process, which means an automatic solution

(machine) is desired to save the labour cost permanently. The team recognizes the need of

building such a machine and starts with researching the current exisiting design ideas and

available components for different purposes.

2.2 RESERVOIR SORTING AND COUTING One large problem associated with the machine is the mechanism of sorting the chips from a

pile to a file, and counting the chips remaining. Industrial solutions have provided us with

insights that a spinning wheel will do the job of counting and sorting by actively providing the

power on the wheel. Figure below shows a counting machine of medical pills.

Figure: a pill counting machine (Source:

http://zhiyao.gongye360.com/prods_view.html?prodid=596955)

Compared to designed that uses gravity to sort the chips, active motor has advantages of higher

capacity, because with more capacity, the gravity filter has greater probability of jamming. The

disadvantage of choosing a motor wheel is the difficulty of construction.

2.3 MOTORS AND SENSORS All machines come with actuators and mechanisms to control the actuator state. The following

text lists a few current solutions.

9

2.3.1 DC MOTOR AND MICROSWITCHES DC motor and microswitch sensors are the cheapest solution available to control the motor

positions. The microswitch is hit by a irregular shape on the motor shaft every full cycle. In order

to fully stop the motor, some time delay needs to be written in the microcontroller code to give

a counter pulse after hitting the microswitch. DC motors also provide the largest torque and

power among all electric actuators.

2.3.2 STEPPER MOTOR Stepper motors give better precision to 15 degrees. Disadvantage of using a stepper motor is

the cost and difficulty of circuit connection to microcontroller. Stepper motors cannot provide

as strong torque as DC motors, but it does not need a H-bridge to have bi-directional support.

2.3.3 SERVO MOTOR Servo motors are the most powerful motors. They can turn to any angle and can be directly

connected to the microcontroller. They only need one pin to operate, and microcontroller can

send sequential instruction through the pin. The greatest disadvantage is the cost of such

motors is usually three times the DC motor, and really easy to be destroyed during debugging. It

cannot provide as much torque as DC motors.

2.4 CONVEYOR BELT AND WHEEL For the purpose of transporting the containers, two current designs are most relevant to the

machine: conveyor belt and wheel.

2.4.1 CONVEYOR BELT Conveyor belt is the most generic design for transporting product of any shapes. However the

disadvantage of conveyor belt is the difficulty of construction. Gear ratio needs to be adjusted to

provide maximum torque with slow speed of the motor, which means building an external gear

box will be necessary. The material selection for the conveyor belt is another critical issue. It

needs to provide sufficient frictional force to drive the product on the belt, while not too much

friction to block the motor.

2.4.2 WHEEL Due to the symmetric shape of the container, a rotating wheel with container slot is also an

viable solution. Compared to the conveyor belt, the wheel can only fit in one type of container,

which is a loss of generality. However, the greatest advantage of choosing wheel is its simplicity

of construction. External gear is not absolute necessary. The rotation simplifies the relation

between the loading site and lid closing site of the machine.

2.6 MICROCONTROLLER AND OTHER SOFTWARE PLATFORMS Software system of the machine is parallel to the brain of human. Choosing a suitable software

platform is absolutely critical for the project.

2.6.1 MICROCONTROLLER, FPGA, AND MICROPROCESSOR Microcontroller, FPGA, and microprocessor are three types of central computing unit available

in the industry. Microcontroller has advantages of low cost and small in size. One

microcontroller chip contain ALU, memory, and file registers. No external computing component

10

is required, which gives a good portability. FPGA has the advantage of programming large size

digital circuit. Microprocessor has the greatest computing power, and thus the most expensive

solution. Microprocessor is essentially the arithmetic and logic unit, and needs peripheral

components such as permanent storage (flash/hard drive), memory, and bus connection. With

the cost constraints stated in the RFP, both FPGA and Microprocessor get out of the competition.

Within the wide range of microcontrollers, PIC16F877 and PIC18F4620 are two most common

options provided by Microchip Inc. PIC18F4620 has more computing power and memory space,

while PIC16F877 gives lower price and simpler programming instruction set. Both types of

microcontroller are suitable for the machine.

2.6.2 ASSEMBLY AND C PROGRAMMING LANGUAGE Microcontrollers can be programmed with both assembly and C programming language.

Essentially, the compiler provided by the chip manufacturer compiles C language into assembly

language with lower efficiency. Assembly language has advantages of closer to hardware, thus

easier to debug, but disadvantage of harder to understand by human (i.e. low maintainability). C

language has advantage of high understandability, but low efficiency and difficulty of debugging.

For this project, assembly language is chosen for its general simplicity; however, in the control

system industry, C language seems to be more commonly used by experienced users.

11

3 DESIGN PHILOSOPHY AND REASONING

3.1 STATEMENT OF THE PROBLEM A game company needs to package two colors of Backgammon chips in cylindrical plastic

containers in various mixed combinations.

The goal is to design and manufacture a machine that can package Backgammon chips in two

colors, amber and camel according to operator’s keypad in request for patterns.

The machine needs to load the chips into containers, and cover the lids for each container. After

loading, the machine needs to count the remaining chips and remain the chips in the reservoir.

3.2 CONSTRAINTS AND OBJECTIVES The constraints of the machine specified in the RFP are:

1. Size: smaller than 50*50*50cm3

2. Weight: lighter than 6kgs

3. Cost: cheaper than $C230

4. Emergency stop: present and accessible

5. Fully autonomous: No human interaction after pressing Start button

6. Accessibility: No installation is required. Containers and chips must be retrieved without

disassembling the machine.

7. Richness: Display operation time, number of chips remaining and packaging pattern at

the end of each run

The objectives are:

1. Time: The entire operation shall not exceed 2 minutes.

2. Completeness: Each container shall be closed completely without damaging the

container and chips.

3. Accuracy: The recorded operation time has less than 5% error. The number of

remaining chips shall be correctly counted.

4. Safety: the machine shall not present hazard during the operation.

5. This project focuses on designing a machine that can package ten chips into two

containers.

6. Portability: The machine shall be as light and as small as possible.

7. Modularity and Maintainability: The machine shall be able to divide into modularized

components which will ease the maintenance process.

3.3 DESIGN DECISIONS During the design stage of the machine, our team not only tried to find a way to meet the

requirement, but strive to find the best way to extend the capacity of the machine to its

extreme under the constraints.

To meet the constraints and objectives, the following design decisions are made:

The use of lightweight wood frame to lower the weight

The use of aluminum wall to retain the rigidness and stability of chip sorting

12

The use of photo IR sensor to maximize the chip counting accuracy

The use of RTC to maximize the timing accuracy

The use of DC motors and micro-switches to minimize the cost

The design of the fin to maximize the accuracy and predictability of pattern loading and

chips counting

The design of vertical layers to maximize the modularity and extensibility

The design of height limiter to maximize the size configurability of chips

The design of outer wall to maximize the chips counting capacity

The design of horizontal reservoir to maximize the accessibility of chips retrieval

Some extra features can be summarized into the following list:

Easy loading chips into the reservoir

Accessible retrieval of chips at the same location

Maximum 40 chips per reservoir

Maximum 8 containers to load

Maximum 99 containers configurable in the software

Customizable preset menu of patterns

Customizable pattern at runtime

Permanent machine diagnostic logs at variable lengths

PC interface for downloading logs and customize menu

13

4 DESCRIPTION OF THE MACHINE

4.1 BASIC INFORMATION The basic information of the machine can be found in the table below.

Size 0.50m*0.47m*0.50m Weight 5.8kg Power Supply 120V Maximum Power Maximum chips per color 40 Maximum number of containers 8 Maximum speed 30 seconds/container Microcontroller PIC16F877 LCD Standard 2*16 display Keypad Standard 4*4 keypad Actuators 3 12V 50rpm DC motor

3 5V 65rpm DC motor Sensors 5 micro-switches

2 pairs of IR sensors Permanent Logs Functional Real Time Clock Functional PC Interface Functional

The machine has a vertical three-layer design which maximizes the machine capacity and

efficiency. The table below is a brief comparison between the Chip Washer machine and other

machine that achieves the same purpose.

Chip Washer Other Machines Size 5.8kg, 0.12m3 ≤6 kg, ≤0.125m3 Maximum chips per reservoir

40 (80 in total, can upgrade to more reservoir layers)

15

Maximum containers 8 (99 configurable in software) 2 Maximum colors 2 (more if reservoir layers keep

stack vertically up) 2 (not extensible to more)

14

4.2 OPERATIONAL PROCEDURES

The bottom layer is designed for transport the containers to the chip loading site and to the lid

covering site. The design of a circular shape maximizes its capacity of 8 containers and allows

single DC motor to control the entire transportation flow.

Micro-switch sensors are installed on the bottom layer to control the position of the DC motor

so that containers can be loaded and covered at exact position.

The lid covering apparatus is efficiently designed with an iron stick and a DC motor. The test

runs proved the functionality of covering and snapping the lid of the container. The lid covering

motor has another micro-switch to help re-positioning the motor.

15

The upper two layers are of same design for different colors of chips. The vertical design of the

machine allows adding more vertical layers to extend the capacity of the machine (i.e. more

chips and more colors) in the future. The design of the upper two layers contains the following

elements: reservoir wheel, central reservoir, arms, inner wall, height limiter, width limiter, fin,

straight lane, and outer wall.

16

The reservoir wheel is a big wood circular disk with radius of 20cm, driven by a 12V DV motor.

The wheel controls the entire motion of the chips in the upper two layers.

The central reservoir is the initial and final position of the chips. The design of the reservoir

allows user to dump all the chips into it without worrying about any jamming.

The arms are essential component which stretch from frame to the inner wall, providing

structural support for both inner and outer wall of the reservoir that does not move with the

reservoir wheel. One of the arms at each layer also supports the DC motor to stay at the center

of the disk.

17

The inner wall acts as a lane to guide the chips from the central reservoir to the chip exit

(loading) site. The inner wall gets narrower as closer to the exit to sort the chips into one lane.

However this is proven not sufficient. Width limiters are designed to stay on the inner wall to act

as a discontinuous point, which blocks the chips of multiple lanes into one lane.

Height limiter is designed to block chips of multiple layers into one layer. This stationary limiter

is proven to be effective with the reservoir wheel to rotate back and forth to unjam the chips. In

the proposal, it was proposed to be installed with dc motors, which was proven to be

unnecessary.

18

The fin is a central part of the reservoir layer to control the loading sequence. It is driven by a 5V

DC motor individually. The micro-switch controls the position of the motor. Each activation of

motor will rotate 90 degrees to permit one chip to exit at a time. The fin not only permit chips to

exit, but also permit chips to enter the outer track, a temporary place for the counted chips.

Before entering the outer track, the chips are guided through a straight track, where the IR

sensors are installed to detect the pass of chips, for the purpose of counting the remaining

chips.

19

After all the chips are counted, the chips are returned back to the central reservoir.

4.3 DIVISION OF WORK The entire project is completed by three members, each responsible for one subsystem.

Electromechanical subsystem member Yuxiang Zhao is responsible for building the physical

structure of the robot. Circuit subsystem member TIanyu Li is responsible for designing and

building the circuit of sensors, actuators, power board, and circuit connecting the DevBugger.

Microcontroller subsystem member Mengye Ren is responsible of comtrolling the entire

machine with programs and providing users of the machine a friendly user interface. For the

later half of the project, both circuit and microcontroller member joined the electromechanical

subsystem to accomplish the unfinished work. All three members are responsible in the

debugging stage of the machine to ensure that the machine satisfies the operation requirement.

20

5 ELECTROMECHANICAL SUBSYSTEM

5.1 PROBLEM ASSESSMENT The above section already introduced the various mechanical components the machine has in

order to accomplish the tasks it was designed to do. The electromechanical system consists of

the entire mechanical structure of the machine, as well as various electrical components such as

motors and sensors and their assembly into the mechanical structures. Along with requirements

in the RFP that are already presented, the following are additional design requirements:

The chip is a circular object with a dimension of 45± 1 mm in diameter and 10±1 mm in

thickness. The weight of each chip is 20 ±1 g.

The container is cylindrical with a height of 107 ± 2 (excluding the cover) and inner

diameter of 52 ± 1 mm at the top and 48 ± 1 mm at the bottom. The cover is has a

diameter of 63 ±1 mm and a thickness of 12 ±1 mm.

The force needed to close the lid when acting on the lock of the lid is approximately

1000 g. This is derived from experiments

The coefficient friction between chips and chips derived from experiment is 0.67 (see

appendix * for derivation process)

After analyzing our solution and the RFP, the following design requirements for each of the

component are developed

FRAME The frame must be light but capable of withstanding the weight

Each level of machine must be removable with relative ease

WHEEL The wheel must be large enough to house the required wall structures. It also must

accommodate a reservoir that would hold at least 15 chips, 40 chips desired. The wheel

material should withstand the weight of the chips

The wheel motor must be strong enough to counter the friction force created by chips

and the bottom of the wall rubbing on the wheel

The bearing system for the wheel should have very low resistance but stable so that the

wheel is stable and does not wobble. The bearing system should withstand the weight

of the chips.

WALL The wall must be strong and rigid to withstand the impact and pressure from the chips.

It also should be constructed with an accurate suspension height from the wheel. The

holding mechanism should also be strong, rigid, light and easy to construct.

The wall structure should be carefully designed so that chips do not jam within the track,

especially around the fin area.

21

HEIGHT LIMITER The height limiter should attempt to reduce the height of chips from multiple chips

down to one chip. It should do so without causing jamming in the system

WIDTH LIMITER The width limiter should attempt to reduce the width of chips from two to three chips

down to one chip. It should do so without causing jamming

FIN The fin should dispense one chip and sent one chip to the counting reservoir in a simple

and controllable manner. This requires that only one chip should be inserted into each

of the fin compartments.

Chips and fin must work together without assistance of any sensors

Chips immediately outside of the fin should not interfere with the fin as the fin turns.

Any other potential jamming conditions should be discovered and resolved

Micro-switch should be integrated to indicate the fin has spun a quarter turn

LOADING TUNNEL Loading tunnel should catch all the chips as they are knocked out of the wheel by the fin.

There is a range of locations where this occurs, the loading tunnel should deal with all of

the situations

Chips loaded into the container should eventually lay down flat

STRAIGHT LANE AND COUNTING LANE The IR emitter and receiver pair as to be mounted low enough (<1 cm) so that the chip

can block of all the IR radiation

The emitter and receiver must be paired accurately so that the receiver can detect the

IR emissions

The emitter and receiver must be stable to withstand various movements and vibrations

The emitter and receiver must be replaceable

During reverse, the straight lane and the fin should work together so that the fin the

rotate back chips without guidance from the IR break point sensor

BASE 8 containers should be inserted onto the base. The containers should be locked firmly

onto the base. The insertion process should be convenient

The base motor and the bearing system should handle the weight of 8 X 10 chips, each

weighing 20 g.

One Micro-switch indicates the stop location for the loading zone and the other for the

lid closing zone. The sensors should be reliable and not interfere with containers

movement. Their position should also assist the base to stop at the precise location

required for loading and lid-closing.

LID CLOSING MECHANISM The DC motor used should provide at least 1000g of force at the lock of the container

22

The mechanism should not block the passage of containers

The mechanism should be reliable and simple to control

5.2 SOLUTIONS

5.2.1 FRAME

Figure 5.1 3 level structure, 4 Main poles, 4 wood beams per level

Figure 5.2 The L bracket holding the wood beams. The level can be disassembled by bolting only the two wood beams together

Figure 5.3 The beams holding the lazy Suzan bearing of the wheel

Figure 5.4 The already bent beams

The frame is built with wood bars and thin wood panels. Four wood bars erect the entire

machine. Four beams made out of wood strips are attached to the wood bar by L brackets, and

forms one layer of the machine. Two additional wood strips are set across the beams, providing

support for the lazy Suzan bearing and the wheel. The edge wood panels provide a platform for

arms, the walls, and the fins to be erected. The use of bolts at the L brackets means the entire

layer can be removed by binding only the four beams, achieving the desired modularity. This

allowed us to work on the middle layer after the top layer is complete for example. This also

23

meant additional layers could be added to the machine very easily, increasing the machine’s

functionality.

In our initial design, a large wood sheet is used to serve as the platform for each layer. Although

this method made each layer easier to construct and more modular, the machine was proven to

be too heavy (2.5 kg for the each layer, 8 kg predicated for the entire machine). It was thought

that only the edge and the middle beam of the wood sheet is used to carry the weight. Hence,

the frame and the layers were rebuilt to only include an edge and middle platform, which

resulted in the design above. The current design resulted in a weight of 5.8 kg

IMPROVEMENTS

Although the re-design solved the weight issue, the thin wood panel proved too fragile with

time. Figure 4.4 indicates the weight of the reservoir layer has caused the edge wood panel to

bend and hence, the structures on the panel began to sag. This caused nightmare issues with

the wall and the wheel as the wall would rest on the wheel with time, jamming the wheel.

Resilient materials, such as aluminum L channels, could be used instead of thin wood panels, as

they are resistant to bending forces while being light.

5.2.2 WHEEL

Figure 5.5 motor and the coupler

Figure 5.6 Roller bearing

Figure 5.7 The lazy Suzan bearing and the roller bearing

Figure 5.8 The bent wheel

24

A pine plywood sheet cut into a 20cm diameter circle is used as the wheel for the reservoir

levels. The pine plywood is selected due to its light weight and high strength. The weight of the

desired number of chips per reservoir is 800 g, and is not an issue to the pine plywood. A 4 inch

lazy Suzan bearing is used at the center of the wheel due to its high axial load capacity (120 Kg,

datasheet see appendix *), low friction, and high stability that reduces wheel wobbles. However,

due to the large size of the disk, the minimum wobble at the lazy Suzan bearing is amplified into

the significant vertical movement at the ends of the wheel, which would allow chips to escape

from the wall from underneath. To combat this, four roller bearings are installed on the edge

panels to support the wheel and prevent any wheel wobble. The roller bearing also add

minimum amount of friction.

The motor used to drive the wheel is a 12 V, 50 RPM gear reduction DC motor. This motor

provides 4.5 kg cm torque at 20 RPM and 7.5 kg cm torque at stall. The combination of high

torque, compactness and low cost (see Budget section) is the primary motivation for using this

motor. A ceramic 10 ohm, 5W resistor is attached to the motor to reduce the speed of the

motor to around 30 RPM at no load. The 50 RPM speed is too high and causes too much

mechanical stress on the wheel and connection between the motor and the wheel. PWM is not

used to limit the speed of the motor because it was found that PWM would severely limit the

torque of the motor but not the speed of the motor. This is undesired and the resistor provided

better results by keeping the torque high and speed low, though at a cost of low efficiency.

The motor is attached to the wheel through a metal coupler (figure 5.5). A significant effort was

spent on find the center of rotation of the wheel after it is mounted to the lazy Suzan bearing

and securing the metal coupler to that center of rotation. Any deviation from the true center of

rotation causes wobbles to the coupler and the motor when the wheel rotates. This not only

jams the wheel but also damages the motor. The center of rotation was found by using a pen

mounted to a stationary pole, and tracing paths on the wheel as the wheel rotates. The center

of the traces is the center of the wheel. The initial design was to mount the motor at the

bottom of the wheel and lock the motor inside. It was known at that time that such method

would render replacing the motor extremely difficult if the motor breaks. The team decided the

elegance was worth the risk, and unfortunately, the motor indeed broke after some usage.

Using considerable effort and time, the motor was extracted and new one was installed on the

top of the wheel by holding it with a wood arm. It was diagnosed that the coupler deviated

which caused the gear box of the motor to break after rotating for extended period of the time.

The team learned this lesson and applied to other parts of the machine.

IMPROVEMENTS

The modified motor mounting technique has not encountered any issue at all. It also made

operating on the machine easier. The primary issue with the wheel is the bended wood disk,

which is shown in figure 5.8. Although care was made to select a flat wood board for the wheel,

the wheel still showed heaving bending after being cut and used. This is thought to have caused

by the plywood board releasing material tension after it is cut and hence changing its shape. To

solve this issue, higher quality wood board or alternative materials, such as aluminum, should be

used.

25

5.2.3 FIN

Four arms were chosen for the fin because it

allows chips from the width limiter side and

straight lane side to be inserted into the fin

when the fin is stopped at one position. Figure

5.9 indicates this geometry. This way, it is easy

to install the micro-switch sensor that will

detect this position as there is only position to

detect. In addition, from this position, the fin

can spin a quarter turn counterclockwise to

dispense the chip, or a half turn clockwise to

count the chips. Both actions are easy and

reliable to control with the micro-switch.

Figure 5.10 Frame by Frame sequence showing how a fin turns and dispense one chip down to

Figure 5.9 Showing the designated position of the fin. At this position, the fin is able to receive chips from width limiter, the straight lane, and dispense chip into the loading tunnel. The Micro-switch detects the fin at this position

26

the loading tunnel

A lot of effort is placed on studying the operation nature of the fin. It is discovered that if the fin

rotates prematurely before the chip is inserted into the fin compartment by the wheel, the chip

will hit the wall and cause the fin to jam. This issue is later resolved in software by increasing the

wait time of the fin well beyond the insertion time of the chip (see integration). A lot of

experimentation and time is spent on adjusting the minute positioning of the wall so that when

the fin spins, the chips will not hit the walls and jam the fin.

FIGURE 5.11 FIN

Figure 5.12 The horseshoe metal wire inserted on the top of each arm of the fin. The horseshoe metal wire slides through underneath of the micro-switch and activates it.

The micro-switch that indicates the correct stopping location of the fin is installed upside down

along the radius that origins from the axis of the rotation of the fin motor. This is so the stopping

location can be adjusted by rotating the arm of the micro-switch. A horseshoe shaped metal

wire is inserted on the top of each of the fin arms. The top of the horseshoe is precisely adjusted

such that as the fin rotates, it slides through underneath the microswitch and activates it. This

works whether the fin is rotating clockwise or counterclockwise and care was made to not to

damage the micro-switch but at the same time made sure the activation was firm.

IMPROVEMENT

During the experimentation, it was discovered that the fin will only be able to carry the chips

when the wheel is spinning underneath. This creates an undesirable dependence: if the wheel is

jammed, the fin will also stop working. For the future, it is important to design a machine that

minimizes this kind of dependence as much as possible.

5.2.4 WALL Aluminum sheet is used to build the wall due to its lightness, ductility for high workability, and

low cost. For curved walls, the aluminum wall is first bent using a cylinder to achieve plastic

deformation and an additional thin strip of aluminum with the same plastic deformation is

firmly bonded to the wall using epoxy. This double layer bonding meant the shape of the wall is

constrained by two layers of aluminum in tensile and compression equilibrium; hence the wall

27

becomes very rigid and difficult to bend. For straight walls, a perpendicular edge is created by

bending the bottom edge of the aluminum sheet and made the aluminum rigid. These solved

the aluminum softness issue.

Figure 5.13 double bonded layer provides rigidty to the wall

Figure 5.14 The bent edge strenghts the aluminum wall so that it is no longer bendable

Figure 5.15 One of the arms that erects the wall. The cylindrical rode is bolted to the wall and

allows for minor adjustment to wall position by simple rotation

Arms and poles made out of wood cylinders are used to erect the wall above the wheel. The arm

is made out of wood cylinders so that they can be rotated in order to adjust the position of the

wall. The pools are bolted onto the four beams. The height of the poles is precisely adjusted so

that the height of the wall from the wheel is on average 4 mm. However, due to the bent wheel,

this proves to be extremely challenging. Since the top priority is to not allow chips to escape the

wall, a soft sponge sheet is added at the bottom of the wall and is made to scrape the wheel.

The sponge sheet stops the chips from escaping, and has low noise and friction when scraping

on the wheel. Additional helper arms are made to further secure the wall. They are made with

balsa wood so the weight added is virtually non-existent. Appendix * shows the dimensions and

layout of the walls on the reservoir layer. The dimensions are made so that the chips can pass

smoothly.

28

5.2.5 HEIGHT LIMITER

Figure 5.16 The height limiter cuts down mutiple layer of chips down to one

Figure 5.17 The condition where the chip will jam at the height limiter forever

The role of the height limiter is to knock multiple layers of chips down to one level and allow

only one layer of chips to pass through. The simplest design is employed in this case: a plain

aluminum sheet held along the radius of the wheel. The aluminum sheet is elevated 1.2 cm to

allow one layer of chips to pass below and is bent at the bottom to increase the strength.

Although the design is effective for many cases, the particularly troublesome case is the shown

in figure 5.17. The problem is not solved mechanically, but rather through the software (See

Microcontroller Section 6)

IMPROVEMENTS

Other shapes of height limiter can be investigated for their effectiveness against cases such as

the one shown in figure 5.17. One possible shape is a triangle that is folded inwards. The slope

allows any chips jammed on the height limiter to slide around, creating an unstable situation so

that the jamming could be resolved.

5.2.6 WIDTH LIMITER

Figure 5.18 Width limiter and the jamming condition

29

The width limiter has circular wall that has a larger curvature than the inner reservoir wall; the

continuously reducing width limits multiple chips down to one chip. From experiments, two

chips often times can jam together as the width narrows. This is somewhat resolved by adding a

wood piece on to the inner wall to provide a bias towards the chips on the outer track. This is a

natural fit because the chips on the outer track already moves faster than the chips on the inner,

hence biasing towards them is more effective. However, the identical jamming situation still

occurs (figure 5.18). We hypothesized that no matter the configuration, there is always a point

where such jamming will occur. We minimized this jamming with software (see Microcontroller

section)

IMPROVEMENTS

Instead of modifying the width limiter, one possible solution is to create bumps on the wheel

surface. This way, as the wheel turns beneath the jammed chips, the bumping provided by the

wheel will be enough to knock the chip loose and resolve the jam.

5.2.7 STRAIGHT LANE AND OUTER LANE

Figure 5.19 Chips returning the resevior are fed contiuneously into the fin. The fin is able to handle this situation

Figure 5.20 the break point IR sensor. The emitter on the left, the reciever on the right

The purpose of the straight lane and the outer lane is to collect, store and return the counted

chips. The straight lane is built to feed the chips into the compartment of the fin just like it is

shown on figure 5.19. It is only at this position that the fin can rotate blindly and still be able to

carry the chips back to the reservoir without any chance of jamming. The straight lane also

provided a platform to install the breakpoint IR sensors which are used for counting. The IR

emitter on one side continuously emits IR radiation, which is detected by the receiver on the

other side. When a chip passes through, it blocks off all the IR radiation and the receiver no

longer receives them, this trigger a change in state in the sensor that is detected by the

Microcontroller. A wood block is used as a container for the two sensors (shown in figure 5.22).

A socket is carved for the sensor such that the sensor can be inserted firmly into the hole

30

(shown in figure 5.23); only the frontal portion of the sensor is exposed to emit or detect IR

radiation. This firmly secures the sensors and protects them from the environment. The sensors

can also be easily replaced from the container if the sensors break. The bottom of the container

is rubbed off so that the sensor is at the edge of the container. The two sensor blocks are

aligned carefully, a hole is cut to the aluminum wall, and the sensor container is bolted to the

wall. This way, the sensor is secure, replaceable, and low enough to detect the chips. Through

testing, the sensors operate exceptionally well.

Figure 5.20 The emitter and its hole. Notice the low height of the sensor compared to the chip

Figure 5.21 The reciever and its hole. Notice the low height of the sensor compared to the chip

Figure 5.22 Showing the wood container block for the emitter, which has duo IR LEDs.

Figure 5.23 Showing the socket made for the duo IR LEDs. It is identical for the reciever

5.2.8 LOADING TUNNEL

31

The loading tunnel took a simple design. It is

a rectangular tunnel that connects from the

top layer to the mouth of an open container.

The portion of the tunnel from the second

layer to the mouth of the container is angled

in so that the tunnel can actually connects

with the mouth of the container. After

experimentation, it was found that chips can

sometimes drop into the container vertically.

A curved bend was given to the angled

portion of the tunnel. This is so that when

chips go through it, it is rotated towards the

horizontal inside of the tunnel, and reduces

the chances of landing vertically in the

container. The exact angle is found by

experimentation. This solved the issue.

Several piece of the aluminum panel are

added to the top and middle layers. This is

because chips are often thrown out to

different locations by the fin and the

aluminum panels direct the chips down to

the tunnel.

5.2.9 BASE

Figure 5.25 The base wheel and the cylindrical poles that secures the cylinders in place

Figure 5.26 The motor mounting mechanism

To secure 8 containers on to the base, three wood cylinders per container are nailed on to the

base. The wood cylinder provides a slot to insert the containers and will firmly secure the

cylinders in place. The other option is to make holes where the cylinder can be inserted into.

Figure 5.24 The loading tunnel. Notice the last portion is curved

32

This option require a thicker wood wheel and wood wheel being elevated, both of which are

undesirable in our design. The bearing system used for the base is identical to the wheel on the

reservoir level: a lazy Suzan bearing is used at the center, and four small roller bearings are

installed at the edge of the wheel. The motor used is a 5V worm gear motor, though it is capable

of handling 12V power if it is needed. This decision was made because of the need to cut on cost

and weight; the base is assumed to have low friction even with heavy containers loaded on it

due to the use of the bearing system, hence high power motor is not required. The motor is

mounted on a wood support beam, which is bolted to the bottom of the middle layer. Holes

were carved out of the unused portion of the base wheel to reduce weight.

Figure 5.27 Showing thee mounting method and the postion of three senors. From the closest to the furthest: load zone sensor, Lid closing zone sensor, lid closing mechanism initial position sensor

Figure 5.28 The sensor is mounted such that it is tanget just over the edge of the base wheel

Figure 5.29 The container rotates by, the body of the container presses on the micro-switch

Figure 5.30 As soon as the container clears the switch, it is directly below the load tunnel. This feature is used in the software to precise postion the container.

The micro-switch for detecting if a container has entered the loading zone is mounted on top of

a wood pole. The sensor is immediately beside the base wheel; as a container spins through it,

33

the body of the container will press on the lever of the micro-switch, hence activating it. The

sensor is mounted before the loading zone; the thinking was that the motor should be notified

beforehand so that the momentum can be absorbed. Coincidentally, the tip of the long lever of

the micro-switch is position directly below the loading zone. This feature is later used in

software to accurately position the container into the loading zone. For the lid closing zone, the

micro-switch is mounted in a similar manner.

BASE MOTOR FAILURE

Although it was initially assumed that the base would have low friction due to the bearing

system, the low quality of craftsmanship put into the base result in large bumps underneath the

base wheel. This interfered with the rollers and required extra power from the motor to drive it.

The motor was given 12 V but the performance showed signs of deteriorations as time went by.

Although the team notices such problem, we did not attribute it to damages done to the motor

by 12 V since the motor’s operating voltage is rated 5V – 15V. In addition, the method of

mounting the motor on to a support beam bolted to the second layer proven to be difficult to

remove the motor; top two layers have to be removed in order to access the motor. Such large

operation to our already delayed schedule is unaffordable; we needed time to debug and test.

Hence, the decision was made to continue use this motor. The motor performed satisfactorily

for the duration of our tests; however, the bumps on the underneath of the wheel continue to

jam the base wheel, rendering it impossible to stop at the precise loading zone. On

demonstration day, the decision was made to put sponge sheets on the rollers to absorb the

bumps. This worked but also added friction to the base wheel and the motor can no longer turn.

The motor was then pulsed to squeeze out for torque to drive the base. It turned but moments

later the motor was burnt. At the time of the incident it was 10 minutes before the

demonstration.

ANALYSIS OF THE CAUSE AND IMPROVEMENTS

There are three primary causes of the incident. First, the construction quality of the base wheel

is too low. Nails used to secure the cylindrical wood poles for each container protrudes from the

bottom. There are also major places where the wood has chipped. All these deficits are located

on the outer rim of the wheel where the roller must be installed; there are no other places for

the rollers. The rollers also needed because the containers loaded with chips are so heavy that

they bend the base wheel to the point where the base motor cannot spin. By installing the

rollers the situation is helped but the motor is still too weak to spin, due to the poor

construction quality. For improvements, built quality should be drastically strengthened,

especially in critical components such as the base wheel; every operation made should be made

in full consideration of the consequences to the end product. The second primary cause is the

use of a worm gear 5V DC motor and giving it 12V in order to turn. Although the operating

voltage is rated from 5V to 15V, by giving it 12 V and later pulsing it is obviously pushing the

motor to the limits. Under such condition, it is not unexpected that the motor will break. In

addition, worm gear plastic motors are not at all built to handle such tough task. Its damage is

also expected. For improvements, a more powerful and resilient full metal gear motor should be

used, such as the one used for the reservoir layers. A few grams savings in weight does not

warrant a compromise in such critical component of the machine. The third reason is continue

to use the motor fully aware of the decreased performance. Although it was not attributed to

34

the motor damages, a thoughtful and through investigation should be conducted to determine

the exact root cause of the issue before proceeding with anything else.

5.2.10 LID CLOSING

Figure 5.31 The lid closing mechansim.

Our solution uses a single DC motor to close and snap the lid of the container. Figure 5.31 shows

the helix shape of the lid closing arm. The lid closing arm works in the principle that for any arm

fixed shape arm to close the lid, its axis of rotation must match the axis rotation of the lid.

However, this poses a problem as the same axis of rotation requirement would make the arm

block the motion of the container. The circular base wheel already provides a solution, the

container will move away from the axis of rotation as it is rotated. The arm only need to provide

a clearance region to clear the passing the container and it is still able to be on the same axis of

rotation as the container. Our initial proposal solicited an arm that is held in on both sides by

poles. Actual experimentation found that such design would require a long arm and would

exceed the size constraint. A solution that require one end to be held is raised, and through

repeated testing and experimenting, the helix shape as it is used now is found to be the most

effective. The arm could simply be mounted directly to the motor shaft, and the container has

to enter a zone with a range of 4 cm for it to work, which is generous. The DC motor selected is

the same 50 RPM 12V motor as used on the reservoir levels.

35

Figure 5.10 Frame by Frame sequence showing how a lid closing mechanism turns, catches the lid, closees the lid, and snapes the lid

IMPROVEMENTS

Although the lid closing mechanism is able to snap on the lid very well, it is still quiet unstable.

This is largely due to the base wheel’s inability to position the container xactly at the center of

the zone. It is also relies on the angle of the container; the container lid must face outwards in

order for it work most reliably. Since there is no sensor indicating the closed position of the arm,

a time delay is set to stop of the motor from turning continuously. However, this is not always

reliable and in event where the arm does not catch a lid, the motor will over rotate and damage

other component in the machine.

6 CIRCUIT SUBSYSTEM

6.1 PROBLEM ASSESSMENT AND DESIGN REQUIREMENTS The circuit subsystem has four responsibilities: 1. Provide stable and safe power to all actuators,

sensors, their associated electronic components and the microcontroller. (Power Supply) 2.

Providing the system by which Microcontroller signals can be safely and accurately interpreted

into actuator movements. (Actuators) 3. Providing the system by which sensors responses are

interpreted into a signal that is easily and safely consumable by the Microcontroller (sensors). 4.

36

Providing the environment by which circuit systems can fully operate in a safe, protected, and

reliable manner. (Circuit panel and cable management)

1. Power supply and distribution

a. Provide 12V at 2A maximum 5V at 2A maximum for the continuous operation of

all actuators, circuits and microcontroller. Detailed power budge is shown in

section *. The main power supply can be a power adapter that plugs into regular

wall socket since the machine is stationary. However, the weight of the power

supply should be light since it is counted in the total weight of the machine; the

power supply should not exceed 500g.

b. Microcontroller and sensors require a stable, regulated and noise-free 5V power

source to work safely and reliably. Over voltage/current protection and wrong

polarity protection should also be present for these delicate electronic devices.

This infrastructure is provided by the power system.

c. DC motors generate noise, high current spikes, high voltage spikes, and wrong

polarity when operating. These electrical anomalies would cause more delicate

electronic devices, such as sensors and Microcontrollers to operate unreliability

or even damage them. Since some DC motors (see section *), Microcontroller

and sensors all operate on 5V source, the power system needs to isolate the

delicate electronic devices from the DC motors. This will also help to achieve

requirement b.

d. An emergency stop is implemented. The emergency stop is a physical switch or

a push button that can be triggered easily. It should also be mounted in an easily

accessible place. Upon triggering the emergency stop, the machine must

completely stop moving and hence remove any threats that caused the stop to

be triggered in the first place. The machine should resume its operation when

the emergency stop is lifted. These requirements are in accordance with the RFP.

2. Sensors

a. IR emitters and receivers running in a breakpoint sensor configuration are

needed to detect the passage of chips

b. Microswitch is used to detect the location that the fin has spun to

c. Microswitch is used to detect if a chip container has entered the loading zone

and the lid closing zone

d. Microswitch is used to detect if the lid closing arm has spun to the correct initial

condition

e. Sensor circuit needs to output TTL digital signal with the appropriate voltage

level for digital high and digital low into the Microcontroller to be consumed

f. Sensors and sensors circuits should be detachable and easily connectable. This is

to increase the flexibility of the sensor attachment during integration.

3. Actuators

a. Be able to drive 6 DC motors with start/stop and bi-direction capabilities.

Microcontroller gives a two bit signal to specify the three states: clockwise,

counterclockwise, and stop.

37

b. Each driver circuit needs to deliver 2A max current. Figure * shows current

requirements of all motor used.

c. Driver circuit should protect the rest of the circuit system from current spikes,

voltage spikes and reverse polarity generated by DC motors

d. Buffers are needed for all driver input signals to protect the Microcontroller

from abnormalities generated in the driver circuit.

4. Circuit panel, cable management, and other design requirement

a. All circuits should be mounted on a circuit panel and should be easily

disassembled and replace when necessary

b. Connections between circuits should be easily assembled and disassembled to

increase modularity and reparability. Connection mechanism should also be

reliable and safe to reduce the chance of loose connections and short circuits

c. Circuits should be modularity to increase resistance to breaking and flexibility

when integrating into the machine

d. Circuits and electrical components such as sensors and motors should also be

pluggable to increase modularity, flexibility, and reparability

e. Wires should be shortened to increase elegance and minimize noise

f. Circuit system should have LED indicators to indicate the states of all sensor

output signals and motor input signals in order to help with the debugging

process.

6.2 SOLUTIONS

6.1 OVERVIEW In accordance with the above design requirements, the following comprehensive circuit

system is designed.

Power system

o main power board

o Power supply connection board

Sensor system

o main sensor board

o secondary sensor board

Actuator driver system

o 6 full H-bridge DC driver boards

o Buffer board

Microcontroller System

o Signal routing board

6.2 POWER BOARD

38

Figure 5.1 Power Bord

The role of the power board is to take the two power supply output, 12v and 5v, and distributed

to the entire machine according to the voltage requirements of each component. DC motors

generate high voltage and current spikes and high noise when operating, and these

abnormalities will propagate to any circuitry connected to the same power source as it. As we

have two motors running on 5V power source, in order to satisfy the regulated and noise-free

power requirement of sensors and Microcontroller, an additional 5V power source must be

constructed and must be block off voltage/current spikes and noise generated from the motors.

The power board does this by taking the 12V power source from the power supply, and

regulates it to a 5 V power source by using a LM7805 voltage regulator. The LM7805 voltage

regulator is able to regulate an input voltage from 7.5 v to V, hence it provides over voltage

protection. The LM7805 has built-in over current protection and is able to output maximum 1A;

this forms the over current protection. A power diode is attached between the regulated power

ground and the un-regulated power ground. It allows current to only flow from the regulated

ground to the un-regulator ground; this forms the reverse polarity protection for the regulated

power source. A 67 uF capacitor grounds the 12 V input to the voltage regulator to dampen any

noise generated from the DC motors before they enter the voltage regulator. An additional 3

1uF ceramic capacitor grounds the regulated 5V power source to further dampen any noise

from the voltage regulator. From observations using an oscilloscope, this step up is enough to

remove any noise generated from DC motors. The full schematic is shown on Appendix 13.2.1.2

and is labeled as section A. Power line 1 is the regulated 5V and ground for sensor boards,

buffer board, and Microcontroller. These boards are placed here because their sensitive nature,

the existence of logic chips, and the requirement of a common ground if order for digital signals

for the Microcontroller to work. Power line 2 is the unregulated 5 V for the fin motors and their

associated driver circuit. Power line 3 is the unregulated 12 V for the base motor, sorter wheel

motor, the lid motor, and their associated driver circuit. Motor power sources are all

39

unregulated because motors and their driver circuit are not sensitive to noise and

voltage/current spikes in the power source.

The power board also integrates the emergency stop switch. The emergency stop chosen is a

toggle SPDT switch. This decision is made instead of a pushbutton because the state of the

emergency stop has to be remembered in hardware, which although is doable with a

pushbutton, the fear at the design stage was that it may not be reliable. A SR latch is

implemented to translate SPSD switch state into a digital high or low. This is done because the

state of the switch must be reported to the Microcontroller, and it must be used to control the

current flow of both 5V and 12V power line. Having to create a single digital signal and consume

such signal in multiple places is the more elegant and reliable. The decision is made to shut off

only power to the motors when the emergency switch is activated and leave all sensors and

microcontroller remaining active. There are several advantages to this system. First, all motors

are stopped regardless of what signal it received, which is guaranteed to be predictable and

reliable. Second, the Microcontroller can retain its operation state and resume its operation in

the event the emergency switch is activated. Third, the Microcontroller can also display

additional messages to users when the emergency switch is activated. Fourth, since the sensor

boards and buffer boards are also not affected, their LED indicators can indicate the state of all

sensor input signals and motor output signals without having actual motors connected; this is

tremendous help to the debugging process since one can verify the correctness of all signals

without risking unexpected motor movements; this also protected many accidents where the

wrong signal was sent to motor driver circuits where it could have burned the driver circuit. In

addition, this system also fits naturally with the existing power board configuration: the power

to sensor boards, buffer board, and Microcontroller is already separated by the voltage

regulator from the motor power; a switch mechanism for the two motor power lines that is

controllable by the emergency switch signal would suffice. A mechanical relay is chosen for this

purpose. The AXCOM P2 Signal relay has two separate SPSD switches controlled by one source

signal and each is used to control one of the two motor power lines. Since the current from the

digital signal is not large enough to switch on the relay (25mA supplied, 40 mA needed), a

general purpose 200mA signal transistor is used to amplify the signal from the switch and switch

on the relay. The switch signal is also connected to the Microcontroller. Section B on Appendix

13.2.1.2 shows the circuit schematics. Three LEDs indicate the operation state of power board;

the red LED indicate the signal output of the emergency switch, two green LEDs indicate the

current flow in the motor power lines. This allowed us to easily debug any problems with the

power and emergency switch.

6.3 POWER SUPPLY AND POWER SUPPLY CONNECTION BOARD The power supply used is a SuperPower AC adapter rated at 100V-240V VAC 60HZ for input, and

12V at 2A and 5V at 2A for output. Although from the power budget table we can see that the

maximum current for each of the sort wheel motors is 2 A, that is the stall current of the motor

and we do not expect the motor to completely stall. As indicated, the power supply is definitely

enough to sustain the average operation current of the entire system. Main advantage of the

power supply is its weight, which is 200g. As the power supply lacks a master switch, a master

switch is created along with a power supply connection board to house it. The power supply

connection board is connected to the power board by 12V, 5V and ground wires.

40

6.4 SENSORS

Figure 5.2 Primary sensor board

The role of the sensor board is to provide power for sensor to operate, take the sensor input,

interpret it into digital signal understood by the Microcontroller, and output the signal to

microcontroller. Two pairs of infrared emitters and detectors running in a breakpoint sensor

configuration are used to detect the passage of chips, and six micro-switches are used to detect

the position of various machine components. The IR emitter is two IR emitting diodeconnected

in series with a 100 ohm resistor. Two IR emitters are used because each IR emitter has an

emitting angle of 20 degrees; two emitters greatly increase the IR coverage and decrease the

accuracy needed when installing the emitter and receiver pair on to the machine. Since the

chips are expected to fully cover both emitters with ease, the increase coverage will not affect

the sensor ability to detect chips passing through the pairs. The receiver is an IR sensitive photo-

transistor. It allows current to flow through when exposed to IR, and stops the current flow

when there is no IR. Appendix 13.2.1.3 shows the IR controller schematics. The 10M ohm

resistor controls the voltage level at point A depending on the amount of current allowed by the

photo transistor. The higher the current, the higher the voltage at point A. A LM358N duo- op

Amp is used to compare this sensor voltage with a reference voltage and output a digital signal.

The reference voltage is constructed by voltage division using 2 100k ohm resistors, creating a

reference voltage of 2.5v. If the sensor voltage is higher than the reference voltage, the op Amp

will output the highest voltage it can, which in this case is 5 V; if the sensor voltage is lower than

the reference voltage, the op Amp will output the lowest voltage it can, which is 0 V. Digitally, 5

V is a digital high, 0 V is a digital low. This forms the basis of IR sensor functionality. A red LED is

attached to the output of the op Amp; this allows one to view the state of the sensor output as

it is inputted to the Microcontroller. Since each LM358N chip has two op amps, two IR sensor

controller circuit is built with one LM358N chip. A four holes screw driver terminal is used to

connect the emitter and receiver to the controller. This is used because the wire to the sensor

41

would be long and loose strand wire is used instead of pin wires to reduce cost, and this allows

one to securely connect loose strand wires.

Micro-switches also use similar controller mechanism to output a digital signal instead of being

connected directly to the Microcontroller. This is because doing so would is unsafe and poses

too much danger to the delicate Microcontroller. Appendix 13.2.4 shows the schematics for the

micro-switch controller and the micro-switch used. The micro-switch is a SPDT switch. A

LM385N op Amp is used to compare the voltage from the micro-switch to a reference voltage.

One terminal of the micro-switch is connected to 5 V source and the other terminal is grounded.

The reference voltage is created by two 10 k ohm resistors. One switch is touching one terminal,

the sensor voltage is 5V and is higher than the reference voltage, the op amp outputs 5V; when

the switch is flipped and touching the other terminal, the sensor voltage is 0V and is lower than

the reference voltage, the op amp outputs 0V. Outputs are compatible with the Microcontroller

and LED is also attached at the output to visualize the sensor output for debug purposes. Screw

driver terminals are also used. Four of these identical controllers are located on the main sensor

board, addition one is located on the secondary board due to space issues.

6.5 ACTUATOR DRIVERS

Figure 5.3 A cluster of 3 H-bridges

The actuators used in this machine are 6 DC motors requiring start/stop and bidirectional

functionality. Hence, the ideal driver circuit for each of the DC motor is a full H-bridge. Appendix

13.2.1.1 shows the schematic of the H-bridge circuit. The maximum stall current of the 12V DC

motor is 2A; it is the largest current draw device in the machine. TIP122/TIP127 can provide a

maxmium current draw of 5A, hence they are selected as the transistor for the full H-bridge

circuit. Although TIP112/TIP117 is cheaper and has less maximum current hence is suitable for

the two small fin motors, the reduction in price is very small and is not worth the decrease in

exchangeability between H-bridge circuits of different types. Therefore, all H-bridge circuits are

42

constructed identically with TIP122/TIP127 so that they are interchangeable and increase the

ease of installation and the ease of replacement. Extra general purpose 200mA transistors are

added to the traditional H-bridge circuits as it is shown on the schematics. This transistor serves

as a protection gate between the small and stable current in the digital signal and the large and

unstable current in the driver circuit. DC motors often generate reverse current going through

the base of the power transistor. This transistor can also stop the reverse current reaching the

digital circuits that generate the motor signals. The resistors are also calculated precisely to limit

the current and protect the transistors. Each H-bridge circuit is constructed on a single board

and controls only one motor. Although this design adds extra redundancy during wiring, board

usage and layouts, it is worth the price to pay for ease of replacement, since H-bridge circuits

are easily destroyed when the signals inputted are incorrect. Two signals controls the transistors

on either side to open; if the both sides are opened, the H-bridge will short circuit, and cause

the transistor to burnout. We combat this by using the emergency switch to shut off the motor

power, and observe the correctness of the motor signal through the LEDs on the buffer board

(discussed below) before turning the motor power back on. This and along with careful H-bridge

design, allows us to reduce H-bridge and buffer burnouts to zero during the debugging stage and

final runs.

Initially a decoder circuit made out of AND gates and NOT gates are used to control the H-bridge.

The Micro-controller provides the enble and direction signal, and the logic gates turns these two

signal into S0, S1 signal for each side of the H-bridge. This circuit is later found extremely

unreliable during the testing stage, partly because it does not have drop down resistors.

Whenever the micro-controller is floating, the logic output floats as well, and send wrong signal

to the H-bridge. Later, this was changed to a simpler buffer system and drop down resistors was

added.

Figure 5.4 Buffer board. Notice the indicator LEDs

43

The buffer board contains two CD6070 buffer chips to isolate the driver circuits from the

Microcontroller. This is to protect the Microcontroller from the expectances in the driver circuit.

The buffer board also has a drop down resistor on each of the input signal from the

Microcontroller. The resistors pull the input signals down to ground when the input signal is

floating but still retains the input signal’s state in normal operation. To do this, resistors with

resistance that matches the internal resistance of the buffer is used. The issue of floating was

very apparent when programming Microcontroller and H-bridges are involved. When

programming the Microcontroller, all inputs were floating which causes both sides of the H-

bridge to open and burns the H-bridge. Drop down resistors were added later on to the buffer

board and completely resolved this issue. LED indicators also installed on the output signals of

the buffers. From them one can view the state of each motor signal, which helped tremendously

in the debugging process. Appendix 13.2.1.5 shows the schematics of one of the buffer system.

6.6 MICROCONTROLLER AND SIGNAL ROUTING BOARD

Figure 5.5 Signal routing board

The Devbugger board is used for the microcontroller. The decision was made because of the

presence of RTC, USB, and programmer components that are needed for the machine’s software.

The complexity and the potential reliability issues in building these ourselves far outweighs the

reduction in weight and cost that the DevBugger was selected. Because the DevBugger is often

detached from the machine for programming purposes, a signal routing board is built to

permanently collect all the signal connections and route them to the correct pin assignment on

a 40pin IDC cable. The DevBugger board is connected to all the signals through the 40 pin IDC

cable. In addition to signals, the DevBugger’s regulated 5 V Vcc and three ground pins are also

routed into the 40 pin IDC cable and connected to the power board’s 5 V regulated power

source and the associated ground line. This allows the DevBugger to run on power supply power

and no additional cables. Throughout the testing and running, the DevBugger has not

44

experienced issues with inferences from other parts of the circuit. This is a testament to the

protection and de-noise capabilities build into the power board.

6.7 CIRCUIT PANEL AND CABLE MANAGEMENT Including the DevBugger, there are 12 circuit boards in total. To make the installation has easy

as possible and reduce the amount of wiring present, all circuit boards are installed on to a

wood board and forms a circuit panel. Circuits are installed on both sides of the circuit panel to

reduce the amount of wood used, and wires are made to go through the circuit panel to connect

boards on either side. The circuit panel is attached to the machine by two screws. The

requirement that all circuit must be dissembled and assembled easily meant soldering them

together is not an option; connectors must be used. As result, the focus is then shifted to find a

secure connector that does not come off easily. Screw driver terminals are used because it was

assumed that they would provide the benefit of easily installation (wire can detached and

plugged) while being secure enough so that no loose connection can occur. However, for power

boards, buffer boards, and signal distribution board, the number of ports are too high to use

screw driver terminals. After considered that fact all these connections are made in between

circuits and the distance between them are short, a pin to pin wire is selected. Wiring posed a

significant issue to the integration process. The details of which is explained in the integration

section. Improvements in this area should definitly be made.

45

7 MICROCONTROLLER SUBSYSTEM (SOFTWARE)

7.1 OVERVIEW The role for the software component of the Chip Washer machine is to provide users a better

human-device interaction interface and control the mechanical components with more accurate

algorithm during runtime.

7.2 PROBLEM ASSESSMENT The software of the machine needs to have following functionality to accommodate the normal

operation of the machine as required by the RFP:

Usable user interface that accomplish all the relevant configuration of a qualified

machine operation

Allow user to enter the patterns for containers

Display emergency stop information

Display pattern loaded

Accurately control motors bi-directionally to stop at desired location based on sensor

readings during chips loading and lid covering

Actively read sensor information to count number of chips left

Display time information of the operation

Display number of chips left

The solution and implementation of the functionalities above are explained into detail in the

solution subsection.

In terms of programming stype, the software programming should use separate code files for

different functional purposes, which provides great maintainability of the software. The

implementation is also explained in the solution.

7.3 SOLUTION Chip Washer uses a microcontroller PIC16F877 as the central computing unit for the software

and motor/sensor control. Peripheral circuits for the microcontroller are equipped on

DevBugger provided by the aerospace laboratory. Since chip washer utilizes almost all the

features on the DevBugger, it seems to be the most time-efficient way to build a machine

prototype with the pre-built board. However, for the purpose of mass-production, printed

circuit board (PCB) can also be built to reduce the cost and weight.

The hardware of user interface is composed of one 4*4 keypad, and 2*15 LCD Display (see

Figure below). The microcontroller communicates with the circuit subsystem with a 40-pin IDE

cable. Other major hardware components include HITACHI 44780 LCD decoder and DS1307 Real

Time Clock IC powered with 3V battery.

Chip Washer is equipped with one of the most stable, flexible, and convenient software

environment. Features include customizable bottle numbers, customizable patterns,

customizable pre-set patterns, permanent machine running log, PC interface for diagnosis etc.

These features allow the software to run on a machine with higher capacity without changing

46

any code. All complex features are implemented on PIC16F877, which is cheaper compared to

PIC18F4620.

Some basic low-level components Paging, Delay, Stack Library, Math Library, Data Table Library,

LCD Library, Keypad Library, Permanent Storage Library. Major higher level components include

UI, Loading Scheme (Motor/Sensor Control), Real Time Clock and Timing, Permanent Logging

Service, and PC Interface. The implementation of all the components above will be explained to

detail in the subsections. Memory organization of each component will be mentioned

individually, but the general memory organization table is in the Appendix. Pin assignment is

also in the Appendix for reference. Block diagram below briefly illustrates the relations between

the major components of the software.

7.3.1 PIN ASSIGNMENT PIC16F877 microcontroller has a total of 40 pins for the purpose of communication with the

circuit subsystem. The details of the pin usage are summarized below.

Pin Name Direction Device Usage

RA0 I Chip Load Sensor 1 Detect Fin Position, Active High

RA1 I Chip Load Sensor 2 Detect Fin Position, Active High

RA2 I Fin Micro-switch Sensor 1 Detect Fin Position, Active Low

RA3 I Fin Micro-switch Sensor 2 Detect Fin Position, Active Low

RA4 I Load Micro-switch Sensor Detect Base Position, Active High

RA5 I Lid Micro-switch Sensor Detect Base Position, Active High

RB1, 4-7 I 4*4 Keyboard Communication

RB2 O Fin Wheel 1 Motor H-bridge second bit

RB3 O Fin Wheel 1 Motor H-bridge first bit

RC0 O Reservoir Wheel Motor H-bridge first bit

RC1 O Reservoir Wheel Motor H-bridge second bit

RC2 O Fin Wheel 2 Motor H-bridge first bit

RC3 I/O RTC Communication

RC4 I/O RTC Communication

RC5 O Fin Wheel 2 Motor H-bridge second bit

RC6 O Base Motor H-bridge second bit

RC7 O Lid Cover Motor H-bridge first bit

RD0-7 I/O 4 rows, 20 cols, 5*8 LCD Communication

RE0 O Lid Cover Motor H-bridge second bit

RE1 I Lid Cover Sensor Lid Cover Angle Finished, Active High

RE2 I Base Motor H-bridge first bit

7.3.2 FILE SYSTEM Chip Washer software is programmed with maximum modularity and maintainability. One

example is the separation of code files which allows each part of the program to be built

separately with lowest interdependency. All code file (.asm) is paired with a macro (.inc) file,

which is a parallel to .c file and .h (header) file in C programming language. File that needs

47

subroutines from other codes only has to import the macro file that is paired with the code,

instead of import all the subroutines manually. The .asm and .inc file pair is further explained in

the diagram below:

CODE.ASM file (code) CODE.INC file (header)

Other code file

global <_subroutine>

_subroutine:

(subroutine logics)

return

extern <_subroutine>

Subroutine: macro

fcall _subroutine

endm

include <code.inc>

Subroutine

The table below is a summary of all the files in the Chip Washer software. The file names will be

referenced frequently in the subsequent sections.

File name Description Delay.asm Time delay library Delay.inc Time delay library header Eeprom.asm Permanent storage read/write library Eeprom.inc Permanent storage read/write library header Fcall.inc Far call header I2c.asm I2C communication library Keypad.asm Keypad library Keypad.inc Keypad library header Lcd.asm LCD library Lcd.inc LCD library header Loader.asm Loading chips scheme Loader.inc Loading chips scheme header Main.asm Main entry point of the software Math.asm Math library Math.inc Math library header Motor.inc Motor macros Rtc.inc RTC macros Stack.inc Software stack library Table.asm Data table library

48

Table.inc Data table library header Timer.asm Timer library Timer.inc Timer library header Ui.asm UI lower level library Ui.inc UI lower level library header Ui2.asm UI higher level library Ui2.inc UI higher level library header

7.3.3 PAGING To achieve high code stability, one of the foremost problems to solve is paging of flash memory

and general purpose registers. Paging allows two more bits in the program address by explicitly

store two bits in the general purpose register, thus increase the accessible program memory by

a factor of 4. Chip Washer software uses 80% of the program memory of PIC16F877, consisted

of all four pages of the memory. If paging is not correctly configured, then the software might

malfunction because the program counter might run into a wrong program address and

execute. The solution of paging problem is the utilization of banksel, pagesel, lcall, lgoto

directives from the MPASM compiler, and the creation of fcall macro. Banksel and pagesel

directives calculate the upper bits of the program address and add to the program while during

compiling process. Fcall macro makes sure the page is set back to the current program line when

finishes a call. The actual code of fcall is in <fcall.inc> file.

7.3.4 STACK Chip Washer software achieved very high code efficiency by using modularized subroutines

instead of the use of macro code. One of the issues that come with using subroutines is

parameter passing and result returning. In C programming language or some other high level

programming language, a software stack is often used to pass parameters and result returning.

To solve this issue, Chip Washer software built a software stack for the purpose of parameter

passing and result returning.

The mechanism of a software stack is further explained in the diagram below. Similar to the file

system diagram, the diagram below adds one more layer of call stack and return stack.

Therefore, the other code file does not need to know the local addresses of the file registers

used by the code library; instead, it passes parameters to the stack which is shared by the entire

program. After the execution of the subroutine logics, the results are stored in the return stack

waiting for the retrieval by the caller. The implementation of stack library is in <stack.inc> file.

49

CODE.ASM file (code) CODE.INC file (header)

Other code file

Call Stack

Return Stack

global <_subroutine>

_subroutine:

(subroutine logics)

return

extern <_subroutine>

Subroutine: macro param1, param2

fcall _subroutine

endm

include <code.inc>

Subroutine param1, param2

param1 (0x00)

param2 (0x01)

result1 (0x00)

result2 (0x01)

StackWrite param2

StackWrite param1

StackRead param1

StackRead param2

StackWrite result1

StackWrite result2

StackRead result1

StackRead result2

7.3.5 MATH One of the drawbacks of using PIC16F877 microcontroller is a lack of multiplication/division

arithmetic unit. To compensate this loss of feature, software code of multiplication/division is

needed. To correctly display and parse user data on bottle numbers and timing (Chip Washer

can allow users to enter a maximum of 99 bottles if possible), binary/decimal number

50

conversion must also be implemented. Implementation of features above is implemented in

<math.inc> and <math.asm> files (for binary/decimal conversions, the code is in LCD.asm for

bin-dec and UI.asm for dec-bin). The diagram below explains how to call the functions.

Call Stack for Multiply

Return Stack for Multiply

Call Stack for Divide

Return Stack for Divide

Multiplier A (0x00)

Multiplier B (0x01)

Result (0x00)

Multiplier A (0x01)

Divisor (0x00)

Dividend (0x01)

Quotient (0x00)

Remainder (0x01)

The table below summarizes the memory organization of the math library.

Address Name Description 0x28 _Divisor Divisor parameter to division 0x29 _Dividend Dividend parameter to division 0x2A _Quotient Quotient of the division subroutine 0x2B _Multiplier A First multiplier parameter 0x2C _Multiplier B Second multiplier parameter 0x2D _MultiplyResult Result of the multiplication

7.3.6 DATA TABLE To display various UI messages on the LCD display, data table is needed in the code for more

clear and organized UI data, which is considered good coding practice. Data tables is achieved by

changing the program counter to the address of the data table, each line of which consists a

return argument that returns the element in the data table. Since PIC16F877 has page

constraints, directly calling data table will cause unstable behavior if the data table is not in the

first page or the data table exceeds 256 lines. One way of solving this is to manually check the

location of the data table and change the higher bits in the program counter to ensure that

paging is handled correctly. The table calling is implemented in <table.inc> and <table.asm>.

7.3.7 LCD Major functions of LCD component of the software is to handle low level LCD interface,

including initialize the LCD screen, display single character, shift cursor, turn on/off cursor,

switch line, clear LCD, display a message from any data table, rotate the message, display

current data time, display timing data from the memory. All command that associates with

51

HITACHI 44780 LCD decoder is stored in a macro of #define block on top of <lcd.asm> file.

Display message mechanism is simply a loop calling data tables until the stop token is reached

(for strings, the stop token is 0 character in ASCII). The implementation of the LCD component is

in <lcd.inc> and <lcd.asm>

7.3.8 KEYPAD The keypad component of the software initializes the keypad communication ports, and handles

low level polling and decoding of the keypad input when user input is expected. The keypad

decoding scheme converts the keypad input 4-bit data into ASCII character for LCD display, or

converts into binary number for decimal-binary number conversion. Other schemes defined in

the keypad component waits the user to input through key or simply reads from the current

keypad input value. The implementation of keypad is in <keypad.inc> and <keypad.asm> files.

7.3.9 UI The UI component is one of the higher level component in the software. It combines both

keypad and LCD scheme. It controls the flow of the text output and user input, and provides

prompt response and feedback for user. Because of its complexity, the UI component is split

into two pieces of code pairs: <ui.inc>, <ui2.inc>, <ui.asm>, and <ui2.asm>. Major functionalities

achieved in the UI component are:

1. Validate keystroke

2. Read input for a given number of maximum expected characters and character validator

(general purpose input box)

3. Parse number input

4. Parse pattern input

Each part above will be presented into detail in the subsections under UI.

Major scheme of the UI flow include:

1. Display welcome message

2. Ask user to input total number of containers

3. Let user to choose the pattern for each bottle from a preset menu

4. Let user to customize the pattern by inputting the pattern directly through keypad

5. Display all the patterns chosen for all the containers

6. Ask user to confirm the start of the machine operation

7. Display finish message

The general flow of the UI scheme is illustrated in the diagram below, the major components

will be explained into details in the subsections:

52

Start:Display welcome

messageDisplay current

date/time

Wait user to press any key

Display cancelled message

Prompt user to enter number of

containers

Prompt user to enter the pattern for

the Nth containerMenu router

If all containers patterns entered

Confirm to start

Customize pattern

Start of loading scheme

Finish of loading scheme

Yes

No

7.3.9.1 KEYSTROKE VALIDATION Different keystrokes are expected in different scenarios. For example, when the user is prompt

to enter the number of bottles, it would not make sense to display key input other than 0-9. In

other cases, only A/C keys are expected in the process of pattern customization. A generic

keystroke validator is designed such that a mask will be applied on all key event, and only keys

that are expected will be notified to the microcontroller input scheme. The separation of this

part as an individual functional unit is essential for the construction of a general purpose input

box which is explained in the next subsection.

Since the keypad has a size of 4*4, it needs two 8-bit validators (masks). For example, for

number input, the validator looks like:

Keys B 6 5 4 A 3 2 1 Lower bits masks 0 1 1 1 0 1 1 1 Keys D # 0 * C 9 8 7 Higher bits masks 0 0 1 0 0 1 1 1 For any keystroke, a keystroke byte will be sent to the mask. The construction of the keystroke

byte involves in a bit shifting of 0x1. For example, key A has the fourth order in the lower bits

mask, then 0x01 is shifted to the left for three times, which will result in a 0x08 keystroke byte.

The following table summarizes all the keystroke byte generated by the software:

Key\Bit 7 6 5 4 3 2 1 0 1 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 1 0 3 0 0 0 0 0 1 0 0 A 0 0 0 0 1 0 0 0 4 0 0 0 1 0 0 0 0 5 0 0 1 0 0 0 0 0

53

6 0 1 0 0 0 0 0 0 B 1 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 1 8 0 0 0 0 0 0 1 0 9 0 0 0 0 0 1 0 0 C 0 0 0 0 1 0 0 0 * 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 # 0 1 0 0 0 0 0 0 D 1 0 0 0 0 0 0 0

For Key 1-B, the keystroke byte will be masked by the lower bits mask, and for Key7-D, the

keystroke byte will be masked by the higher bits mask. If the masked value is not zero, then the

UI will display the keystroke, otherwise, the microcontroller will ignore the keystroke. More

details on passing the validator to the input box will be explained in the next subsection.

7.3.9.2 GENERAL PURPOSE INPUT BOX General purpose input box is useful in all kinds of user interaction scenarios. However,

constructing a generic input box is hard in microcontroller assembly language because it needs

to take into consideration of temporary input stack, key erasing, variable maximum length,

cursor position, and keystroke validation. Thankfully, keystroke validating unit is built to

accommodate the input box. For calling a general purpose input box subroutine, higher-bit

validator and lower-bit validator are expected to be in the call stack at relative address 0x01 and

0x00. Maximum length of the input box must also be specified. The length parameter should

stay in the call stack at relative address 0x02. The input stack will support 10 characters at

maximum, to accommodate the input of customized pattern. However, for other usage of the

input box, an address change will extend the maximum length to any length that is supported by

the memory space. The diagram below illustrates the memory organization of the input box,

including the call stack.

54

Software Stack (Call Stack) (0x67-0x70)

Lower bits validator (0x00)

Higher bits validator (0x01)

Input Stack (0x59 - 0x63)

Input stack pointer

Input stack (0x00)

Maximum length (0x02)......

Input stack (0x01)......Input stack (0x09)

Stack restore (0x41)

TempStack

Stack Pointer (FSR)

FSR

First, the subroutine uses stack pointer to read the input parameters: Lower bits validator,

higher bits validator and maximum length of the input box. Then, it saves the stack pointer to

the stack restore address (0x41), so it can use the FSR register for other indirect addressing

usage, in this case, the input stack. The input stack starts at address 0x63 and keeps

decrementing until it hits the address of the input stack pointer. The input stack pointer serves

as an end point of the input sequence for later parsing. After the characters are input, the stack

pointer (FSR) gets restored from the value saved in the stack restore address (0x41), and then

decrement the call stack and return.

The following diagram illustrates the entire program flow of the generic input box.

55

Detect keypad input

No

Get the input valueGenerate keystroke

byte

Mask with validatorValid keystroke?

Yes

No

Maximum length reached?

Yes

Move stack pointer, move cursor

position to the next

Display character and store in the

input stack

No

Yes

Check value

Start Submit End

# key

If at start of the input stack

Move stack pointer, move cursor

position to the previous

* key

Other keys

Yes

No

The picture below illustrates the actual user interface of the input box. Cursor stays right beside

the last input character. Characters can be erased by hitting “Corr” key at the left bottom. Input

box can be submitted by hitting “OK” key at the bottom.

56

7.3.9.3 INPUT NUMBER PARSING To have a programmable knowledge on the number of bottles entered by the user (assuming

the total number can exceed 9), a decimal-binary number conversion needs to be implemented

in the parsing scheme of the input stage. Thanks to the construction of math library in the

previous subsection, the conversion is not extremely difficult. The following chart illustrates the

flow of parsing a number from the input stack to the parsed input number address (0x64).

Read the current character from the

top of the input stack (hundredth

digit first)

Decode the keystroke into

number

Send the number to multiplication of 10

Add the number to the temporary

number

Reach the end of the stack?

Move the temporary number to parsed number

address

Save the stack pointer

Move the stack pointer to the input

stack

Yes

No

57

7.3.9.4 MENU ROUTING (PATTERN SELECTION) The menu routing scheme is an essential part of the user interaction. The most time spent is for

user to input the patterns. The developer of the software believes that it is not sensible to force

the user to remember the patterns and it will always be helpful to display the pattern on the

user interface to help the user to decide which pattern to load. Restricted by the size of the LCD

screen, only two patterns can be displayed at a time. Hence, a flow loop is designed to help user

browse across all the possible choices. Users can use hot key 1-6 to quickly select between

patterns 1-6 without the need to browse the menu. Table below summarizes the preset

patterns that come with the machine (can be modified using PC interface). Users can definitely

create a pattern imaginatively at any time by hitting hot key 7 to initiate a customized pattern

input. The mechanism of customized pattern includes the input box stage, which is explained

into detail in the previous subsections, and input parsing stage, which will be explained in the

next subsection. The design of the pattern selection scheme demonstrates the effort made to

maximize the user customizability and convenience in software development. The diagram

below illustrates the program flow of the menu routing.

Pattern Number Pattern (A for amber, C for camel) 1 CCCCCCCCCC 2 AAAAAAAAAA 3 CCCCCAAAAA 4 CCAACCAACC 5 AACCAACCAA 6 CACACACACA

58

Wait keystroke

Display Menu 1, 2

Wait keystroke Display Menu 3,4 Wait keystroke

Display Menu 5, 6

Wait keystrokeDisplay Menu 7

Copy the pattern to current pattern

Parse the input pattern

Copy the current pattern to

configuration storage

# key 1-6 key

# key

# key

# key

1-6 key

1-6 key

1-6 key

Customize pattern input

7 key

7 key

7 key7 key

Start

End

7.3.9.5 PATTERN PARSING To accommodate a full feature of customized patterns at runtime, parsing the patterns from the

input stack to the configuration storage is needed. The following diagram gives very good

explanation of mechanism of pattern parsing, which is similar (even simpler) than decimal-

binary number conversion.

Read the current character from the

input stack

Reach the end of the stack?

Move the temporary pattern to parsed pattern

address

Save the stack pointer

Move the stack pointer to the input

stack

Yes

Is character C or A?

No

Set the corresponding bit to

1

Set the corresponding bit to

0C

A

59

7.3.9.6 REAL TIME AND TIMING Real time display and timing component is achieved with DS1907 integrated circuit and the

corresponding socket on DevBugger board. The microcontroller communicates with the RTC

(Real Time Clock) circuit with I2C communication through PORTC pin 3 and 4. The

communication interface is summarized in table below:

Address 0x06 0x05 0x04 0x03 0x02 0x01 0x00 Description Year Month Day Weekday Hour Minute Second

As shown above, memory addresses in RTC chip give date time information. All 8-bit numbers

saved in those addresses are in decimal number format. For the upper four bits are the tenth

digit, and the lower four bits are the ones digit. RTC can be reset through writing values to each

memory addresses in RTC. The implementation of RTC module is in <rtc.inc> and <i2c.asm>.

RTC module is also utilized for timing purpose of the entire machine operation. Upon the start of

the operation, time information is stored in the memory. As the machine operation ends, the

program retrieves time information again. Since time information is stored in decimal format for

each digit, to do a proper subtraction, the software needs to first convert the decimal number in

each digit to a binary number. Carries are also handled in case the end time has second or

minute that is less than the start time. The diagram below illustrates the scheme of timing

module. The implementation of timing module is in <timer.inc>

Table below explains the memory organization of the Timing component.

Address 0x7C 0x7D 0x7E 0x7F Description Temporary

timer count Timer second Timer minute Timer hour

7.3.10 SENSOR AND MOTOR CONTROL Sensor and motor control component of the software are in charge of the entire automatic flow

of loading chips to the containers, adding lids of the containers, counting the remaining chips,

and returning the chips back to the reservoir. In detail, the flow of the machine can be

summarized into the following chart:

60

Loading scheme flow chart

Lid coveringLoadingInitializationBasic motor control Chip counting Chip returningPh

ase

Start

Initialization:Clear/Turn on timer

Display messageClear bottle counter

Write logs

Is the micro-switch hit?

Turn on motor

Turn motor on opposite direction

for small time delay and stop motor

No

Yes

Loading: Load next container

Turn base motor

Read patterns from memory

Is all 10 chips loaded?

Read next chip pattern

Are all containers

loaded

Cover lid: Turn base motor and wait for

lid micro-switch

5 empty passes though the sensor?

Rotate Fin C for small delay to overcome the micro-switch.

Rotate Fin A to previous position

If sensor A is activated

If maximum wait time is reached

No

Rotate Fin A for small delay to overcome the micro-switch.

Rotate Fin C to previous position

Increment chip A count

Yes

Yes

If sensor is activated

If maximum wait time is reached

No

Increment chip C count

Yes

Yes

No

Initialize Lid CoverInitialize Fin A/CRotate to initial

position

Initialize ReservoirRotate back and forth with time

delay to unjam the chips

Turn on motor for small time delay

Turn on motor for opposite direction

for small time delay

Turn off motor

Turn on motor for time delay

Overcome the load micro-switch

Overcome the lid micro-switch

No

Which color to load

Rotate Fin A to next position

Rotate Fin C to next position

Camel

Amber

Re-initialize the reservoir

Yes

No

Yes

Turn lid cover half way

Turn lid cover back half way

Reposition lid cover

Rotate Fin A for next position

Rotate Fin A for next position

If sensor C is activated

If sensor A is activated

If both A and C chips reached 5 empty passes

End

Clear empty pass for A

chips

Clear empty pass for A

chips

End:Stop all motors

Show chip counting information

Finish Machine Logs

Yes

Yes

No

Yes

Yes

No

Yes

No

61

7.3.10.1 INITIALIZATION In the initialization stage, motors including lid cover motor and fin motors get to find with their initial

position by detecting the micro-switches. Once this is done, the reservoirs start the unjam process of

rotating back and forth for several times until the chips are sorted into a line in front of the fins.

7.3.10.2 LOADING The loading stage starts with positioning the container into the right loading site by detecting micro-

switches. By reading the current loading pattern, the software decides which fin wheel to turn to load

the chip of correct colour.

7.3.10.3 LID COVERING After loading the correct pattern for the container, the base wheel continues to turn until the container

enters the lid covering site. The lid cover motor turns half way to cover and snap the lid, and then turns

back to re-position itself.

7.3.10.4 CHIP COUNTING After all containers are loaded and covered, the reservoirs continues to turn but with fins tuning in an

opposite direction. Meanwhile, IR sensors are polled to check the number of chips remaining. This

process continues until five empty passes through the IR sensors are reached.

7.3.10.5 CHIP RETURNING In the end, all remaining chips are returned back into the reservoir by turning reservoir wheel in the

clockwise direction and fin wheel in the counterclockwise direction. This process continues until five

empty passes through the IR sensors are reached.

7.3.10.6 SENSORS Software uses sensor polling instead of interrupt because polling gives maximum flexibility, stability and

maintainability. Time delay is inserted to stabilize polling input.

7.3.10.7 MOTORS Since the mechanical part of the machine uses only DC motors and micro-switches to control the

position, rotating on an opposite direction when the micro-switches are hit is necessary. Therefore,

most DC motor controls are equipped with two output pins, connected through a buffer circuit and

eventually signaling the H-bridges. H-bridge input standards are hence followed, specified in the table

below.

H-bridge (2 pins) 0, 0 0, 1 1, 0 Meaning Stop Counterclockwise Clockwise

The code implementation of the sensor and motor control are in <motor.inc>, <loader.inc>,

<loader.asm> files.

7.3.11 EMERGENCY STOP The software emergency stop is designed to be key “D”. After key “D” is hit during pattern configuration

and machine running, the program will exit and goto address 0x08, which is a reset vector to redirect

62

the program to display “Task cancelled” information on the LCD. After the emergency stop text is

displayed, the program is reset to the start point.

The way of reading emergency stop is still port polling. In any waiting stage (waiting sensor/user input),

polling on key “D” scheme is added so that emergency stop is allowed at this stage. Due to the high

speed of microcontroller operation, it is safe to assume that the keystroke of key “D” will last longer

than any other non-waiting stage of the code, so that the emergency keystroke can always be detected

by the microcontroller.

The software emergency stop is a different concept with the circuit emergency stop. After the circuit

emergency stop is hit, the microcontroller is still operating, which means after re-enabling the

emergency switch, the loading will continue from the previous point. If both emergency stops are hit,

then the loading scheme cannot be restored and the entire program is reset to the start position. The

separation of roles of two types of emergency stops allow user to decide whether a pause or a complete

stop is needed based on specific circumstances.

7.3.12 PERMANENT STORAGE Permanent storage allows the software to store data permanently even if the machine is powered off.

Two important information should be saved in the permanent storage: preset patterns and machine

logs.

<eeprom.inc>, <eeprom.asm> provide basic interface for reading and writing to the permanent storage.

The mechanism of reading and writing to the permanent storage is similar to indirect memory

addressing. Permanent memory address is written into EEADR register, and the value to read/write is

prepared in EEDATA register. EECON1 register controls whether to read or to write to the permanent

storage.

Storing preset pattern menu in the permanent storage gives greatest customizability and convenience

on user operations. Changing the preset menu can be done through PC interface, which will be

explained in the next subsection. Since each pattern contains 10 elements in a sequence (0 for amber

colour, and 1 for camel colour), it will need at least two bytes to store one single pattern. In this

software, only lower 5-bit are used, and two bytes in total to store a single pattern. Higher 3 bits are

remained to be 0. 6 preset patterns will consume 0x0C of the permanent memory, which is read during

menu display.

Permanent logging service is one of the advanced feature in the software. It not only records all the

information of each run, including start date/time, duration of operation, number of containers, pattern

for each container, success/failure of the operation, number of chips left. Permanent storage is utilized

at its maximum efficiency. The logs are at variable length depending on the number of containers, and

continue to write to the permanent storage of the microcontroller until the space are full. The actual

logging service comes with the loading scheme in <loader.asm>. Upon the start of each operation, the

logging service logs the start date/time, number of containers. At the end of each successful container

loading, the service updates the pattern loaded. At the end of a successful operation, the logging service

updates the status of the operation to successful, writes the number of chips left in the reservoir, and

fills the duration time of the operation. Permanent logs can be viewed and downloaded through PC

interface, which gives ultimate support on machine diagnosis.

63

The detail specification of the memory organization of each log is explained in the chart below:

Single Log EntryEEPROM Memory (0x00-0xFF)

Single Pattern (0 for A, 1 for C)

Preset Patterns (0x01-0x0C)

Machine Logs (0x0D-0xFF)

Start Value: 0xFF

Start Time: Year (Tens and Ones in Decimal from RTC)(0BTTTTOOOO)

Start Time: Month (0BTTTTOOOO)

Start Time: Day (0BTTTTOOOO)

Start Time: Hour (0BTTTTOOOO)

Memory Usage Pointer (0x00)

Preset Patterns

Machine Logs

Pattern Higher Bits (0B000PPPPP)

Pattern Lower Bits(0B000PPPPP)

Pattern #1

Pattern #2

Machine Log 1

Machine Log 2

...Machine Log N

...Pattern #6

Start Time: Minute (0BTTTTOOOO)

Start Time: Second (0BTTTTOOOO)

Duration: Minute (Binary)

Duration: Second (Binary)

Success State (S) Container Number (N) (0BSNNNNNNN)

Amber Chips Left (Binary)

Camel Chips Left (Binary)

Pattern 1

...Pattern N

7.3.13 PC INTERFACE PC interface is another advanced feature presented in the software. Two major functionalities are

achieved through PC interface: changing preset pattern menu and download the permanent logs. PC

interface has the ability to write and read from the EEPROM permanent memory of the microcontroller,

and parse the data internally and present friendly information to the users. PC interface is programmed

with C# (.NET technology), which has the most stable support across all Windows platform. PC interface

does not use the RS232 port. Instead, it directly uses USB port, which is more commonly used on

64

electronic devices with PC connectivity features. The PC interface is designed with maximal conciseness

and convenience. The following diagram summarizes the user interaction flow of the PC interface:

Start

Connect USB cable from computer to

the DevBugger

Turn on Programming Mode on the DevBugger

Open ChipWasher.exe

Click Download Button

Preset patterns and Machine Logs are

now downloaded on the screen

Enter the file name of the machine log to save on the local

computer

Click Reset ButtonMachine is now

reset to initial state

Machine log is downloaded to the

computer

Change preset patterns on the left and click Update

Machine preset patterns are

updated

The following picture is the screenshot of the PC interface.

For C# original code of the PC interface, please refer to Appendix.

7.4 IMPROVEMENTS AND SUGGESTIONS The Chip Washer has been made with the belief to perfection. All possible required and additional

features listed in the RFP have been considered and realized. While the space of improvement is

restricted, some suggestions could still be made to the current state of the software.

65

First, if time allowed, it might worth the time to construct an Interrupt Library. Interrupt service is not

used in the software because of its low maintainability and unreliability. But eventually, using interrupt

is a must because one cannot have a program scheme to poll millions of pins at the same time and do

corresponding reaction. Building such a library will made the software programming many times easier

because the entire software can be event-oriented, a classical model that is still widely in use in many

windows-based programs and mobile apps.

Second, although the current PC interface is reliable and usable, one possible improvement is writing a

native program on the microcontroller to send the EEPROM information instead of using the

programmer unit on the DevBugger, which might reduce some of the cost if microcontroller board is

self-made.

66

8 INTEGRATION

8.1 OVERVIEW After the completion of each individual subsystem, integrations are scheduled between the

electromechanical and circuit subsystems, and circuit and microcontroller subsystems. Since the entire

electromechanical subsystem is far behind the total schedule, after a brief test of the functionality of the

communication of all ports, both circuit and microcontroller member joined the process of of building

mechanical components. While building part of the electromechanical subsystem, integration continues

as the circuit boards are temporarily mounted on the machine to test partial functionality. The

integration process was not hugely influenced by the prolonged mechanical components construction

time.

8.2 INTEGRATION BETWEEN CIRCUIT AND ELECTROMECHANICAL COMPONENTS The integration between circuits and electromechanical components includes functionally integrating

sensors into mechanical structures, connecting sensors and motors to the circuit system, securing the

circuit systems on to the mechanical structure, and installing human interface elements which includes

the emergency switch, power switch, and the DevBuger Board.

Due to the prolonged delay in the electromechanical subsystem, sensor integration, which includes the

microswitches and the IR sensors was done at the same time that the mechanical strutures were built

since the electromechanical member and the circuit memeber was working togather. The details of the

integration was already described in the electromechanical section: section 4.2.3 for the fin microswitch,

section 4.2.9 for the base microswitchs, and section 4.2.7 for IR sensor. This model resulted in a few

advanteges. The first advantage is that the mechanical components are now built with the sensors in

mind. This is evident in the design of the fin as the fin and the sensor is integrated perfectly into one

functional system. This increase the overal functionality and the reliability of the sensor. The second

advantage is that the mechanical and electrical system are now tested togather, not only for their

individual function, but also how they work togather. The entire system is then incooperated into the

main system after all tests of integration is complete. This again increases overall reliability and

functionality. Lastly, efficency is greately enhanced, since there is no more taking complete systems

apart to install additional systems. The fin could not have accomplished without the circuit and

electromechanical member working togather like this.

When part of the mechanical components were complete, the circuits system were mounted onto the

machine to test out some functionality. This includes the top resevior layer and the base layer. However,

at that time the circuit panel was not developed and each board was mounted on individually. This

resulted extremely complex and unmanagable wiring, and resulted in the creation of the circuit panel to

house all of the circuits in one place.

Wiring methodolgy for the motors and sensors were already described in the circuit section 5.7. During

the integration, the most time consuming aspect is connecting each wire from the sensors and the

motors to the screw driver terminals. The doube sided circuit panel made the circuits on the inside of

the panel especially diffcult to connect. This is because all of the circuits on the inside are the H-bridges

and all of the H-bridges uses the screw driver terminal to connect with wires. Although the terminals

sound good on paper, they are a pain when used with circuits that located on the inside of the circuit

panel: the tight space made it extremely difficult to insert the stranded wire into the slot of the terminal,

67

and the screw driver often do not have enough space to turn the screw. As result, many screws are not

turned tightly enough and connections often get lost. Thoughts were gave to rectify this situation.

However, the Devbugger board has to be mounted on the outside of the panel and hence, the H-bridges

has to be mounted inside. This is because that is the only way by which all of the boards can be

squeezed on to the circuit panel. Patients were given to try to connect each wire to the terminal as tight

as possible, and care was given to not to distrub the wires to cause loose connections. A better terminal

and a better circuit allocation should be used for future improvements.

The use of the pin to pin wires also caused problems. Wires were often touched and pulled, which

caused the thin metal pin to bend. It turns out the wire pins are fragile to fatigue, and many of the pins

were broken after a few bends. This caused a lot of headaches as the connections between circuits have

to be re-made, which is difficult since many of the connections are on the inside of the already mounted

circuit panel. A better quality pin to pin wire should used for future improvements

8.3 INTEGRATION BETWEEN CIRCUIT AND MICROCONTROLLER 40-pin IDE cable are chosen as the communication wiring between the microcontroller and the rest of

the circuit board because of its simplicity. Output and input test code are programmed on the

microcontroller for debugging purpose (checking connections). In the output test code, all motors are

rotate clockwise, then counterclockwise, and then stop for one second each. This is an effective way to

check whether the motor circuit (voltage and ground) are connected in the correct order. In the input

test code, all the port readings are converted to decimal numbers on the LCD screen to check if the

sensors are connected and active high/low of the sensors are correct.

In the beginning, motor signal decoder is used between the microcontroller and the H-bridges, so that

the direction and enable bits can be separated. But later we found that this configuration is not very

stable, because the circuit cannot with stand float signal, so the microcontroller has to stay on for the

entire time. Later, the decoder circuit is removed and replaced by a buffer circuit which automatically

pulled down the float signal. This allows the microcontroller to be programmed with the rest circuit on,

which significantly enhanced the security of the integration between the microcontroller and the circuit

subsystems.

The microcontroller board is powered by the 5V Vcc and GND port in the 40-pin port, which gives the

maximum simplicity and portability.

During the testing stage, the LEDs that indicate sensor output and motor input were especially helpful.

They helped to debug many circuit and DevBug board connection problems. They also helped to debug

many of the software bugs where the software is sending out the wrong signal or has an unexpected

behavior. It also helped to test the entire system without actual motor operations, which protected the

motors and driver board from damage. The LEDs accelerated the integration and debug process greatly.

8.4 ACCOMPLISHED SCHEDULE The following Gantt chart truthfully represents the actual project progress. It differs much from the

proposed time management schedule mainly on the electromechanical subsystem because of a lack of

realization on the difficulty, and a lack of time awareness. The electromechanical subsystem was able to

finish with the assistance from circuit and microcontroller members, but resulted in a lack of debugging

time, so not enough time was before the public demonstration to find out the problem of the base

68

motor, and no time to substitute the motor. Time management on the electromechanical subsystem is

definitely one area that needs improvement in the future.

ID Task Name Start Finish DurationJan 2013 Feb 2013 Mar 2013 Apr 2013

1/13 1/20 1/27 2/3 2/10 2/17 2/24 3/3 3/10 3/17 3/24 3/31 4/7 4/14

1 64d4/9/20131/10/2013Electromechanical subsystem

2 17d2/1/20131/10/2013Overall design

3 17d2/25/20132/1/2013Reservoir prototyping

4 23d3/5/20132/1/2013Base layer

5 5d3/18/20133/12/2013Frame

11 48d4/9/20132/1/2013Circuit subsystem

21 57d4/9/20131/21/2013Microcontroller subsystem

12 19d3/1/20132/5/2013H-bridges

22 3d2/5/20132/1/2013Pin assignment

23 12d2/5/20131/21/2013Keypad/LCD interface

24 14d2/22/20132/5/2013UI flow

25 2d2/25/20132/22/2013Loading scheme

26 1d2/26/20132/26/2013RTC

28 1d4/8/20134/8/2013PC interface

27 1d4/8/20134/8/2013Permanent log

29 11d3/12/20132/26/2013Integration with circuits

14 4d3/13/20133/8/2013Power board

13 19d3/1/20132/5/2013Sensors

15 1d4/1/20134/1/2013Buffer board

16 9d2/15/20132/5/2013Decoder board

17 3d3/4/20132/28/2013Microcontroller connection board

32d4/1/20132/15/2013Integration between circuits

6 5d3/26/20133/20/2013Reservoir layer 1

7 19d4/5/20133/12/2013Reservoir layer 2

8 21d4/5/20133/8/2013Motor mounting

9 14d4/8/20133/20/2013Sensor mounting

10 7d4/9/20134/1/2013Integration and debugging

30 7d4/9/20134/1/2013Debugging

11d3/12/20132/26/2013Integration with Microcontroller

20 15d4/9/20133/20/2013Integration with Electromechanic

18

19

9 SYSTEM ISSUES AND IMPROVEMENTS Motor is a huge part that affect the success of the machine. The failure in the Public Demonstration was

also largely due to the breakdown of the base motor. First, more realistic calculation on the motor

should have taken place in the planning stage of the project so many mismatch motor testing could be

avoided later in the debugging stage. Second, motors should always be installed on the basis of easy

replacement. The failure of the motor mounting process of one of the reservoir layer has proven this

point. If the base motor had been installed more accessibly, the issue happened in the public

demonstration could have possible been avoided. More work should be done in terms of controlling the

overall motor power. Currently motor power output are controlled directly by placing high power

resistors in series with the motor, which is an inefficient solution in terms of power usage. Gearing is

also worth investigating since if reservoir and base motors are built with high torque, then it will be less

susceptible to the weight of chips, which will improve the motor accuracy for loading chips and less

69

chance of chip jamming in the reservoir. Some chip jamming still occurs at the fin because of lack of

accuracy in controlling the angle of the fin. Since the fin does not need high torque and high power,

servo motor might worth implementing in this case.

More accessible design on the middle reservoir layer might improve the user-friendliness of the machine.

Although currently the reservoir design maximize the accessibility of the chips, but only to the top layer.

For the middle reservoir layer, it is still relatively hard to place chips in and take chips out of the

reservoir. Large design change such as staggered layer design, expandable layer using hinge might worth

trying to improve the accessigbility issue.

PCB circuit is definitely worth implementing on a project scale like this. PCB has advantages such as light

weight, low probability of error, low probability of loose connection, etc. This advantages will push the

project quality and reliability up one level.

If time allowed, it is also great practice to solder another microcontroller board for the purpose of

manufacturing. DevBugger is great board to start with the programming, but once the program solidates,

board that is exclusively made for the machine seems necessary. This will reduce the unnecessary

weight and cost brought by the DevBugger Board.

Lastly, time management has shown to be one of the greatest problem existing in the team. The team

nearly redid most of the mechanical components during the system integration. The delay in the

completion of the mechanical subsystem significantly affected the quality of the integration and

debugging process, which is partially accountable for the failure in the Public Demonstration.

70

10 BUDGET Electromechanical Components

Module Component Unit Price ($)

Quantity Vendor Subtotal ($)

Materials for the entire machine

Sheet wood 5.50 1 Home depot 5.50

Wood stick (round)

2.20 1 Home depot 2.20

Balsa wood stick

1.20 1 Home hardware

1.20

Wood stick (square)

2.20 1 Home depot 2.20

Aluminum sheet

1.00 3 Active Surplus

30

Roller bearing 1.00 8 Active Surplus

80

Lazy Susan bearing

3.50 3 Home Depot 10.50

Nails, screws, nuts, bolts, glue, and steel wire

- - Home Depot 6.00

Reservoir layer, Lid closing

12V 50 rpm DC Motor

13.30 3 Creatron 39.90

Reservoir layer and Base layer

5V 65 rpm DC Motor

7.50 3 Creatron 22.50

Subsystem Total 101.00

71

Cicruits and Microcontroller

Module Component Unit Price ($) Quantity Vendor Subtotal ($)

H- Bridge

TIP 122 0.4 2 DigiKey 0.8

TIP 127 0.4 2 DigiKey 0.8

1k ohm, 1/4 w resistor 0.02 2 Creatron 0.04

100k ohm, 1/4 w resistor 0.02 2 Creatron 0.04

Screw driver terminal 0.5 1 Active surplus

0.5

2N3904 0.16 2 Creatron 0.32

Circuit board 1.2 1 Creatron 1.2

Module subtotal

3.7

six H-bridge total

- - - - 22.2

Buffer board

CD7080 buffer chip 0.8 2 Creatron 1.6

LED 0.05 12 Creatron 0.6

1k ohm, 1/4 w resistor 0.02 12 Creatron 0.24

100 k ohm, 1/4w resistor 0.02 12 Creatron 0.24

Chip seats 0.5 2 1

Circuit board 2 1 Creatron 2

12 pin hole connector 1.4 2 Creatron 2.8

Module subtotal

8.48

Primary Sensor Board

LM358N 1.3 3 Creatron 3.9

1k ohm, 1/4 w resistor 0.02 16 Creatron 0.32

10M ohm, 1/4w resistor 0.02 2 Creatron 0.04

333k ohm, 1/4w resistor 0.02 4 Creatron 0.08

LED 0.05 6 Creatron 0.3

Screw Driver terminal 0.3 6 Active surplus

1.8

6 pin hole connector 1.2 1 Creatron 1.2

Chip seats 0.5 3 Creatron 1.5

Circuit board 2 1 Creatron 2

Module subtotal

11.14

72

Cicruits and Microcontroller Cont.

Secondary Sensor Board

LM358N 2.2 1 Creatron 2.2

1k ohm, 1/4 w resistor 0.02 2 Creatron 0.04

10M ohm, 1/4w resistor 0.02 1 Creatron 0.02

LED 0.05 1 Creatron 0.05

6 pin hole connector 1.2 1 Creatron 1.2

Chip seats 0.5 1 Creatron 0.5

Circuit board 1.5 1 Creatron 1.5

Module subtotal

5.51

Power board

74LS00 0.98 1 Creatron 0.98

AXCOM P2 01222 V23079 Signal relay

1.78 1 Project kit 1.78

78S05 5V voltage regulator

1.2 1 Home hardware

1.2

Toggle switch 1 1 Active surplus

1

68 μF Capacitor 0.3 1 Creatron 0.3

1 μF Capacitor 0.16 3 Creatron 0.48

2N3904 0.16 1 Creatron 0.16

Circuit board 2 1 Creatron 2

LED 0.05 3 Creatron 0.15

Screw Driver terminal 0.3 2 Active surplus

0.6

6 pin hole connector 1.2 2 Active surplus

2.4

Module subtotal

11.05

Signal relay board

IDC 40 pin connector 1.5 1 Creatron 1.5

20 Pin hole connector 2.5 1 Creatron 2.5

Circuit board 1.5 1 Creatron 1.5

Module subtotal

5.5

Power supply connector board

4 Pin power supply connector

2.8 1 Creatron 2.5

DPDT switch 1.5 1 Project kit 1.5

4

Module subtotal

12V , 5V power supply 9.9 1 Active surplus

9.9

DevBug Board 50 1 Project kit 50

73

Cicruits and Microcontroller subsystem total 127.78

System Total 227.58

74

11 CONCLUSION Chip Washer is considered a viable solution with extra design features addressing to the original

problem. Although the public demonstration performance was not satisfactory, the failure was largely

due to the mechanical construction quality but not the design concept. Suggestions are made in the

report for future improvement, which will make the machine more stable and reliable.

Major portion of the report focuses on the design highlight of each subsystem. The design features

highlight the uniqueness and effectiveness of the entire machine. Chip Washer is designed with extra

capacity and features, which consequently increased the difficulty of construction, which the team did

not take in consideration with the previous experience associated with machine building. Many of

mechanical components had to be redone by all three members in the integration stage, which delayed

the entire schedule of project completion. The full debugging process was too late to make large scale

changes to the system, and the base motor, one of the least stable components, broke down during the

public demonstration. Although it was unfortunate about the timing of the motor breaking down, it is an

indicator of lack of stability and reliability of the current prototype machine.

With a wide range of improvement suggestions made in the report, Chip Washer has a future to be fixed

if more time is given. Problems showed up in the Public Demonstration can be solved under the same

machine design. Chip Washer is believed to be the greatest solution to meet the need of the game

company on chip packaging.

12 REFERENCES [1] M.R.Emami, Multidisciplinary Engineering Design: From Theory to Practice, 2013 Ed. New

York NY, McGraw Hill, 2013

[2] Wikipedia contributors. (2013). Backgammon. [Online]. Available:

http://en.wikipedia.org/wiki/Backgammon

[3] Wikipedia contributors. (2013). Packging and labeling. [Online]. Available:

http://en.wikipedia.org/wiki/Packaging_and_labeling

75

13 APPENDIX

13.1 ELECTROMECHANICAL COMPONENTS

13.1.1 LAZY SUSAN BEARING

Name Size Shape Center hole diameter

Normal balancing load capacity

Part Number

Price

4 Lazy 4" Lazy Susan Bearing from Triangle Manufacturing Company

4’’ Square 2.170’’ 300 lbs 4C $2.10 (ebay)

Lazy Susan Blueprint, retrieved Jan. 25, 2010, from http://www.triangleoshkosh.com/assets/files/cad-

drawings-lazy-susans/lazy-susan-4c.pdf

76

13.2 CIRCUITS

13.2.1 SCHEMATICS

13.2.1.1 H-BRIDGE

1 K ohm

TIP 127 TIP 127

PIC Signal, S1

100k ohm 100k ohm

PIC Signal, S0

Ground

5/12 V

TIP 122TIP 122

2N3904

2N3904

77

13.2.1.2 POWER BOARD

LM7805

Common

Power Supply 12V

68 uF Capacitor5 V regulator Sensor and

Micro-controller Power, Line 1

1

Battery Common

Power Supply 5V

IN4003 Power Diode

12 V Motor Power, Line 2

5 V Motor Power, Line 3

Signal Relay

NPN Transistor

1 uF capacitor

Section 1 Voltage regulation

Emergency Stop and Motor Power Control

Toggle switch

13.2.1.3 IR BREAK POINT SENSOR CONTROLLER

Duo IR Emitter LTE 5208A

Green LED

1 Ohm Resistor

Chip Passing

Photo transistor LTR-3208E

10M ohms resistor333k ohms resistor

333k ohms resistor

LM385N duo op amp-

+

1k ohm resistor

Signal indicating LED

To PIC

Regulated 5V

Ground

78

13.2.1.4 MICROSWITCH CONTROLLER

Signal Indicating LED

1k ohm resistor

1k ohm resistor 1k ohm resistor

1k ohm resistor

1k ohm resistor

Micro-switch

+

-

Regulated 5V

Ground

To PIC

LM358N

13.2.1.5 BUFFER

10k ohm resistor1k ohm resistor

Signal indicating LED

To MotorFrom PICCD7050 Buffer Chip

Regulated 5V

Ground

79

13.3 MICROCONTROLLER

13.3.1 GENERAL PURPOSE REGISTER ORGANIZATION Addr File Name Description

0x20 lcd.asm _LcdCommandBuffer Buffer for sending a command to the LCD

0x21 lcd.asm _LcdDataBuffer Buffer for sending data to the LCD

0x22 lcd.asm _LcdNumberPtr Stack pointer to the last digit of the output number

0x23 lcd.asm _LcdNumberChar Output number digit stack (255 max)

0x24 lcd.asm _LcdNumberChar+0x1 Output number digit stack

0x25 lcd.asm _LcdNumberChar+0x2 Output number digit stack (least significant bit)

0x26 lcd.asm _LcdNumberEnd End of the number output stack (constant 0)

0x27 lcd.asm _LcdNumberRemainder Remainder of the number division operation

0x28 math.asm _Divisor Parameter divisor to the Division subroutine

0x29 math.asm _Divident Parameter divident to the Division subroutine

0x2A math.asm _Quotient Return parameter quotient of the Division subroutine

0x2B math.asm _MultiplierA The first multiplier

0x2C math.asm _MultiplierB The second multiplyer

0x2D math.asm _MultiplyResult The multiply result

0x2E table.asm PclTemp Save the program counter higher bits

0x2F loader.asm BottleNumber Total number to bottles

0x30 loader.asm CurrentLoadBottle Currently loading bottle

0x31 loader.asm CurrentLidBottle Currently bottle adding lid

0x32 loader.asm CurrentLoadPatternH Current loading bottle pattern higher

0x33 loader.asm CurrentLoadPatternL Current loading bottle pattern lower

0x34 loader.asm CurrentLoadChip Current loading chip

0x35

0x36

0x37 loader.asm _LoaderChipMask

0x38 loader.asm _LoaderChipMaskCount

0x39 loader.asm _TempSensor

0x3A

0x3B

0x3C

0x3D

0x3E

0x3F

0x40 stack.inc TempW Temporary backup for working register

80

when operating on the stack

0x41 stack.inc TempStack Temporary stack pointer backup for operating on other types of stack other than the default one

0x42 ui.asm TempW Temporary save working register

0x43 ui.asm TempMask Temporary mask by rotating 1

0x44 ui.asm TempCounter Temporary counter for rotating the mask

0x45 loader.asm

0x46 loader.asm

0x47 loader.asm

0x48 loader.asm

0x49 loader.asm

0x4A eeprom.asm Address

0x4B eeprom.asm Value

0x4C keypad.asm Index

0x4D usart.asm TIMCNT

0x4E usart.asm LPCNT

0x4F usart.asm TDATA

0x50

0x51

0x52

0x53

0x54

0x55 delay.inc Counter Counter for number of multiples of delay

0x56 delay.asm d1 Variable for counting the loop

0x57 delay.asm d2 Variable for counting the loop

0x58 ui.asm _UIInputLength Specify the maximum expected length of a given input

0x59 ui.asm _UIInputStackPtr Input stack pointer (the last input character)

0x5A ui.asm _UIInputStack Input stack (10 characters maximum)

0x5B ui.asm _UIInputStack+0x1 Input stack

0x5C ui.asm _UIInputStack+0x2 Input stack

0x5D ui.asm _UIInputStack+0x3 Input stack

0x5E ui.asm _UIInputStack+0x4 Input stack

0x5F ui.asm _UIInputStack+0x5 Input stack

0x60 ui.asm _UIInputStack+0x6 Input stack

0x61 ui.asm _UIInputStack+0x7 Input stack

0x62 ui.asm _UIInputStack+0x8 Input stack

0x63 ui.asm _UIInputStack+0x9 Input stack start

0x64 ui.asm _UIInputNumber The parsed number

0x65 ui.asm _UIInputStackPtrEnd The end of the input stack

0x66 ui.asm _UIInputMax If the maximum input limit is reached

81

0x67 stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x68 stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x69 stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x6A stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x6B stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x6C stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x6D stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x6E stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x6F stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x70 stack.inc StackPtr Stack pointer for passing subroutine parameters, subroutine variable, and subroutine return results

0x71 rtc.inc StackPtr rtc

0x72 rtc.inc StackPtr rtc

0x73 rtc.inc StackPtr rtc

0x74 rtc.inc StackPtr rtc

0x75 rtc.inc StackPtr rtc

0x76 rtc.inc StackPtr rtc

0x77 rtc.inc StackPtr rtc

0x78 rtc.inc StackPtr rtc

0x79 isr.asm WTemp Save the working register temporarily for handling interrupt

0x7A isr.asm StatusTemp Save the Status register temporarily for handling interrupt

0x7B isr.asm PCLATHTemp Save the program counter temporarily for handling interrupt

0x7C timer.asm TimerCount Timer counter from the interrupt. Count every 1/8 second

0x7D timer.asm TimerSec Second part of the counter (59 max)

82

0x7E timer.asm TimerMin Minute part of the counter (59 max)

0x7F timer.asm TimerHour Hour part of the timer (255 max)

0xA0 ui2.asm #1 Pattern lower

0xA1 ui2.asm #1 Pattern higher

0xA2 ui2.asm #2 Pattern lower

0xA3 ui2.asm #2 Pattern higher

0xA4 ui2.asm #3 Pattern lower

0xA5 ui2.asm #3 Pattern higher

0xA6 ui2.asm #4 Pattern lower

0xA7 ui2.asm #4 Pattern higher

0xA8 ui2.asm #5 Pattern lower

0xA9 ui2.asm #5 Pattern higher

0xAA ui2.asm #6 Pattern lower

0xAB ui2.asm #6 Pattern higher

0xAC ui2.asm #7 Pattern lower

0xAD ui2.asm #7 Pattern higher

0xAE ui2.asm #8 Pattern lower

0xAF ui2.asm #8 Pattern higher

0xB0 ui2.asm #9 Pattern lower

0xB1 ui2.asm #9 Pattern higher

0xB2 ui2.asm #10 Pattern lower

0xB3 ui2.asm #10 Pattern higher

0xB4 ui2.asm BottleNumber Bottle number

0xB5 ui2.asm _UIPatternCount Counter for number of patterns entered

0xB6 ui2.asm _UIMenuSelection Menu selection number

0xB7 ui2.asm _UICurrentPatternH Current parsed pattern higher

0xB8 ui2.asm _UICurrentPatternL Current parsed pattern lower

83

13.3.2 MICROCONTROLLER ORIGINAL SOURCE CODE

DELAY.ASM ;**********************************************************************

; Delay for 10ms

;**********************************************************************

ifndef Stack

#include <stack.inc>

endif

global _Delay

global _ShortDelay

global _TinyDelay

cblock 0x55

DelayCounter

d1

d2

endc

__Delay: code

; Delay for 2ms

Delay10:

movlw 0xe6

movwf d1

movlw 0x4

movwf d2

;movlw 0x86

;movwf d1

;movlw 0x5

;movwf d2

Delay10Cycle:

decfsz d1, f

goto $+2

decfsz d2, f

goto Delay10Cycle

84

goto $+1

nop

return

_ShortDelay:

movlw 0x3

movwf d1

movlw 0x0

movwf d2

_ShortCycle:

decfsz d1, f

goto $+2

decfsz d2, f

goto _ShortCycle

goto $+1

nop

return

_TinyDelay:

movlw 0xff

movwf d1

_TinyCycle:

decfsz d1, f

goto $-1

return

; Call Delay 10

_Delay:

movwf DelayCounter

_Cycle:

call Delay10

85

decfsz DelayCounter, f

goto _Cycle

return

end

86

DELAY.INC ;**********************************************************************

; Delay Library

;**********************************************************************

ifndef Stack

#include <stack.inc>

endif

extern _Delay

extern _ShortDelay

extern _TinyDelay

Delay: macro Time ; multiples of 10 ms

movlw Time

fcall _Delay

endm

;ResWheelPWM: macro Time

; movlw Time

; fcall _ResWheelPWM

; endm

;

;LongResWheelPWM: macro

; ResWheelPWM 0xff

; ResWheelPWM 0xff

; ResWheelPWM 0xff

; ResWheelPWM 0xff

; endm

LongDelay: macro

Delay 0xff

Delay 0xff

Delay 0xff

Delay 0xff

endm

87

ShortDelay: macro

fcall _ShortDelay

endm

TinyDelay: macro

fcall _TinyDelay

endm

88

EEPROM.ASM ;**********************************************************************

; EEProm Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and exports">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc>

endif

ifndef TinyDelay

#include <delay.inc>

endif

ifndef Pattern1H

#define Pattern1H b'00011111'

#define Pattern1L b'00011111'

#define Pattern2H b'00000000'

#define Pattern2L b'00000000'

#define Pattern3H b'00011111'

#define Pattern3L b'00000000'

#define Pattern4H b'00011001'

#define Pattern4L b'00010011'

#define Pattern5H b'00000110'

#define Pattern5L b'00001100'

#define Pattern6H b'00010101'

#define Pattern6L b'00001010'

endif

global _EEPromWrite

global _EEPromRead

#define _TempEEPtr 0x3b

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Variables and constants">

cblock 0x4a

89

Address ; 0x4a

Value ; 0x4b

endc

;</editor-fold>

code

_EEPromWrite:

banksel EECON1

btfsc EECON1, WR ; Wait for

goto $-1 ; write to finish

banksel Address

movfw Address ; Address to

banksel EEADR

movwf EEADR ; write to

banksel Value

movfw Value ; Data to

banksel EEDATA

movwf EEDATA ; write

banksel EECON1

bcf EECON1, EEPGD ;Point to Data memory

BSF EECON1, WREN ;Enable writes

movlw 0x55 ;Write 55h to

movwf EECON2 ;EECON2

movlw 0xaa ;Write AAh to

movwf EECON2 ;EECON2

bsf EECON1, WR ;Start write operation

bcf EECON1, WREN ;Disable writes

banksel PORTA

;TinyDelay

return

_EEPromRead:

banksel Address

90

movfw Address ;Write address

banksel EEADR

movwf EEADR ;to read from

banksel EECON1

bcf EECON1, EEPGD ;Point to Data memory

bsf EECON1, RD ;Start read operation

banksel EEDATA

movfw EEDATA ;W = EEDATA

banksel Value

movwf Value

movfw Value

banksel PORTA

return

end

91

EEPROM.INC ;**********************************************************************

; EEProm Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and exports">

ifndef PORTA

#include <pic16f877.inc>

endif

ifndef _EEPromWrite

extern _EEPromWrite

extern _EEPromRead

endif

#define EEPromAddr 0x4a

#define EEPromValue 0x4b

#define EEPromAddrPtr 0x0

#define EEPromPattern1H 0x1

#define EEPromPattern1L 0x2

#define EEPromPattern2H 0x3

#define EEPromPattern2L 0x4

#define EEPromPattern3H 0x5

#define EEPromPattern3L 0x6

#define EEPromPattern4H 0x7

#define EEPromPattern4L 0x8

#define EEPromPattern5H 0x9

#define EEPromPattern5L 0xa

#define EEPromPattern6H 0xb

#define EEPromPattern6L 0xc

#define Pattern1H b'00011111'

#define Pattern1L b'00011111'

#define Pattern2H b'00000000'

#define Pattern2L b'00000000'

#define Pattern3H b'00011111'

#define Pattern3L b'00000000'

#define Pattern4H b'00011001'

92

#define Pattern4L b'00010011'

#define Pattern5H b'00000110'

#define Pattern5L b'00001100'

#define Pattern6H b'00010101'

#define Pattern6L b'00001010'

;</editor-fold>

EEPromWrite: macro

fcall _EEPromWrite

endm

EEPromRead: macro

fcall _EEPromRead

endm

EEPromReadA: macro Addr

banksel EEPromAddr

movlw Addr

movwf EEPromAddr

fcall _EEPromRead

endm

93

FCALL.INC fcall macro Line

lcall Line

pagesel $

endm

movff macro File1, File2

banksel File1

movfw File1

banksel File2

movwf File2

endm

movfws macro File

banksel File

movfw File

endm

movwfs macro File

banksel File

movwf File

endm

94

I2C.ASM include <p16f877.inc>

errorlevel -302

errorlevel -305

;global labels

global write_rtc,read_rtc,rtc_convert,i2c_common_setup,p2p_write,p2p_read

;Definition and variable declarations;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

cblock 0x71 ;these variable names are for reference only. The following

dt1 ;0x71 addresses are used for the RTC module

dt2 ;0x72

ADD ;0x73

DAT ;0x74

DOUT ;0x75

B1 ;0x76

dig10 ;0x77

dig1 ;0x78

endc

;I2C lowest layer macros;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

i2c_common_check_ack macro err_address ;If bad ACK bit received, goto err_address

banksel SSPCON2

btfsc SSPCON2,ACKSTAT

goto err_address

endm

i2c_common_start macro

;input: none

;output: none

;desc: initiate start conditionon the bus

banksel SSPCON2

bsf SSPCON2,SEN

95

btfsc SSPCON2,SEN

goto $-1

endm

i2c_common_stop macro

;input: none

;output: none

;desc: initiate stop condition on the bus

banksel SSPCON2

bsf SSPCON2,PEN

btfsc SSPCON2,PEN

goto $-1

endm

i2c_common_repeatedstart macro

;input: none

;output: none

;desc: initiate repeated start on the bus. Usually used for

; changing direction of SDA without STOP event

banksel SSPCON2

bsf SSPCON2,RSEN

btfsc SSPCON2,RSEN

goto $-1

endm

i2c_common_ack macro

;input: none

;output: none

;desc: send an acknowledge to slave device

banksel SSPCON2

bcf SSPCON2,ACKDT

bsf SSPCON2,ACKEN

btfsc SSPCON2,ACKEN

goto $-1

endm

96

i2c_common_nack macro

;input: none

;output: none

;desc: send an not acknowledge to slave device

banksel SSPCON2

bsf SSPCON2,ACKDT

bsf SSPCON2,ACKEN

btfsc SSPCON2,ACKEN

goto $-1

endm

i2c_common_write macro

;input: W

;output: to slave device

;desc: writes W to SSPBUF and send to slave device. Make sure

; transmit is finished before continuing

banksel SSPBUF

movwf SSPBUF

banksel SSPSTAT

btfsc SSPSTAT,R_W ;While transmit is in progress, wait

goto $-1

banksel SSPCON2

endm

i2c_common_read macro

;input: none

;output: W

;desc: reads data from slave and saves it in W.

banksel SSPCON2

bsf SSPCON2,RCEN ;Begin receiving byte from

btfsc SSPCON2,RCEN

goto $-1

banksel SSPBUF

movf SSPBUF,w

97

endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

code

i2c_common_setup

;input: none

;output: none

;desc: sets up I2C as master device with 100kHz baud rate

banksel SSPSTAT

clrf SSPSTAT ;I2C line levels, and clear all flags

movlw d'24' ;100kHz baud rate: 10MHz osc / [4*(24+1)]

banksel SSPADD

movwf SSPADD ;RTC only supports 100kHz

movlw b'00001000' ;Config SSP for Master Mode I2C

banksel SSPCON

movwf SSPCON

bsf SSPCON,SSPEN ;Enable SSP module

i2c_common_stop ;Ensure the bus is free

return

;rtc Algorithms;;;;;;

write_rtc

;input: address of register in RTC

;output: none

;Desc: handles writing data to RTC

;Select the DS1307 on the bus, in WRITE mode

i2c_common_start

movlw 0xD0 ;DS1307 address | WRITE bit

i2c_common_write

i2c_common_check_ack WR_ERR

;Write data to I2C bus (Register Address in RTC)

98

banksel 0x73

movf 0x73,w ;Set register pointer in RTC

i2c_common_write

i2c_common_check_ack WR_ERR

;Write data to I2C bus (Data to be placed in RTC register)

banksel 0x74

movf 0x74,w ;Write data to register in RTC

i2c_common_write

i2c_common_check_ack WR_ERR

goto WR_END

WR_ERR

nop

WR_END

i2c_common_stop ;Release the I2C bus

return

read_rtc

;input: address of RTC

;output: DOUT or 0x75

;Desc: This reads from the selected address of the RTC

; and saves it into DOUT or address 0x75

;Select the DS1307 on the bus, in WRITE mode

i2c_common_start

movlw 0xD0 ;DS1307 address | WRITE bit

i2c_common_write

i2c_common_check_ack RD_ERR

;Write data to I2C bus (Register Address in RTC)

banksel 0x73

movf 0x73,w ;Set register pointer in RTC

i2c_common_write

i2c_common_check_ack RD_ERR

;Re-Select the DS1307 on the bus, in READ mode

99

i2c_common_repeatedstart

movlw 0xD1 ;DS1307 address | READ bit

i2c_common_write

i2c_common_check_ack RD_ERR

;Read data from I2C bus (Contents of Register in RTC)

i2c_common_read

banksel 0x75

movwf 0x75

i2c_common_nack ;Send acknowledgement of data reception

goto RD_END

RD_ERR

nop

;Release the I2C bus

RD_END i2c_common_stop

return

rtc_convert

;input: W

;output: dig10 (0x77), dig1 (0x78)

;desc: This subroutine converts the binary number

; in W into a two digit ASCII number and place

; each digit into the corresponding registers

; dig10 or dig1

banksel 0x76

movwf 0x76 ; B1 = HHHH LLLL

swapf 0x76,w ; W = LLLL HHHH

andlw 0x0f ; Mask upper four bits 0000 HHHH

addlw 0x30 ; convert to ASCII

movwf 0x77 ;saves into 10ths digit

banksel 0x76

100

movf 0x76,w

andlw 0x0f ; w = 0000 LLLL

addlw 0x30 ; convert to ASCII

movwf 0x78 ; saves into 1s digit

return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;pic to pic subroutines;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

p2p_write

;Select the DS1307 on the bus, in WRITE mode

i2c_common_start

movlw b'00010000'

i2c_common_write

i2c_common_check_ack W_END

banksel 0x70

movf 0x70, W

i2c_common_write

i2c_common_check_ack W_END

goto W_END

W_END

i2c_common_stop ;Release the I2C bus

return

p2p_read

;Select the DS1307 on the bus, in WRITE mode

i2c_common_start

movlw b'00010001'

i2c_common_write

i2c_common_check_ack R_END

i2c_common_read

banksel 0x70

101

movwf 0x70

i2c_common_nack ;Send acknowledgement of data reception

R_END

i2c_common_stop

return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

End

102

KEYPAD.ASM ;**********************************************************************

; Keypad Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and exports">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc>

endif

ifndef Delay

#include <delay.inc> ; delay

endif

ifndef StackInit

#include <stack.inc> ; stack

endif

global _KeypadInit

global _KeypadDecode

global _KeypadDecodeNumber

global _KeypadReadChar

global _KeypadWaitChar

#define Index 0x4c

;</editor-fold>

_Keypad: code

;<editor-fold defaultstate="collapsed" desc="_KeypadInit: Initialize the keypad">

_KeypadInit:

banksel TRISA

movlw b'11110010'

movwf TRISB

103

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_KeypadDecode: Decode lookup table">

_KeypadDecode:

;dt "123A456B789C*0#D", 0

banksel Index

movfw Index

sublw 0x0

btfsc STATUS, Z

retlw '1'

movfw Index

sublw 0x1

btfsc STATUS, Z

retlw '2'

movfw Index

sublw 0x2

btfsc STATUS, Z

retlw '3'

movfw Index

sublw 0x3

btfsc STATUS, Z

retlw 'A'

movfw Index

sublw 0x4

btfsc STATUS, Z

retlw '4'

movfw Index

sublw 0x5

btfsc STATUS, Z

104

retlw '5'

movfw Index

sublw 0x6

btfsc STATUS, Z

retlw '6'

movfw Index

sublw 0x7

btfsc STATUS, Z

retlw 'B'

movfw Index

sublw 0x8

btfsc STATUS, Z

retlw '7'

movfw Index

sublw 0x9

btfsc STATUS, Z

retlw '8'

movfw Index

sublw 0xa

btfsc STATUS, Z

retlw '9'

movfw Index

sublw 0xb

btfsc STATUS, Z

retlw 'C'

retlw 0x0

;</editor-fold>

105

;<editor-fold defaultstate="collapsed" desc="_KeypadDecodeNumber: Decode number lookup table">

_KeypadDecodeNumber:

banksel Index

movfw Index

sublw 0x0

btfsc STATUS, Z

retlw 0x1

movfw Index

sublw 0x1

btfsc STATUS, Z

retlw 0x2

movfw Index

sublw 0x2

btfsc STATUS, Z

retlw 0x3

movfw Index

sublw 0x4

btfsc STATUS, Z

retlw 0x4

movfw Index

sublw 0x5

btfsc STATUS, Z

retlw 0x5

movfw Index

sublw 0x6

btfsc STATUS, Z

retlw 0x6

movfw Index

sublw 0x8

106

btfsc STATUS, Z

retlw 0x7

movfw Index

sublw 0x9

btfsc STATUS, Z

retlw 0x8

movfw Index

sublw 0xa

btfsc STATUS, Z

retlw 0x9

retlw 0x0;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_KeypadReadChar: Poll keypad value from PORTB to W">

_KeypadReadChar:

banksel PORTB

swapf PORTB, w

andlw 0x0f

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_KeypadWaitChar: Wait until a key is hit from keypad">

_KeypadWaitChar:

;goto $

banksel PORTB

btfss PORTB, 1 ;Wait until data is available from the keypad

goto $-1

;Delay d'3'

swapf PORTB, w

andlw 0x0f

;call _KeypadReadChar

107

;banksel PORTB

btfsc PORTB, 1 ;Wait until key is released

goto $-1

return;</editor-fold>

end

108

KEYPAD.INC ;**********************************************************************

; Keypad Library

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports">

ifndef _KeypadInit

extern _KeypadInit

extern _KeypadDecode

extern _KeypadDecodeNumber

extern _KeypadReadChar

extern _KeypadWaitChar

endif

ifndef PORTA

#include <p16f877.inc>

endif

ifndef TableLookup

#include <table.inc>

endif;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="CheckKey">

CheckKey: macro Key, IfTrue

local IfTrueInit, CheckKeyEnd

addlw -Key

btfsc STATUS, Z

goto IfTrueInit

goto CheckKeyEnd

IfTrueInit:

lgoto IfTrue

CheckKeyEnd:

addlw Key

endm

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Check emergency stop">

109

CheckStop: macro

local Check

btfsc PORTB, 1

goto Check

goto CheckStopEnd

Check:

KeypadReadChar

CheckKey 0xf, 0x008

CheckStopEnd:

endm

;</editor-fold>

KeypadInit: macro

fcall _KeypadInit

endm

KeypadReadChar: macro

fcall _KeypadReadChar

endm

KeypadWaitChar: macro

fcall _KeypadWaitChar

endm

KeypadDecode: macro Index

; StackPushL HIGH _KeypadDecode

; StackPushL LOW _KeypadDecode

; StackInc

; StackWriteF 0x0, Index

; TableLookupHL

; StackDec 0x3

; TableLookup _KeypadDecode, Index

movff Index, 0x4c

fcall _KeypadDecode

endm

110

KeypadDecodeNumber: macro Index

; StackPushL HIGH _KeypadDecodeNumber

; StackPushL LOW _KeypadDecodeNumber

; StackInc

; StackWriteF 0x0, Index

; TableLookupHL

; StackDec 0x3

; TableLookup _KeypadDecodeNumber, Index

movff Index, 0x4c

fcall _KeypadDecodeNumber

endm

111

LCD.ASM ;**********************************************************************

; LCD Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports, exports and constants">

global _LcdInit

global _LcdWriteData

global _LcdWriteCommand

global _LcdSwitchLine

global _LcdClear

global _LcdRotateLeft

global _LcdHome

global _LcdCursorOn

global _LcdCursorOff

global _LcdDisplay

global _LcdRotate

global _LcdRotateN

global _LcdDisplayNumber

global _LcdDisplayTime

global _LcdCursorLeft

global _LcdCursorRight

global _LcdDisplayDateTime

global _LcdDisplayDate

#define _LcdRs PORTD, 2

#define _LcdEnable PORTD, 3

#define _LcdCommandClear b'00000001'

#define _LcdCommandSwitchLine b'11000000'

#define _LcdCommandShiftLeft b'00011000'

#define _LcdCommandCursorLeft b'00010000'

#define _LcdCommandCursorRight b'00010100'

#define _LcdCommandCursorHome b'00000010'

#define _LcdCommandCursorOn b'00001111'

#define _LcdCommandCursorOff b'00001100'

112

ifndef PORTA

#include <p16f877.inc> ; processor specific variable definitions

endif

ifndef fcall

#include <fcall.inc>

endif

ifndef TableLookup

#include <table.inc>

endif

ifndef Stack

#include <stack.inc> ; lcd constants

endif

ifndef Delay

#include <delay.inc> ; lcd constants

endif

ifndef Divide

#include <math.inc> ; math library

endif

ifndef TimerSec

#include <timer.inc> ; math library

endif

ifndef rtc_read

#include <rtc.inc>

endif

cblock 0x20

_LcdCommandBuffer ; 0x20: Buffer for instruction

_LcdDataBuffer ; 0x21: Buffer for LcdData

_LcdNumberPtr ; 0x22

_LcdNumberChar:0x3 ; 0x23,24,25

_LcdNumberEnd ; 0x26

_LcdNumberRemainder ; 0x27

endc

;</editor-fold>

113

_Lcd: code

;<editor-fold defaultstate="collapsed" desc="_LcdInit: Initialize LCD">

_LcdInit:

Delay 0x01

Delay 0x01

movlw b'00110011' ; First two 0011 sequences

fcall _LcdWriteCommand ; (Display sends two 4-bit chunks)

movlw b'00110010' ; Third 0011 sequence, then set to 4-bit

fcall _LcdWriteCommand

movlw b'00101100' ; 4 bits, 2 lines, 5x7 dots

fcall _LcdWriteCommand

movlw _LcdCommandClear

fcall _LcdWriteCommand

movlw b'00001100' ; Display on/off

fcall _LcdWriteCommand

movlw b'00000110' ; No auto shift left

fcall _LcdWriteCommand

clrf _LcdNumberEnd

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdStartWrite: Start to write a command">

_LcdStartWrite:

banksel PORTD

bsf _LcdEnable

Delay 0x01

bcf _LcdEnable

;Delay 0x01

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdWriteCommand: Write a command to LCD">

_LcdWriteCommand:

114

bcf _LcdRs ; Clear LcdRs

movwf _LcdCommandBuffer ; Instruction now has the value in the working register

andlw 0xf0 ; Mask 4 bits of most significant bits

banksel PORTD

movwf PORTD ; Send 4 bits most significant bits command

fcall _LcdStartWrite

swapf _LcdCommandBuffer, w ; Swap least significant bits to most significant bits

andlw 0xf0

banksel PORTD

movwf PORTD ; Send least significant

fcall _LcdStartWrite

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdWriteData: Write LcdData to LCD">

_LcdWriteData:

bsf _LcdRs

movwf _LcdDataBuffer ; Copy the working register to LcdDataa register

movf _LcdDataBuffer, w

andlw 0xf0 ; Get the higher bits

addlw 4 ; Add working register with 100

banksel PORTD

movwf PORTD ; Send working register to Port D

fcall _LcdStartWrite

swapf _LcdDataBuffer, w ; Swap least significant bits to most significant bits

andlw 0xf0

addlw 4

banksel PORTD

115

movwf PORTD

fcall _LcdStartWrite

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplay: Display a message on LCD">

_LcdDisplay:

StackPush Counter, 0x0

_LcdDisplayCharacterLoop:

TableLookupHL

xorlw b'00000000' ; Check work register to see if 0 is returned (reached the end of the string)

btfsc STATUS, Z

goto _LcdDisplayCharacterLoopEnd

fcall _LcdWriteData

incf Counter, f

goto _LcdDisplayCharacterLoop

_LcdDisplayCharacterLoopEnd:

StackDec 0x01

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplayNumber: Display a decimal number on the LCD">

_LcdDisplayNumber:

StackPushW Number1

StackPushW Number2

StackPushL 0xa

movlw _LcdNumberEnd

movwf _LcdNumberPtr

clrf _LcdNumberEnd

; Get each digit in the number

_LcdDisplayNumberLoop:

Divide

StackReadF Remainder, _LcdNumberRemainder

116

; Save the remainder in the number char array

StackSave

decf _LcdNumberPtr, f

movfw _LcdNumberPtr

movwf StackPtr

movfw _LcdNumberRemainder

addlw d'48'

movwf Stack

StackRestore

; Check if the quotient is zero

StackReadW Quotient

xorlw b'00000000'

btfsc STATUS, Z

goto _LcdDisplayNumberLoopEnd

; Swap the quotient as the new divident

StackReadW Quotient

StackWriteW Divident

StackWriteL Divisor, 0xa

goto _LcdDisplayNumberLoop

; Display the char string to the LCD

_LcdDisplayNumberLoopEnd:

StackSave

movfw _LcdNumberPtr

movwf StackPtr

_LcdDisplayNumberLoopEnd2:

movfw Stack

xorlw b'00000000'

btfsc STATUS, Z

goto _LcdDisplayNumberLoopEnd3

movfw Stack

117

fcall _LcdWriteData

incf StackPtr, f

goto _LcdDisplayNumberLoopEnd2

_LcdDisplayNumberLoopEnd3:

StackRestore

StackDec 0x3

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplayTime: Display time string">

_LcdDisplayTime:

; Process Hour

movlw 0xa

subwf TimerHour, w

btfsc STATUS, C

goto Next1

AddZero1:

movlw d'48'

fcall _LcdWriteData

Next1:

movfw TimerHour

fcall _LcdDisplayNumber

movlw 0x3a ; colon

fcall _LcdWriteData

; Process Minute

movlw 0xa

subwf TimerMin, w

btfsc STATUS, C

goto Next2

AddZero2:

movlw d'48'

fcall _LcdWriteData

Next2:

movfw TimerMin

fcall _LcdDisplayNumber

118

movlw 0x3a ; colon

fcall _LcdWriteData

; Process Second

movlw 0xa

subwf TimerSec, w

btfsc STATUS, C

goto Next3

AddZero3:

movlw d'48'

fcall _LcdWriteData

Next3:

movfw TimerSec

fcall _LcdDisplayNumber

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplayDateTime: display date time">

_LcdDisplayDateTime:

rtc_read 0x06 ;Read Address 0x06 from DS1307---year

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

movlw "/"

fcall _LcdWriteData

;Get month

rtc_read 0x05 ;Read Address 0x05 from DS1307---month

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

119

movlw "/"

fcall _LcdWriteData

;Get day

rtc_read 0x04 ;Read Address 0x04 from DS1307---day

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

movlw " "

fcall _LcdWriteData

;Get hour

rtc_read 0x02 ;Read Address 0x02 from DS1307---hour

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

movlw ":"

fcall _LcdWriteData

;Get minute

rtc_read 0x01 ;Read Address 0x01 from DS1307---min

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplayDate: display date">

_LcdDisplayDate:

; Get year

movlw "2" ;First line shows 20**/**/**

120

fcall _LcdWriteData

movlw "0"

fcall _LcdWriteData

rtc_read 0x06 ;Read Address 0x06 from DS1307---year

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

movlw "/"

fcall _LcdWriteData

;Get month

rtc_read 0x05 ;Read Address 0x05 from DS1307---month

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

movlw "/"

fcall _LcdWriteData

;Get day

rtc_read 0x04 ;Read Address 0x04 from DS1307---day

movfw 0x77

fcall _LcdWriteData

movfw 0x78

fcall _LcdWriteData

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdRotate: Rotate until the entire message is displayed">

_LcdRotate:

StackPush Counter, 0x0

121

_LcdRotateCharacterLoop:

TableLookupHL

xorlw b'00000000' ; Check work register to see if 0 is returned (reached the end of the string)

btfsc STATUS, Z

goto _LcdRotateCharacterLoopEnd

fcall _LcdRotateLeft

Delay 0x1f

incf Counter, f

goto _LcdRotateCharacterLoop

_LcdRotateCharacterLoopEnd:

fcall _LcdHome

StackDec 0x01

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdRotateN: Rotate N spot">

_LcdRotateN:

movfw Stack

StackPushW Number

_LcdRotateNCharacterLoop:

movfw Number

xorlw b'00000000'

btfsc STATUS, Z

goto _LcdRotateNCharacterLoopEnd

fcall _LcdRotateLeft

Delay 0x8f

decf Number, f

goto _LcdRotateNCharacterLoop

_LcdRotateNCharacterLoopEnd:

StackDec 0x01

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_Lcd: LCD Utilities">

_LcdSwitchLine:

movlw _LcdCommandCursorHome

122

fcall _LcdWriteCommand

movlw _LcdCommandSwitchLine

fcall _LcdWriteCommand

return

_LcdClear:

movlw _LcdCommandClear

fcall _LcdWriteCommand

return

_LcdRotateLeft:

movlw _LcdCommandShiftLeft

fcall _LcdWriteCommand

return

_LcdHome:

movlw _LcdCommandCursorHome

fcall _LcdWriteCommand

return

_LcdCursorOn:

movlw _LcdCommandCursorOn

fcall _LcdWriteCommand

return

_LcdCursorOff:

movlw _LcdCommandCursorOff

fcall _LcdWriteCommand

return

_LcdCursorLeft:

movlw _LcdCommandCursorLeft

fcall _LcdWriteCommand

return

_LcdCursorRight:

123

movlw _LcdCommandCursorRight

fcall _LcdWriteCommand

return

;</editor-fold>

End

124

LCD.INC ;**********************************************************************

; LCD Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and exports">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc>

endif

ifndef TableLookup

#include <table.inc>

endif

ifndef StackInit

#include <stack.inc>

endif

ifndef _LcdWriteData

extern _LcdWriteData

extern _LcdWriteCommand

extern _LcdSwitchLine

extern _LcdClear

extern _LcdRotateLeft

extern _LcdHome

extern _LcdCursorOn

extern _LcdCursorOff

extern _LcdDisplay

extern _LcdRotate

extern _LcdRotateN

extern _LcdDisplayNumber

extern _LcdDisplayTime

extern _LcdCursorLeft

extern _LcdCursorRight

extern _LcdDisplayDateTime

extern _LcdDisplayDate

125

endif

ifndef _LcdInit

extern _LcdInit

endif

ifndef Delay

#include <delay.inc> ; delay

endif;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdDisplay: Display a message on LCD">

LcdDisplay: macro Message

StackPushL HIGH Message

StackPushL LOW Message

fcall _LcdDisplay

StackDec 0x02

; movlw HIGH Message

; StackPushW HighBits

; movlw LOW Message

; StackPushW LowBits

; lcall _LcdDisplay

; StackDec 0x02

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdDisplayW: Display W value on LCD">

LcdDisplayW: macro

fcall _LcdWriteData

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdDisplayNumber: Display a decimal number on LCD">

LcdDisplayNumber: macro

fcall _LcdDisplayNumber

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdDisplayTime: Display the time string">

LcdDisplayTime: macro

126

fcall _LcdDisplayTime

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplayDateTime">

LcdDisplayDateTime: macro

fcall _LcdDisplayDateTime

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_LcdDisplayDateTime">

LcdDisplayDate: macro

fcall _LcdDisplayDate

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdRotate: Rotate until the entire message is displayed">

LcdRotate: macro Message

movlw HIGH Message

StackPushW HighBits

movlw LOW Message

StackPushW LowBits

fcall _LcdRotate

StackDec 0x02

endm

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdRotateN: Rotate N spot">

LcdRotateN: macro Number

StackPush number, Number

fcall _LcdRotateN

StackDec 0x01

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LcdDisplayAll: Display a message with shift left number">

LcdDisplayAll: macro Message, Number

127

LcdDisplay Message

LcdRotateN Number

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Lcd Utilities">

LcdInit: macro

fcall _LcdInit

endm

LcdSwitchLine: macro

fcall _LcdSwitchLine

endm

LcdClear: macro

fcall _LcdClear

endm

LcdRotateLeft: macro

fcall _LcdRotateLeft

endm

LcdHome: macro

fcall _LcdHome

endm

LcdCursorOn: macro

fcall _LcdCursorOn

endm

LcdCursorOff: macro

fcall _LcdCursorOff

endm

LcdCursorLeft: macro

fcall _LcdCursorLeft

endm

128

LcdCursorRight: macro

fcall _LcdCursorRight

endm

;</editor-fold>

129

LOADER.ASM ;<editor-fold defaultstate="collapsed" desc="Imports">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc>

endif

ifndef Delay

#include <delay.inc>

endif

ifndef StackInit

#include <stack.inc>

endif

ifndef LcdInit

#include <lcd.inc>

endif

ifndef KeypadInit

#include <keypad.inc>

endif

ifndef Divide

#include <math.inc>

endif

ifndef UIInit

#include <ui.inc>

endif

ifndef UILoading

#include <ui2.inc>

endif

ifndef TimerSec

#include <timer.inc>

endif

ifndef rtc_read

#include <rtc.inc>

endif

130

ifndef BaseStop

#include <motor.inc>

endif

ifndef EEPromAddr

#include <eeprom.inc>

endif

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Imports2">

extern Finish

extern _UIMessageLoading

extern _UIMessageCounting

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Exports">

global _LoaderLoad

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Constants">

#define Pattern 0xa0

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Variables">

cblock 0x2f

BottleNumber ;0x2f

CurrentLoadBottle ;0x30

CurrentLidBottle ;0x31

CurrentLoadPatternH ;0x32

CurrentLoadPatternL ;0x33

CurrentLoadChip ;0x34

ChipsLeftCountA ;0x35

ChipsLeftCountC ;0x36

_LoaderChipMask ;0x37

_LoaderChipMaskCount ;0x38

_TempSensor ;0x39

131

_TempSensorCounter ;0x3a

_TempEEPtr ;0x3b

endc

;</editor-fold>

_Loader: code

;<editor-fold defaultstate="collapsed" desc="Mask: Generate mask bits">

Mask:

movwf _LoaderChipMaskCount

clrf _LoaderChipMask

bsf _LoaderChipMask, 0

_MaskLoop:

movfw _LoaderChipMaskCount

xorlw b'00000000'

btfsc STATUS, Z

goto _MaskLoopEnd

decf _LoaderChipMaskCount, f

bcf STATUS, C

rlf _LoaderChipMask, f

goto _MaskLoop

_MaskLoopEnd:

return;</editor-fold>

_LoaderLoad:

TimerClear

TimerOn

LcdClear

LcdDisplay _UIMessageLoading

clrf CurrentLoadBottle

clrf CurrentLidBottle

132

banksel PORTA ; Make permanent entry

EEPromReadA EEPromAddrPtr ; Read address pointer

movfw EEPromValue

movwf EEPromAddr

movlw 0xff

movwf EEPromValue

EEPromWrite ; Make 0xff entry to initialize

incf EEPromAddr, f ; Write year

rtc_read 0x06

movfw 0x75

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write month

rtc_read 0x05

movfw 0x75

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write day

rtc_read 0x04

movfw 0x75

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write hour

rtc_read 0x02

movfw 0x75

movwf EEPromValue

EEPromWrite

133

incf EEPromAddr, f ; Write minute

rtc_read 0x01

movfw 0x75

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write second

rtc_read 0x00

movfw 0x75

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write duration temporarily

clrf EEPromValue

EEPromWrite

incf EEPromAddr, f

EEPromWrite

incf EEPromAddr, f ; Write bottle (not success for now)

movfw BottleNumber

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write chips left A temporarily

clrf EEPromValue

EEPromWrite

incf EEPromAddr, f ; Write chips left C temporarily

EEPromWrite

;fcall LoadInit

;_LoaderLoadBottleLoop:

134

; movfw BottleNumber

; subwf CurrentLoadBottle, w

; btfsc STATUS, Z

; goto _LoaderLoadBottleLoopEnd

fcall LoadBottle

; movlw d'1'

; subwf CurrentLoadBottle, w

; btfsc STATUS, Z

; goto _LoaderLoadBottleLoop1

;

; fcall CoverLid

; BaseStop

; goto _LoaderLoadBottleLoop

;_LoaderLoadBottleLoop1:

; BaseCCW

; Delay 0x40

;_LoaderLoadBottleLoop12:

; ;TinyDelay

; ;KeypadReadChar

; ;CheckKey 0xf, 0x008

; ;btfss BaseSensorLoad

; ;goto _LoaderLoadBottleLoop12

; BaseStop

; Delay 0xcf

; goto _LoaderLoadBottleLoop

;

;_LoaderLoadBottleLoopEnd:

; fcall CoverLid

; BaseStop

fcall CountChips

135

UIChipsLeft

fcall ReturnChips

_LoaderLoadEnd:

Delay 0x20

TimerOff

banksel PORTA ; Finish permanent entry

EEPromReadA EEPromAddrPtr ; Read address pointer

movlw d'9'

addwf EEPromValue, w

movwf EEPromAddr

EEPromRead

bsf EEPromValue, 7 ; Change success bit

EEPromWrite

movlw -d'2' ; Write duration

addwf EEPromAddr, f

movfw TimerMin

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f

movfw TimerSec

movwf EEPromValue

EEPromWrite

movlw d'2' ; Write chips count

addwf EEPromAddr, f

movfw ChipsLeftCountA

;movlw d'3' ; Comment this out to full run!!

movwf EEPromValue

EEPromWrite

incf EEPromAddr, f

movfw ChipsLeftCountC

136

;movlw d'3' ; Comment this out to full run!!

movwf EEPromValue

EEPromWrite

rlf BottleNumber, w

addlw 0x1 ; Change address pointer

addwf EEPromAddr, w

movwf EEPromValue

clrf EEPromAddr

EEPromWrite

movfw EEPromValue

movwf _TempEEPtr

lgoto Finish

return

;<editor-fold defaultstate="collapsed" desc="LoadInit: Initialize the machine">

LoadInit:

fcall LidCoverPosition ; Initialize the machine

fcall FinANextPosition

fcall FinCNextPosition

ResWheelCCW

Delay 0xff

fcall ResWheelInit

Delay 0xff

fcall ResWheelInit

Delay 0xff

fcall ResWheelInit

Delay 0xff

fcall ResWheelInit

Delay 0xff

fcall ResWheelInit

Delay 0xff

return

137

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LoadBottle: Position the bottle for loading chips">

LoadBottle:

; ResWheelStop

; BaseCCW

;LoadBottle1:

; BaseCCW

; ShortDelay

; ;btfsc BaseSensorLoad

; ;goto LoadBottle11

; ShortDelay

; ;btfsc BaseSensorLoad

; ;goto LoadBottle11

; BaseStop

; ShortDelay

; KeypadReadChar

; CheckKey 0xf, 0x008

; btfss BaseSensorLoad

; goto LoadBottle1

;LoadBottle11:

; BaseCW

; Delay 0x2

; BaseStop

; Delay 0xcf

; BaseCCW ; Go a little bit over the micro-switch

;LoadBottle2:

; BaseCCW

; ShortDelay

; ;btfss BaseSensorLoad

; ;goto LoadBottle22

; ShortDelay

; ;btfss BaseSensorLoad

; ;goto LoadBottle22

138

; BaseStop

; ShortDelay

; KeypadReadChar

; CheckKey 0xf, 0x008

; btfsc BaseSensorLoad

; goto LoadBottle2

;LoadBottle22:

; BaseCW

; Delay 0x34

;

; movlw 0x0 ; More back delay for bottle 1

; subwf CurrentLoadBottle, w

; btfss STATUS, Z

; goto LoadBottle2Next

;MoreDelay2:

; Delay 0x20

; Delay 0x32

;

;LoadBottle2Next:

; BaseStop

call LoadChips

; Change entry about the current bottle to success

; banksel PORTA

; EEPromReadA EEPromAddrPtr ; Read address pointer

; decf CurrentLoadBottle

; rlf CurrentLoadBottle, w

; incf CurrentLoadBottle, f

; addlw d'12'

; addwf EEPromValue, w

; movwf EEPromAddr

; EEPromRead

; bsf EEPromValue, 7 ; Change the success bit

; EEPromWrite

139

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="CoverLid: add the lid for the current bottle">

CoverLid:

ResWheelStop

banksel CurrentLidBottle

incf CurrentLidBottle, f

BaseCCW

CoverLid1:

BaseCCW

ShortDelay

;btfsc BaseSensorLid

;goto CoverLid11

ShortDelay

;btfsc BaseSensorLid

;goto CoverLid11

BaseStop

ShortDelay

KeypadReadChar

CheckKey 0xf, 0x008

btfss BaseSensorLid

goto CoverLid1

CoverLid11:

BaseCW

Delay 0x5

BaseStop

Delay 0xcf

BaseCCW ; go a little bit over the microswitch

CoverLid2:

BaseCCW

ShortDelay

140

;btfss BaseSensorLid

;goto CoverLid22

ShortDelay

;btfss BaseSensorLid

;goto CoverLid22

BaseStop

ShortDelay

KeypadReadChar

CheckKey 0xf, 0x008

btfsc BaseSensorLid

goto CoverLid2

CoverLid22:

BaseCW

Delay 0x2d

; movlw 0x1 ; more back delay for 1

; subwf CurrentLidBottle, w

; btfss STATUS, Z

; goto CoverLid2Next

;MoreDelay:

; Delay d'15'

CoverLid2Next:

BaseStop

Delay 0xcf

call LidCoverHalf ; gently add cover for now

fcall LidCoverPosition ; re-position the lid cover apparatus

BaseCCW

CoverLid3:

KeypadReadChar

CheckKey 0xf, 0x008

btfsc BaseSensorLid

goto CoverLid3

BaseStop

141

Delay 0xcf

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LoadChips: Load the pattern for the current bottle">

LoadChips:

banksel CurrentLoadBottle ; Retrieve the pattern

rlf CurrentLoadBottle, w

addlw Pattern

LcdDisplayNumber

StackSave

banksel CurrentLoadBottle

rlf CurrentLoadBottle, w

addlw Pattern

movwf StackPtr

movff Stack, CurrentLoadPatternH

incf StackPtr, f

movff Stack, CurrentLoadPatternL

StackRestore

; Write an entry about the current bottle to success

banksel PORTA

EEPromReadA EEPromAddrPtr ; Read address pointer

rlf CurrentLoadBottle, w

addlw d'12'

addwf EEPromValue, w

movwf EEPromAddr

movfw CurrentLoadPatternH

movwf EEPromValue

EEPromWrite ; Write pattern

incf EEPromAddr, f

movfw CurrentLoadPatternL

movwf EEPromValue

EEPromWrite

142

movfw EEPromAddr ; Record temporary EE pointer for emergency stop

movwf _TempEEPtr

incf CurrentLoadBottle, f ; Start with 1st bottle

LcdClear ; Update the UI of the current bottle

LcdHome

LcdDisplay _UIMessageLoading

LcdSwitchLine

movfw CurrentLoadBottle

LcdDisplayNumber

movlw d'46'

LcdDisplayW

;UIDisplayPatternFF CurrentLoadPatternH, CurrentLoadPatternL, CurrentLoadBottle

;LongDelay

LcdCursorRight

LcdCursorRight

LcdCursorRight

LcdCursorRight

LcdCursorRight

LcdCursorRight

LcdCursorRight

LcdCursorRight

LcdCursorRight

banksel PORTA

clrf CurrentLoadChip

_LoaderLoadLoopInnerL:

fcall ResWheelInit

;ResWheelCCW

Delay 0xff

incf CurrentLoadChip, f ; Start with 1st chip (lower 1)

143

movfw CurrentLoadChip

addlw -0x1

fcall Mask

movfw _LoaderChipMask

andwf CurrentLoadPatternL, w

btfsc STATUS, Z

goto _LoaderLoadLoopInnerLA

goto _LoaderLoadLoopInnerLC

_LoaderLoadLoopInnerLA:

movlw 'A'

LcdDisplayW

LcdCursorLeft

LcdCursorLeft

fcall FinANextPosition

goto _LoaderLoadLoopInnerLNext

_LoaderLoadLoopInnerLC:

movlw 'C'

LcdDisplayW

LcdCursorLeft

LcdCursorLeft

fcall FinCNextPosition

goto _LoaderLoadLoopInnerLNext

_LoaderLoadLoopInnerLNext:

movfw CurrentLoadChip

addlw -0x5

btfsc STATUS, C

goto _LoaderLoadLoopInnerH

goto _LoaderLoadLoopInnerL

_LoaderLoadLoopInnerH:

;ResWheelCCW

fcall ResWheelInit

144

Delay 0xff

incf CurrentLoadChip, f ; Start with 1

movfw CurrentLoadChip

addlw -0x6

fcall Mask

movfw _LoaderChipMask

andwf CurrentLoadPatternH, w

btfsc STATUS, Z

goto _LoaderLoadLoopInnerHA

goto _LoaderLoadLoopInnerHC

_LoaderLoadLoopInnerHA:

movlw 'A'

LcdDisplayW

LcdCursorLeft

LcdCursorLeft

fcall FinANextPosition

goto _LoaderLoadLoopInnerHNext

_LoaderLoadLoopInnerHC:

movlw 'C'

LcdDisplayW

LcdCursorLeft

LcdCursorLeft

fcall FinCNextPosition

goto _LoaderLoadLoopInnerHNext

_LoaderLoadLoopInnerHNext:

movfw CurrentLoadChip

addlw -0xa

btfsc STATUS, C

goto _LoaderLoadLoopEnd

goto _LoaderLoadLoopInnerH

_LoaderLoadLoopEnd:

145

ResWheelStop

LongDelay

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="CountChips: Count the remaining chips">

CountChips:

LcdClear

LcdDisplay _UIMessageCounting

ResWheelCCW

clrf 0x45 ; Countchip wait loop

clrf 0x46 ; temporary counter for empty pass A

clrf 0x47 ; CountA

clrf 0x48 ; CountC

clrf 0x49 ; temporary counter for empty pass C

CountChipsA:

fcall FinAPrevPositionRestore

Delay 0x50

FinAStop ; Rotate fin A to count A first

fcall FinAPrevPosition

clrf 0x45

CountChipsWaitA:

banksel PORTC

btfsc ChipLoadSensorA

goto CountChipsIncA

ShortDelay

incf 0x45, f

movlw d'5'

subwf 0x45, w

btfsc STATUS, C

goto CountChipsC

goto CountChipsWaitA

146

CountChipsIncA:

banksel PORTC

btfss ChipLoadSensorA

goto $-1

Delay 0x70

;movlw 'A'

;LcdDisplayW

clrf 0x46

incf 0x47, f

goto CountChipsC

CountChipsC: ; Rotate Fin C to count C next

fcall FinCPrevPositionRestore

Delay 0xa0

FinCStop

fcall FinCPrevPosition

clrf 0x45

CountChipsWaitC:

banksel PORTC

btfsc ChipLoadSensorC

goto CountChipsIncC

ShortDelay

incf 0x45, f

movlw d'5'

subwf 0x45, w

btfsc STATUS, C

goto CountChipsEnd

goto CountChipsWaitC

CountChipsIncC:

banksel PORTC

btfss ChipLoadSensorC

goto $-1

Delay 0x70

147

;movlw 'C'

;LcdDisplayW

clrf 0x49

incf 0x48, f

goto CountChipsEnd

CountChipsEnd:

incf 0x46, f ; Add empty pass count

incf 0x49, f

;Delay 0xcf

movlw d'5' ; Count at least 5 empty pass for A

subwf 0x46, w

btfss STATUS, C

goto CountChipsA

movlw d'5' ; Count at least 5 empty pass for C

subwf 0x49, w

btfss STATUS, C

goto CountChipsA

movff 0x47, ChipsLeftCountA ; Store the counted value

movff 0x48, ChipsLeftCountC

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="ReturnChips: Return the counted chips back to the reservoir">

ReturnChips:

fcall FinANextPosition ; Position Fin A/C

fcall FinCNextPosition

FinACW

Delay 0x20

FinAStop

148

ResWheelCW

LongDelay

Delay 0xff

Delay 0xff

clrf 0x46 ; temporary counter for empty pass A

clrf 0x49 ; temporary counter for empty pass C

ReturnChipsLoop:

btfss ChipLoadSensorA

incf 0x46, f

btfss ChipLoadSensorC

incf 0x49, f

fcall FinANextPosition

fcall FinCNextPosition

movlw d'5' ; need both temporary counter have more than 5

subwf 0x46, w

btfss STATUS, C

goto ReturnChipsLoop

movlw d'5'

subwf 0x49, w

btfss STATUS, C

goto ReturnChipsLoop

ReturnChipsEnd:

ResWheelStop

FinAStop

FinCStop

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="ResWheelInit: Unjam the reservoir wheel">

ResWheelInit:

banksel PORTC

149

ResWheelCW

Delay d'200'

banksel PORTC

ResWheelCCW

Delay 0xff

Delay 0x50

return

;</editor-fold>

;;<editor-fold defaultstate="collapsed" desc="FinANextPosition">

;FinANextPosition:

; banksel PORTC

; FinACCW

;FinANextPositionLoop:

; KeypadReadChar

; CheckKey 0xf, 0x008

; btfsc FinWheelSensorA

; goto FinANextPositionLoop

; goto FinANextPositionDetected

;

;FinANextPositionDetected:

; FinACCW

; Delay 0x20

; FinACW

; Delay 0x10

; FinAStop

; return

;;</editor-fold>

;

;;<editor-fold defaultstate="collapsed" desc="FinCNextPosition">

;FinCNextPosition:

; banksel PORTC

; FinCCCW

;FinCNextPositionLoop:

; KeypadReadChar

150

; CheckKey 0xf, 0x008

; btfsc FinWheelSensorC

; goto FinCNextPositionLoop

; goto FinCNextPositionDetected

;FinCNextPositionDetected:

;; btfss FinWheelSensorC

;; goto $-1

;; FinCCW

;; Delay 0x10

;; FinCCCW

;; btfss FinWheelSensorC

;; goto $-1

;; FinCCW

;; Delay 0x4

;; FinCStop

; FinCCCW

; Delay 0x25

; FinCCW

; Delay 0x10

; FinCStop

; return;</editor-fold>

;

;;<editor-fold defaultstate="collapsed" desc="FinAPrevPosition">

;FinAPrevPosition:

; FinACW

;FinAPrevPositionLoop:

; KeypadReadChar

; CheckKey 0xf, 0x008

; btfsc FinWheelSensorA

; goto FinAPrevPositionLoop

; goto FinAPrevPositionDetected

;FinAPrevPositionDetected:

; FinACCW

; Delay 0x15

; FinAStop

151

; return

;

;FinAPrevPositionRestore:

; banksel PORTC

; FinACW

; return;</editor-fold>

;

;;<editor-fold defaultstate="collapsed" desc="FinCPrevPosition">

;FinCPrevPosition:

; banksel PORTC

; FinCCW

;FinCPrevPositionLoop:

; KeypadReadChar

; CheckKey 0xf, 0x008

; btfsc FinWheelSensorC

; goto FinCPrevPositionLoop

; goto FinCPrevPositionDetected

;FinCPrevPositionDetected:

; FinCCCW

; Delay 0x10

; FinCStop

; return

;

;FinCPrevPositionRestore:

; banksel PORTC

; FinCCW

; return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="FinANextPosition">

FinANextPosition:

banksel PORTC

FinACCW

FinANextPositionLoop:

KeypadReadChar

CheckKey 0xf, 0x008

152

btfsc FinWheelSensorA

goto FinANextPositionLoop

goto FinANextPositionDetected

FinANextPositionDetected:

FinACCW

Delay 0x20

FinACW

Delay 0x10

FinAStop

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="FinCNextPosition">

FinCNextPosition:

banksel PORTC

FinCCCW

; clrf 0x45

FinCNextPositionLoop:

; ShortDelay

; incf 0x45, f

KeypadReadChar

CheckKey 0xf, 0x008

; movlw 0x40

; subwf 0x45, w

; btfsc STATUS, C

; goto FinCNextPositionUJ

;

btfsc FinWheelSensorC

goto FinCNextPositionLoop

goto FinCNextPositionDetected

;

;FinCNextPositionUJ:

; FinCCW

153

; Delay 0x5

; clrf 0x45

; goto FinCNextPositionLoop

FinCNextPositionDetected:

btfss FinWheelSensorC

goto $-1

FinCCW

Delay 0x4

FinCCCW

; btfss FinWheelSensorC

; goto $-1

; FinCCW

; Delay 0x4

FinCStop

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="FinAPrevPosition">

FinAPrevPosition:

FinACW

FinAPrevPositionLoop:

KeypadReadChar

CheckKey 0xf, 0x008

btfsc FinWheelSensorA

goto FinAPrevPositionLoop

goto FinAPrevPositionDetected

FinAPrevPositionDetected:

FinACCW

Delay 0x15

FinAStop

return

FinAPrevPositionRestore:

banksel PORTC

FinACW

154

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="FinCPrevPosition">

FinCPrevPosition:

banksel PORTC

FinCCW

FinCPrevPositionLoop:

KeypadReadChar

CheckKey 0xf, 0x008

btfsc FinWheelSensorC

goto FinCPrevPositionLoop

goto FinCPrevPositionDetected

FinCPrevPositionDetected:

FinCCCW

Delay 0x15

FinCStop

return

FinCPrevPositionRestore:

banksel PORTC

FinCCW

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LidCoverPosition: Re-position the lid cover apparatus">

LidCoverPosition:

banksel PORTB

LidCoverCW

LidCoverPositionSensor1:

TinyDelay

KeypadReadChar

CheckKey 0xf, 0x008

btfss LidCoverSensor1

goto LidCoverPositionSensor1

LidCoverCCW

155

Delay 0x15

LidCoverStop

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="LidCoverHalf: Go half way of the lid cover">

LidCoverHalf:

banksel PORTB

LidCoverCCW

Delay 0xff

Delay 0xcf

LidCoverStop

Delay 0xcf

LidCoverCW

Delay d'140'

LidCoverStop

return

;</editor-fold>

End

156

LOADER.INC ifndef fcall

#include <fcall.inc>

endif

ifndef _LoaderLoad

extern _LoaderLoad

endif

#define _TempEEPtr 0x3b

LoaderLoad: macro

fcall _LoaderLoad

endm

157

MAIN.ASM ;**********************************************************************

; Entry point

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and Configs">

list p=16f877

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc>

endif

ifndef StackInit

#include <stack.inc> ; Stack library

endif

ifndef KeypadInit

#include <keypad.inc> ; Keypad library

endif

ifndef LcdInit

#include <lcd.inc> ; Lcd library

endif

ifndef UIInit

#include <ui.inc> ; UI library

endif

ifndef UIInitBottleNumber

#include <ui2.inc> ; UI library

endif

ifndef Divide

#include <math.inc> ; Math library

endif

ifndef TimerCheck

#include <timer.inc> ; Timer library

158

endif

ifndef LoaderLoad

#include <loader.inc> ; Loader

endif

ifndef BaseMotorDir

#include <motor.inc> ; Motor

endif

ifndef EEPromAddr

#include <eeprom.inc> ; EEProm library

endif

#include <rtc.inc>

__config _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _DEBUG_OFF & _CPD_OFF

global Finish

global Start2

#define TRISAIO b'00111111'

#define TRISBIO b'11110011'

#define TRISCIO b'00011000'

#define TRISDIO b'00000000'

#define TRISEIO b'00000010' ; Watch out the configuration bits

cblock 0x79

WTemp ; 9

StatusTemp ; a

PCLATHTemp ; b

endc

;</editor-fold>

159

;<editor-fold defaultstate="collapsed" desc="Reset vector">

Reset: org 0x0000

goto Main

; org 0x0004

; goto IntService

org 0x0008

goto Cancel;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Interrupt">

;_Interrupt: org 0x20

;IntService:

; movwf WTemp ; Copy W to TEMP register

; swapf STATUS,W ; Swap status to be saved into W

; clrf STATUS ; bank 0, regardless of current bank, Clears IRP,RP1,RP0

; movwf StatusTemp ; Save status to bank zero STATUS_TEMP register

; movf PCLATH, W ; Only required if using pages 1, 2 and/or 3

; movwf PCLATHTemp ; Save PCLATH into W

; clrf PCLATH ; Page zero, regardless of current page

;

; btfsc INTCON, RBIF

; goto KeyInt

; goto TimerInt

;

;TimerInt:

; clrf PIR1

; incf TimerCount, f

; TimerCheck

; goto IntServiceEnd

;

;KeyInt:

; bcf INTCON, RBIF

; KeypadReadChar

; CheckKey 0xf, 0x008

160

; goto IntServiceEnd

;

;IntServiceEnd:

; movf PCLATHTemp, W ; Restore PCLATH

; movwf PCLATH ; Move W into PCLATH

; swapf StatusTemp,W ; Swap STATUS_TEMP register into W

; ; (sets bank to original state)

; movwf STATUS ; Move W into STATUS register

; swapf WTemp,F ; Swap W_TEMP

; swapf WTemp,W ; Swap W_TEMP into W

; retfie

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Main">

Main: ;org 0x100

fcall Init

lgoto Start;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Init">

Init:

banksel TRISA ; Initialize the I/O pins

movlw TRISAIO

movwf TRISA

movlw 0x06

movwf ADCON1 ; All port A, E is digital

movlw TRISBIO

movwf TRISB

movlw TRISCIO

movwf TRISC

movlw TRISDIO

movwf TRISD

movlw TRISEIO

movwf TRISE

banksel PORTA

161

clrf PORTB

clrf PORTC

clrf PORTE

clrf INTCON

StackInit ; Initialize the stack

UIInit ; Initialize the LCD and the keypad

;TimerInit ; Initialize the timer module

;<editor-fold defaultstate="collapsed" desc="comment">

fcall i2c_common_setup

;rtc_resetAll

;fcall set_rtc_time;</editor-fold>

LcdClear

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Start">

Start:

; Delay 0xff

; banksel PORTB

; btfss PORTB, 1

; goto Start

; ResWheelCCW

; goto $

;

;;<editor-fold defaultstate="collapsed" desc="Output pin test code">

;Output:

; LcdClear

; banksel PORTC

; bsf PORTC, 5

;Loop2:

; banksel PORTC

; FinACW

162

; FinCCW

; ResWheelCW

; BaseCW

; LongDelay

; FinACCW

; FinCCCW

; ResWheelCCW

; BaseCCW

; LongDelay

; FinAStop

; FinCStop

; ResWheelStop

; BaseStop

; LongDelay

;LidTest:

; call LidCoverPosition

; LongDelay

; btfsc PORTB, 1

; goto Input

; goto Loop2

;;</editor-fold>

;

;;<editor-fold defaultstate="collapsed" desc="Input pin test code">

;Input:

; clrf PORTB

; LcdHome

;

; banksel PORTA

; movlw 'A'

; LcdDisplayW

; movlw ':'

; LcdDisplayW

; movfw PORTA

; LcdDisplayNumber

; movlw ' '

163

; LcdDisplayW

;

; movlw 'B'

; LcdDisplayW

; movlw ':'

; LcdDisplayW

; movfw PORTB

; LcdDisplayNumber

; movlw ' '

; LcdDisplayW

;

; movlw 'C'

; LcdDisplayW

; movlw ':'

; LcdDisplayW

; movfw PORTC

; LcdDisplayNumber

; movlw ' '

; LcdDisplayW

;

; LcdSwitchLine

;

; movlw 'D'

; LcdDisplayW

; movlw ':'

; LcdDisplayW

; movfw PORTD

; LcdDisplayNumber

; movlw ' '

; LcdDisplayW

;

; movlw 'E'

; LcdDisplayW

; movlw ':'

; LcdDisplayW

164

; movfw PORTE

; LcdDisplayNumber

; movlw ' '

; LcdDisplayW

;

; Delay 0xff

;

; btfsc PORTB, 1

; goto Clock

; goto Input

;;</editor-fold>

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Clock-Start">

Clock:

LcdClear

LcdCursorOff

Delay 0xff

LcdDisplay _UIMessageMachineName

LongDelay

LcdClear

ClockLoop:

;LcdDisplayDateTime

;Delay d'250'

;Delay d'207'

UIWelcome

Delay d'10'

btfss PORTB, 1

goto ClockLoop

UIInitBottleNumber

UIInitPattern

Start2:

UIConfirmStart Run, Cancel;</editor-fold>

165

;<editor-fold defaultstate="collapsed" desc="Cancel">

Cancel:

EEPromReadA 0x0

movfw _TempEEPtr

subwf EEPromValue, w

btfsc STATUS, Z

goto CancelNext

ResetPtr:

movfw _TempEEPtr

addlw 0x1

movwf EEPromValue

clrf EEPromAddr

EEPromWrite

TimerOff

CancelNext:

UICancel

LcdClear

banksel PORTB

clrf PORTB

clrf PORTC

clrf PORTE

lgoto ClockLoop

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Run">

Run:

LoaderLoad

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Finish">

Finish:

UIDisplayAllPattern

UIFinished

166

KeypadWaitChar

LcdClear

goto ClockLoop

;</editor-fold>

;;<editor-fold defaultstate="collapsed" desc="RTC reset">

;set_rtc_time:

; rtc_resetAll ;reset rtc

;

; rtc_set 0x00, B'10000000'

;

; ;set time

; rtc_set 0x06, 0x13 ; Year

; rtc_set 0x05, 0x4 ; Month

; rtc_set 0x04, 0x9 ; Date

; rtc_set 0x03, 0x2 ; Day

; rtc_set 0x02, 0x4 ; Hours

; rtc_set 0x01, 0x56 ; Minutes

; rtc_set 0x00, 0x0 ; Seconds

; return

;</editor-fold>

End

167

MATH.ASM ;**********************************************************************

; Math Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports, exports, and constants">

global _Divide

global _Multiply

#define Quotient 0x0

#define Remainder 0x1

#define Divisor 0x0

#define Divident 0x1

#define MultiplierA 0x0

#define MultiplierB 0x1

#define MultiplyResult 0x0

ifndef PORTA

#include <p16f877.inc>

endif

ifndef Stack

#include <stack.inc>

endif

ifndef LcdInit

#include <lcd.inc>

endif

cblock 0x28

_Divisor ;28

_Divident ;29

_Quotient ;2a

_MultiplierA ;2b

_MultiplierB ;2c

_MultiplyResult ;2d

endc;</editor-fold>

168

code

; Divide 8 bit number by 8 bit

; Stack: Quotient/Remainder-----Divisor<---/Divident

;<editor-fold defaultstate="collapsed" desc="_Divide: divide 8-bit number by 8-bit">

_Divide:

StackReadF Divisor, _Divisor ; Read divisor

StackReadF Divident, _Divident ; Read divident

clrf _Quotient

_DivideLoop:

incf _Quotient, f

movfw _Divisor

subwf _Divident, f

btfss STATUS, C ; Check borrow bit

goto _DivideLoopEnd

goto _DivideLoop

_DivideLoopEnd:

movfw _Divisor ; Add back one divisor to divient to get remainder

addwf _Divident, f

StackWriteF Divident, _Divident ; The divident stack spot is now remainder

decf _Quotient, f

StackWriteF Divisor, _Quotient ; The divisor stack spot is now quotient

return;</editor-fold>

; Multiply 8 bit number by 8 bit

; Stack: Result/MultiplyerA ------------- MultiplyerA/MultiplyerB

;<editor-fold defaultstate="collapsed" desc="_Multiply: Multiply 8 bit number by 8 bit">

_Multiply:

StackReadF MultiplierA, _MultiplierA

StackReadF MultiplierB, _MultiplierB

169

clrf _MultiplyResult

_MultiplyLoop:

movfw _MultiplierB ; Check if reaches end of the loop

xorlw b'00000000'

btfsc STATUS, Z

goto _MultiplyLoopEnd

decf _MultiplierB, f ; Decrement B

movfw _MultiplierA ; Add A to the result

addwf _MultiplyResult, f

goto _MultiplyLoop

_MultiplyLoopEnd:

StackWriteF MultiplyResult, _MultiplyResult

return;</editor-fold>

end

170

MATH.INC ;**********************************************************************

; Math Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and constants">

#define Quotient 0x0

#define Remainder 0x1

#define Divisor 0x0

#define Divident 0x1

ifndef _Divide

extern _Divide

extern _Multiply

endif;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Divide: divide a 8-bit number by 8-bit">

Divide: macro

fcall _Divide

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Multiply: multiply a 8-bit number by 8-bit">

Multiply: macro

fcall _Multiply

endm;</editor-fold>

171

MOTOR.INC ifndef PORTA

#include <p16f877.inc>

endif

#define ChipLoadSensorA PORTA, 0

#define ChipLoadSensorC PORTA, 1

#define FinWheelSensorA PORTA, 2

#define FinWheelSensorC PORTA, 3

#define BaseSensorLoad PORTA, 4

#define BaseSensorLid PORTA, 5

#define ResWheelMotorDir PORTC, 0

#define ResWheelMotorEnable PORTC, 1

#define FinWheelMotorADir PORTB, 3

#define FinWheelMotorAEnable PORTB, 2

#define FinWheelMotorCDir PORTC, 2

#define FinWheelMotorCEnable PORTC, 5

#define BaseMotorEnable PORTC, 6

#define BaseMotorDir PORTE, 2

#define LidCoverMotorDir PORTC, 7

#define LidCoverSensor1 PORTE, 1

#define LidCoverMotorEnable PORTE, 0

FinAStop: macro

bcf FinWheelMotorADir

bcf FinWheelMotorAEnable

endm

FinACW: macro

bcf FinWheelMotorAEnable

bsf FinWheelMotorADir

endm

FinACCW: macro

bcf FinWheelMotorADir

bsf FinWheelMotorAEnable

172

endm

FinCStop: macro

bcf FinWheelMotorCDir

bcf FinWheelMotorCEnable

endm

FinCCW: macro

bcf FinWheelMotorCEnable

bsf FinWheelMotorCDir

endm

FinCCCW: macro

bcf FinWheelMotorCDir

bsf FinWheelMotorCEnable

endm

ResWheelStop: macro

bcf ResWheelMotorDir

bcf ResWheelMotorEnable

endm

ResWheelCW: macro

bcf ResWheelMotorEnable

bsf ResWheelMotorDir

endm

ResWheelCCW: macro

bcf ResWheelMotorDir

bsf ResWheelMotorEnable

endm

BaseStop: macro

bcf BaseMotorDir

bcf BaseMotorEnable

173

endm

BaseCW: macro

bcf BaseMotorEnable

bsf BaseMotorDir

endm

BaseCCW: macro

bcf BaseMotorDir

bsf BaseMotorEnable

endm

LidCoverStop: macro

bcf LidCoverMotorDir

bcf LidCoverMotorEnable

endm

LidCoverCW: macro

bcf LidCoverMotorEnable

bsf LidCoverMotorDir

endm

LidCoverCCW: macro

bcf LidCoverMotorDir

bsf LidCoverMotorEnable

endm

174

RTC.INC ;External labels

extern write_rtc,read_rtc,rtc_convert,i2c_common_setup

;RTC Macros;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

rtc_resetAll macro

;input: none

;output: none

;desc: Resets all the time keeping registers on the RTC to zero

banksel 0x74

clrf 0x74

banksel 0x73

clrf 0x73

fcall write_rtc ;Write 0 to Seconds

banksel 0x73

incf 0x73 ;Set register address to 1

fcall write_rtc

banksel 0x73

incf 0x73 ;Set register address to 2

fcall write_rtc

banksel 0x73

incf 0x73 ;Set register address to 3

fcall write_rtc

banksel 0x73

incf 0x73 ;Set register address to 4

fcall write_rtc

banksel 0x73

incf 0x73 ;Set register address to 5

fcall write_rtc

banksel 0x73

incf 0x73 ;Set register address to 6

fcall write_rtc

endm

175

rtc_set macro addliteral,datliteral

;input: addliteral: value of address

; datliteral: value of data

;output: none

;desc: loads the data in datliteral into the

; address specified by addliteral in the RTC

banksel 0x73

movlw addliteral

movwf 0x73

banksel 0x74

movlw datliteral

movwf 0x74

fcall write_rtc

endm

rtc_read macro addliteral

;input: addliteral

;output: 0x75, 0x77, 0x78

;desc: From the selected register in the RTC, read the data

; and load it into 0x75. 0x75 is also converted into

; ASCII characters and the tens digit is placed into

; 0x77 and the ones digit is placed in 0x78

movlw addliteral

banksel 0x73

movwf 0x73

fcall read_rtc

banksel 0x75

movf 0x75,w

fcall rtc_convert

endm

176

STACK.INC ;**********************************************************************

; Stack Library for PIC16

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and constants">

ifndef PORTA

#include <p16f877.inc>

endif

#define Stack INDF

#define StackPtr FSR

#define TempW 0x40

#define TempStack 0x41;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Initialize the stack to 0x7e">

StackInit: macro

movlw 0x71

movwf StackPtr

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackJmp: Jump stack upwards with specified size">

StackJmp: macro Size

movwf TempW

movlw Size

subwf StackPtr, f

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackInc: Increment stack by 1">

StackInc: macro

decf StackPtr, f

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackDec: Decrement stack by specified size">

StackDec: macro Size

movwf TempW

177

movlw Size

addwf StackPtr, f

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackPush: Push the stack with a label and value">

StackPush: macro Label, Literal

banksel PORTA

movwf TempW

StackInc

variable Label=Stack

movlw Literal

movwf Stack

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackPushL: Push the stack with a literal value">

StackPushL: macro Value

banksel PORTA

movwf TempW

StackInc

movlw Value

movwf Stack

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackPushW: Push the stack with a label with value as the working register">

StackPushW: macro Label

banksel PORTA

movwf TempW

StackInc

variable Label=Stack

movwf Stack

;movfw INDF

178

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackWriteW: Write the content in WREG to the stack with a relative address to the stack pointer">

StackWriteW: macro RelativeAddr

banksel PORTA

StackDec RelativeAddr

movwf Stack

StackJmp RelativeAddr

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackWriteL: Write the literal value to the stack with a relative address to the stack pointer">

StackWriteL: macro RelativeAddr, Value

banksel PORTA

movwf TempW

StackDec RelativeAddr

movlw Value

movwf Stack

StackJmp RelativeAddr

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackWriteF: Write the file to the stack with a relative address">

StackWriteF: macro RelativeAddr, File

banksel PORTA

movwf TempW

StackDec RelativeAddr

banksel File

movfw File

banksel PORTA

movwf Stack

179

StackJmp RelativeAddr

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackReadW: Read the stack with relative address to the WREG">

StackReadW: macro RelativeAddr

banksel PORTA

StackDec RelativeAddr

movfw Stack

StackJmp RelativeAddr

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackReadF: Read the stack with relative address to a file register">

StackReadF: macro RelativeAddr, File

banksel PORTA

movwf TempW

StackDec RelativeAddr

movfw Stack

banksel File

movwf File

StackJmp RelativeAddr

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="StackSave: Save the stack pointer to temporary address">

StackSave: macro

banksel PORTA

movwf TempW

movfw StackPtr

movwf TempStack

movfw TempW

endm;</editor-fold>

180

;<editor-fold defaultstate="collapsed" desc="StackRestore: Restore the temporary stack pointer">

StackRestore: macro

banksel PORTA

movwf TempW

movfw TempStack

movwf StackPtr

movfw TempW

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="var: Dynamically decalare a variable">

var: macro Label

banksel PORTA

movfw TempW

StackInc

variable Label=INDF

movwf TempW

endm;</editor-fold>

181

TABLE.ASM ;**********************************************************************

; Lookup Table Library

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and exports">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef Stack

#include <stack.inc>

endif

ifndef movff

#include <fcall.inc>

endif

global _TableCall

global _TableLookupHL

#define StatusTemp 0x2e

;</editor-fold>

_TableLookup: code

;<editor-fold defaultstate="collapsed" desc="_TableCall: Call table by changing PCL with W">

_TableCall:

movwf PCL

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_TableLookupHL: Lookup table from offset/low/high in the stack">

_TableLookupHL:

;movff STATUS, StatusTemp

StackDec 0x02

movfw Stack

movwf PCLATH

182

StackInc

movfw Stack

StackInc

addwf Stack, w

btfsc STATUS, C

incf PCLATH, f

;movff StatusTemp, STATUS

movwf PCL

;call _TableCall

;pagesel $

;movff StatusTemp, STATUS

;return

;</editor-fold>

End

183

TABLE.INC ;**********************************************************************

; Lookup Table Library

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports and exports">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef Stack

#include <stack.inc>

endif

ifndef _TableCall

extern _TableCall

extern _TableLookupHL

endif;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="TableLookup: Lookup a table address with offset">

TableLookup: macro Table, Offset

movlw HIGH Table ; load PCLATH with base of table

movwf PCLATH

movlw LOW Table ; add offset to base

banksel Offset

addwf Offset, w

btfsc STATUS, C ; if overflow

incf PCLATH, f ; increment PCLATH

call _TableCall

banksel PORTA

pagesel $

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Lookup table with address specified in offset/low/high order in the stack">

TableLookupHL: macro

fcall _TableLookupHL

endm;</editor-fold>

184

185

TIMER.INC ifndef _TimerCheck

extern _TimerCheck

extern _TimerInit

endif

ifndef Divide

#include <math.inc>

endif

ifndef Stack

#include <stack.inc>

endif

#define TimerCount 0x7c ; c

#define TimerSec 0x7d ; d

#define TimerMin 0x7e ; e

#define TimerHour 0x7f ; f

TimerInit: macro

fcall _TimerInit

endm

TimerCheck: macro

fcall _TimerCheck

endm

TimerClear: macro

banksel TimerCount

clrf TimerCount

clrf TimerSec

clrf TimerMin

clrf TimerHour

endm

TimerOn: macro

186

rtc_read 0x0

StackInc

StackWriteF 0x0, 0x77

StackPushL 0xa

Multiply

StackReadF 0x0, TimerSec

StackDec 0x2

movfw 0x78

addwf TimerSec, f

rtc_read 0x1

StackInc

StackWriteF 0x0, 0x77

StackPushL 0xa

Multiply

StackReadF 0x0, TimerMin

StackDec 0x2

movfw 0x78

addwf TimerMin, f

endm

TimerOff: macro

local TimerSecCarry, TimerOff2, TimerMinCarry, TimerOffEnd

rtc_read 0x0 ; Read current seconds into timer count

StackInc

StackWriteF 0x0, 0x77

StackPushL 0xa

Multiply

StackReadF 0x0, TimerCount

StackDec 0x2

movfw 0x78

addwf TimerCount, f

movfw TimerSec ; Read current seconds into timer count

187

subwf TimerCount, f

movfw TimerCount

movwf TimerSec

movfw TimerSec ; Substract from the starting seconds

addlw -d'60'

btfsc STATUS, C

goto TimerSecCarry

goto TimerOff2

TimerSecCarry:

incf TimerMin, f ; Carry of seconds substraction

movlw d'60'

addwf TimerSec, f

TimerOff2:

clrf TimerCount ; Read current minutes into timer count

rtc_read 0x1

StackInc

StackWriteF 0x0, 0x77

StackPushL 0xa

Multiply

StackReadF 0x0, TimerCount

StackDec 0x2

movfw 0x78

addwf TimerCount, f

movfw TimerMin ; Substract from the starting minutes

subwf TimerCount, f

movfw TimerCount

movwf TimerMin

movfw TimerMin

188

addlw -d'60'

btfsc STATUS, C

goto TimerMinCarry

goto TimerOffEnd

TimerMinCarry:

movlw d'60' ; Carry of minutes substraction

addwf TimerMin, f

TimerOffEnd:

Endm

189

UI.ASM ;**********************************************************************

; UI Interaction

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports, exports, and variables">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc> ; delay

endif

ifndef Delay

#include <delay.inc> ; delay

endif

ifndef LcdInit

#include <lcd.inc> ; lcd library

endif

ifndef StackInit

#include <stack.inc> ; stack library

endif

ifndef KeypadInit

#include <keypad.inc> ; keypad library

endif

ifndef Divide

#include <math.inc>

endif

ifndef TimerInit

#include <timer.inc>

endif

global _UIInit

global _UIWelcome

global _UIFinished

global _UIChipsLeft

190

global _UIReadInput

global _UIParseInputNumber

global _UIWaitPond

global _UICancel

global _UIDisplayPattern

global _UIMessageMachineName

global _UIMessageWaitPond

global _UIMessageCancel

global _UIMessageCancelled

global _UIMessageCounting

cblock 0x58

_UIInputLength

_UIInputStackPtr

_UIInputStack:0xa ; Maximum of 10 characters can be input

_UIInputNumber

_UIInputStackPtrEnd

_UIInputMax

_UIInputCurrentChar

endc

cblock 0x42

TempW2

TempMask

TempCounter

endc

#define PondKey 0xe

#define StarKey 0xc

#define CancelKey 0xf

;</editor-fold>

_UI: code

191

;<editor-fold defaultstate="collapsed" desc="UI built in messages">

_UIMessageMachineName:

dt " Chip Washer", 0

_UIMessageWelcome:

dt "Welcome", 0

_UIMessageWaitPond:

dt "Ready to start", 0

_UIMessageCancel:

dt "OK/Cancel", 0

_UIMessageCancelled:

dt "Task cancelled", 0

_UIMessageFinished:

dt "Finished in ", 0

_UIMessageChipsLeft:

dt "Chips left ", 0

_UIMessageCounting:

dt "Counting...", 0

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIInit: Initialize LCD and keypad">

_UIInit:

LcdInit

KeypadInit

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIWelcome: Display the welcome message">

_UIWelcome:

LcdHome

LcdDisplay _UIMessageWelcome

LcdSwitchLine

LcdDisplayDateTime

;KeypadWaitChar

return;</editor-fold>

;;<editor-fold defaultstate="collapsed" desc="_UILoading: Display loading message">

192

;_UILoading:

; LcdClear

; LcdCursorOff

; LcdDisplay _UIMessageLoading

; Delay 0xff

; Delay 0xff

; Delay 0xff

; Delay 0xff

; Delay 0xff

; Delay 0xff

; Delay 0xff

; ;KeypadWaitChar

; return

;;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIFinished: Display finished message">

_UIFinished:

LcdClear

LcdCursorOff

LcdDisplay _UIMessageFinished

LcdSwitchLine

LcdDisplayTime

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIChipsLeft: Display number of chips left">

_UIChipsLeft:

LcdClear

LcdDisplay _UIMessageChipsLeft

movlw 'A'

LcdDisplayW

movlw ':'

LcdDisplayW

movfw 0x35

LcdDisplayNumber

193

LcdSwitchLine

LcdDisplay _UIMessageChipsLeft

movlw 'C'

LcdDisplayW

movlw ':'

LcdDisplayW

movfw 0x36

LcdDisplayNumber

;fcall _UIWaitPond

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIWaitPond">

_UIWaitPond:

KeypadWaitChar

CheckKey PondKey, _UIWaitPondEnd

CheckKey CancelKey, 0x0008

goto _UIWaitPond

_UIWaitPondEnd:

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="Mask: Generate mask bits">

Mask:

movwf TempCounter

clrf TempMask

bsf TempMask, 0

_MaskLoop:

movfw TempCounter

xorlw b'00000000'

btfsc STATUS, Z

goto _MaskLoopEnd

decf TempCounter, f

194

bcf STATUS, C

rlf TempMask, f

goto _MaskLoop

_MaskLoopEnd:

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIReadInputValidate: Validate input using mask">

_UIReadInputValidate: macro Addr

fcall Mask

StackRestore

StackReadW Addr

andwf TempMask, w

btfsc STATUS, Z

goto _UIReadInputLoop

goto _UIReadInputDisplay

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIReadInput: Aggregate the result with certain length and character validator">

_UIReadInput:

; Test the input without any validator and output the exact same message

; Just use the stack to store the characters

; Need a parameter to specify the length of the expected input

; Length is saved in 0x02 of the stack

; HIGH Validator is saved in the 0x01 0f the stack

; LOW Validator is saved in 0x00 of the stack

clrf _UIInputMax

StackReadF 0x2, _UIInputLength

StackSave ; Save the stack and switch to UIInput Stack

movlw _UIInputStackPtr

addlw 0xa ; Set the stack pointer to the bottom of the input stack

movwf _UIInputStackPtr

195

movfw _UIInputStackPtr

movwf StackPtr

_UIReadInputLoop:

KeypadWaitChar

movwf TempW2

movfw TempW2

CheckKey PondKey, _UIReadInputLoopNext ; Check if it is # key then go to next

CheckKey StarKey, _UIReadInputDelete ; Check if it is * key then decrement stack

CheckKey CancelKey, 0x0008 ; Check if D then cancel

addlw -0x8 ; Get lower bits

btfsc STATUS, C

goto _UIReadInputValidateH

addlw 0x8

goto _UIReadInputValidateL

_UIReadInputValidateH:

_UIReadInputValidate 0x1

_UIReadInputValidateL:

_UIReadInputValidate 0x0

_UIReadInputDisplay:

StackSave

movff _UIInputStackPtr, StackPtr

StackWriteF 0x0, TempW2

KeypadDecode Stack

LcdDisplayW

196

movfw StackPtr ; Check if the maximum reading length is reached

sublw _UIInputStackPtr

btfsc STATUS, Z

goto _UIReadInputMax ; If reached

clrf _UIInputMax ; Clear max flag

movfw _UIInputLength ; Check if reached the expeceted input length

addwf _UIInputStackPtr, w

movfw _UIInputLength

addwf _UIInputStackPtr, w

addlw -0x0b

sublw _UIInputStackPtr

btfsc STATUS, Z

goto _UIReadInputMax

decf StackPtr, f

decf _UIInputStackPtr, f

goto _UIReadInputLoop

_UIReadInputMax:

LcdCursorLeft

movlw 0x1

movwf _UIInputMax

goto _UIReadInputLoop

_UIReadInputDelete:

movlw 0x20 ; Check if it is at the minimum

LcdDisplayW

LcdCursorLeft

movfw _UIInputStackPtr

addlw -0x0a

sublw _UIInputStackPtr

197

btfss STATUS, Z

goto _UIReadInputDelete2

goto _UIReadInputLoop

_UIReadInputDelete2:

incf StackPtr, f

incf _UIInputStackPtr, f

LcdCursorLeft

lgoto _UIReadInputLoop

_UIReadInputLoopNext:

btfss _UIInputMax, 0

goto _UIReadInputNextNMax

goto _UIReadInputDisplayEnd

_UIReadInputNextNMax:

movfw _UIInputStackPtr

addlw -0xa

sublw _UIInputStackPtr

btfss STATUS, Z

goto _UIReadInputNextNMax2

goto _UIReadInputLoop

_UIReadInputNextNMax2:

incf StackPtr, f

incf _UIInputStackPtr, f

goto _UIReadInputDisplayEnd

;;<editor-fold defaultstate="collapsed" desc="DisplayLoop">

;;_UIReadInputDisplayLoop:

;; KeypadDecode Stack

;; LcdDisplayW

;;

;; movfw StackPtr

;; subwf _UIInputStackPtr, w

198

;; btfsc STATUS, Z

;; goto _UIReadInputDisplayEnd

;;

;; movfw StackPtr

;; sublw _UIInputStack

;; btfsc STATUS, Z

;; goto _UIReadInputDisplayEnd

;;

;; decf StackPtr

;; goto _UIReadInputDisplayLoop

;;</editor-fold>

_UIReadInputDisplayEnd:

movff _UIInputStackPtr, _UIInputStackPtrEnd

StackRestore

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIParseInputNumber: Parse the number in the input stack and store it in the WREG">

_UIParseInputNumber:

StackSave

movlw _UIInputStackPtr

addlw 0xa

movwf _UIInputStackPtr

movff _UIInputStackPtr, StackPtr

clrf _UIInputNumber

_UIParseInputNumberLoop:

KeypadDecodeNumber Stack ; Read the digit

;movff Stack, _UIInputCurrentChar

;StackRestore

;KeypadDecodeNumber _UIInputCurrentChar

;StackSave

;movff _UIInputStackPtr, StackPtr

199

addwf _UIInputNumber, f ; Add to the parsed number

movfw StackPtr ; Check if reached end

subwf _UIInputStackPtrEnd, w

btfsc STATUS, Z

goto _UIParseInputNumberLoopEnd

StackRestore ; Do a multiplication

StackInc

StackWriteF 0x0, _UIInputNumber

StackPushL 0xa

Multiply

StackReadF 0x0, _UIInputNumber

StackDec 0x2

StackSave ; Goto next digit

decf _UIInputStackPtr, f

movfw _UIInputStackPtr

movwf StackPtr

goto _UIParseInputNumberLoop

_UIParseInputNumberLoopEnd:

StackRestore

;movfw _UIInputNumber

;LcdDisplayNumber

;goto $

movfw _UIInputNumber

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UICancel: Display messsage for cancelling a task">

_UICancel:

200

LcdClear

LcdCursorOff

LcdDisplay _UIMessageCancelled

Delay 0xff

return;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIDisplayPattern: Display 2 bytes of pattern in terms of A/C">

_UIDisplayPatternInner: macro Mask, NextCheck

local DisplayA, DisplayC

andlw Mask

btfsc STATUS, Z

goto DisplayA

goto DisplayC

DisplayA:

call _UIDisplayPatternA

goto NextCheck

DisplayC:

call _UIDisplayPatternC

goto NextCheck

endm

; Stack Org:

; 0x0: Index

; 0x1: LowPattern

; 0x2: HighPattern

_UIDisplayPattern:

StackReadW 0x0

xorlw b'00000000'

btfsc STATUS, Z

goto _UIDisplayPatternHigher1

StackReadW 0x0

LcdDisplayNumber

201

movlw d'46'

LcdDisplayW

_UIDisplayPatternHigher1:

StackReadF 0x2, TempW2

movfw TempW2

_UIDisplayPatternInner b'00010000', _UIDisplayPatternHigher2

_UIDisplayPatternHigher2:

movfw TempW2

_UIDisplayPatternInner b'00001000', _UIDisplayPatternHigher3

_UIDisplayPatternHigher3:

movfw TempW2

_UIDisplayPatternInner b'00000100', _UIDisplayPatternHigher4

_UIDisplayPatternHigher4:

movfw TempW2

_UIDisplayPatternInner b'00000010', _UIDisplayPatternHigher5

_UIDisplayPatternHigher5:

movfw TempW2

_UIDisplayPatternInner b'00000001', _UIDisplayPatternLower1

_UIDisplayPatternLower1:

StackReadF 0x1, TempW2

movfw TempW2

_UIDisplayPatternInner b'00010000', _UIDisplayPatternLower2

_UIDisplayPatternLower2:

movfw TempW2

_UIDisplayPatternInner b'00001000', _UIDisplayPatternLower3

_UIDisplayPatternLower3:

movfw TempW2

202

_UIDisplayPatternInner b'00000100', _UIDisplayPatternLower4

_UIDisplayPatternLower4:

movfw TempW2

_UIDisplayPatternInner b'00000010', _UIDisplayPatternLower5

_UIDisplayPatternLower5:

movfw TempW2

_UIDisplayPatternInner b'00000001', _UIDisplayPatternEnd

_UIDisplayPatternEnd:

return

_UIDisplayPatternA:

movlw d'65'

LcdDisplayW

return

_UIDisplayPatternC:

movlw d'67'

LcdDisplayW

return;</editor-fold>

end

203

UI.INC ;**********************************************************************

; UI Library

;**********************************************************************

ifndef _UIWelcome

extern _UIInit

extern _UIWelcome

;extern _UILoading

extern _UIFinished

extern _UIChipsLeft

extern _UIReadInput

extern _UIParseInputNumber

extern _UIWaitPond

extern _UIDisplayPattern

extern _UIMessageMachineName

endif

#define NumberValidatorH b'00100111'

#define NumberValidatorL b'01110111'

#define ACValidatorH b'00001000'

#define ACValidatorL b'00001000'

UIInit: macro

fcall _UIInit

endm

UIWelcome: macro

fcall _UIWelcome

endm

UIInitBottles: macro

fcall _UIInitBottles

endm

;UILoading: macro

204

; fcall _UILoading

; endm

UIFinished: macro

fcall _UIFinished

endm

UIChipsLeft: macro

fcall _UIChipsLeft

endm

UIReadInputAC: macro Length

StackInc

StackWriteL 0x0, Length

StackInc

StackWriteL 0x0, ACValidatorH

StackInc

StackWriteL 0x0, ACValidatorL

fcall _UIReadInput

StackDec 0x03

endm

UIReadInputNumber: macro Length

StackInc

StackWriteL 0x0, Length

StackInc

StackWriteL 0x0, NumberValidatorH

StackInc

StackWriteL 0x0, NumberValidatorL

fcall _UIReadInput

StackDec 0x03

endm

205

UIParseNumber: macro

fcall _UIParseInputNumber

endm

UIWaitPond: macro

fcall _UIWaitPond

endm

UICancel: macro

fcall _UICancel

endm

UIDisplayPattern: macro HighPattern, LowPattern, Index

StackPushL HighPattern

StackPushL LowPattern

StackPushL Index

fcall _UIDisplayPattern

StackDec 0x3

endm

UIDisplayPatternF: macro HighPatternF, LowPatternF, Index

StackInc

StackWriteF 0x0, HighPatternF

StackInc

StackWriteF 0x0, LowPatternF

StackPushL Index

fcall _UIDisplayPattern

StackDec 0x3

endm

; index in the working reg

UIDisplayPatternFF: macro HighPatternF, LowPatternF, IndexF

StackInc

StackWriteF 0x0, HighPatternF

206

StackInc

StackWriteF 0x0, LowPatternF

StackInc

StackWriteF 0x0, IndexF ; Index

fcall _UIDisplayPattern

StackDec 0x3

Endm

207

UI2.ASM ;**********************************************************************

; UI Interaction 2 (2nd file for UI component)

;**********************************************************************

;<editor-fold defaultstate="collapsed" desc="Imports, exports, and variables">

ifndef PORTA

#include <p16f877.inc>

endif

ifndef fcall

#include <fcall.inc> ; delay

endif

ifndef Delay

#include <delay.inc> ; delay

endif

ifndef LcdInit

#include <lcd.inc> ; lcd library

endif

ifndef StackInit

#include <stack.inc> ; stack library

endif

ifndef KeypadInit

#include <keypad.inc> ; keypad library

endif

ifndef Divide

#include <math.inc>

endif

ifndef UIInit

#include <ui.inc>

endif

ifndef EEPromAddr

#include <eeprom.inc>

endif

global _UIInitBottleNumber

208

global _UIInitPattern

global _UIConfirmStart

global _UIMessageLoading

global _UIDisplayAllPattern

extern _UIMessageWaitPond

extern _UIMessageCancel

extern Finish

cblock 0x58

_UIInputLength

_UIInputStackPtr

_UIInputStack:0xa ; Maximum of 10 characters can be input

_UIInputNumber

_UIInputStackPtrEnd

_UIInputMax

endc

cblock 0xa0

Pattern:d'20'

_UIPatternCount

_UIMenuSelection

_UICurrentPatternH

_UICurrentPatternL

endc

cblock 0x2f

BottleNumber

CurrentLoadBottle

CurrentLidBottle

CurrentLoadPatternH

CurrentLoadPatternL

CurrentLoadChip

endc

#define PondKey 0xe

209

#define StarKey 0xc

#define CancelKey 0xf

;</editor-fold>

_UI2: code

;<editor-fold defaultstate="collapsed" desc="Built in messages">

_UIMessageAskBottleNumber:

dt "# of bottles:", 0

_UIMessageNumberTooLarge:

dt "Too large", 0

_UIMessageNumberTooSmall:

dt "Too small", 0

_UIMessagePatternTooShort:

dt "Pls enter 10", 0

_UIMessageAskPattern:

dt "Pattern for #", 0

_UIMessagePatternMenu:

dt "OK to view menu", 0

_UIMessagePatternMenu7:

dt "7.Custom", 0

_UIMessagePatternCustom:

dt "Enter A/C:", 0

_UIMessageLoading:

dt "Loading...", 0

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIInitBottleNumber">

_UIInitBottleNumber:

LcdClear

LcdDisplay _UIMessageAskBottleNumber

LcdSwitchLine

LcdCursorOn

; Read input

210

UIReadInputNumber 0x2

LcdCursorOff

LcdClear

LcdSwitchLine

; Parse number

UIParseNumber

movfw _UIInputNumber

addlw -d'4'

btfss STATUS, C

goto _UIInitBottleNumberNext

LcdClear

LcdDisplay _UIMessageNumberTooLarge

Delay 0xff

goto _UIInitBottleNumber

_UIInitBottleNumberNext:

movfw _UIInputNumber

xorlw b'00000000'

btfss STATUS, Z

goto _UIInitBottleNumberNext2

LcdDisplay _UIMessageNumberTooSmall

Delay 0xff

goto _UIInitBottleNumber

_UIInitBottleNumberNext2:

movfw _UIInputNumber

banksel BottleNumber

movwf BottleNumber

;banksel PORTA

return

;</editor-fold>

211

;<editor-fold defaultstate="collapsed" desc="Pattern macro">

;_UICopyPattern: macro SourceH, SourceL

;

; movlw SourceH

; banksel _UICurrentPatternH

; movwf _UICurrentPatternH

;

; movlw SourceL

; banksel _UICurrentPatternL

; movwf _UICurrentPatternL

; banksel PORTA

;

; endm

_UIParsePattern: macro SourceAC, Dest, Offset

local _UIParsePattern1, _UIParsePattern0, _UIParsePatternEnd

banksel SourceAC

movfw SourceAC

banksel Dest

addlw -0x8

btfsc STATUS, C

goto _UIParsePattern1

goto _UIParsePattern0

_UIParsePattern1:

bsf Dest, Offset

goto _UIParsePatternEnd

_UIParsePattern0:

bcf Dest, Offset

goto _UIParsePatternEnd

_UIParsePatternEnd:

banksel PORTA

endm;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIMenuRouter: Validate menu selection">

212

_UIMenuRouter:

banksel _UIMenuSelection

movwf _UIMenuSelection

KeypadDecodeNumber _UIMenuSelection

banksel _UIMenuSelection

movwf _UIMenuSelection

banksel PORTA

addlw -d'8' ; Too large menu number

btfsc STATUS, C

goto _UIInitPatternLoopWait

addlw d'8'

xorlw b'00000000' ; Too small menu number

btfsc STATUS, Z

goto _UIInitPatternLoopWait

banksel PORTA

; Record the pattern

; 1

addlw -d'1' ; Custom menu number

btfsc STATUS, Z

goto _UIMenuRouter1

addlw d'1'

; 2

addlw -d'2' ; Custom menu number

btfsc STATUS, Z

goto _UIMenuRouter2

addlw d'2'

; 3

213

addlw -d'3' ; Custom menu number

btfsc STATUS, Z

goto _UIMenuRouter3

addlw d'3'

; 4

addlw -d'4' ; Custom menu number

btfsc STATUS, Z

goto _UIMenuRouter4

addlw d'4'

; 5

addlw -d'5' ; Custom menu number

btfsc STATUS, Z

goto _UIMenuRouter5

addlw d'5'

; 6

addlw -d'6' ; Custom menu number

btfsc STATUS, Z

goto _UIMenuRouter6

addlw d'6'

; 7

addlw -d'7' ; Custom menu number

btfsc STATUS, Z

goto _UIInitPatternCustom

addlw d'7'

goto _UIInitPatternLoopEnd

_UIMenuRouter1:

214

EEPromReadA EEPromPattern1H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern1L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

banksel PORTA

goto _UIInitPatternLoopEnd

_UIMenuRouter2:

EEPromReadA EEPromPattern2H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern2L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

banksel PORTA

goto _UIInitPatternLoopEnd

_UIMenuRouter3:

EEPromReadA EEPromPattern3H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern3L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

banksel PORTA

goto _UIInitPatternLoopEnd

_UIMenuRouter4:

EEPromReadA EEPromPattern4H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern4L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

banksel PORTA

goto _UIInitPatternLoopEnd

215

_UIMenuRouter5:

EEPromReadA EEPromPattern5H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern5L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

banksel PORTA

goto _UIInitPatternLoopEnd

_UIMenuRouter6:

EEPromReadA EEPromPattern6H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern6L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

banksel PORTA

goto _UIInitPatternLoopEnd;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIInitPattern: Let user input the pattern for each bottle">

_UIInitPattern:

banksel _UIPatternCount

movlw 0x1 ; Make Count to start with 1

movwf _UIPatternCount

banksel PORTA

_UIInitPatternLoop:

banksel PORTA

LcdClear

LcdDisplay _UIMessageAskPattern

banksel _UIPatternCount

movfw _UIPatternCount

banksel PORTA

LcdDisplayNumber

216

movlw d'58'

LcdDisplayW

LcdSwitchLine

LcdCursorOff

LcdDisplay _UIMessagePatternMenu

_UIInitPatternLoopWait:

KeypadWaitChar

CheckKey PondKey, _UIInitPatternMenu1

CheckKey CancelKey, 0x0008

goto _UIMenuRouter

_UIInitPatternMenu1:

banksel PORTA

LcdClear

EEPromReadA EEPromPattern1H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern1L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x1

banksel PORTA

LcdSwitchLine

EEPromReadA EEPromPattern2H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern2L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x2

KeypadWaitChar

217

CheckKey PondKey, _UIInitPatternMenu2

CheckKey CancelKey, 0x0008

goto _UIMenuRouter

_UIInitPatternMenu2:

banksel PORTA

LcdClear

EEPromReadA EEPromPattern3H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern3L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x3

banksel PORTA

LcdSwitchLine

EEPromReadA EEPromPattern4H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern4L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x4

KeypadWaitChar

CheckKey PondKey, _UIInitPatternMenu3

CheckKey CancelKey, 0x0008

goto _UIMenuRouter

_UIInitPatternMenu3:

banksel PORTA

LcdClear

EEPromReadA EEPromPattern5H

218

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern5L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x5

banksel PORTA

LcdSwitchLine

EEPromReadA EEPromPattern6H

banksel _UICurrentPatternH

movwf _UICurrentPatternH

EEPromReadA EEPromPattern6L

banksel _UICurrentPatternL

movwf _UICurrentPatternL

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x6

KeypadWaitChar

CheckKey PondKey, _UIInitPatternMenu4

CheckKey CancelKey, 0x0008

goto _UIMenuRouter

_UIInitPatternMenu4:

LcdClear

LcdDisplay _UIMessagePatternMenu7

KeypadWaitChar

CheckKey PondKey, _UIInitPatternMenu1

CheckKey CancelKey, 0x0008

goto _UIMenuRouter

_UIInitPatternCustom:

LcdClear

LcdDisplay _UIMessagePatternCustom

219

LcdCursorOn

LcdSwitchLine

UIReadInputAC 0xa

movfw _UIInputStackPtrEnd

sublw _UIInputStack

btfsc STATUS, Z

goto _UIInitPatternCustomParse

LcdClear

LcdCursorOff

LcdDisplay _UIMessagePatternTooShort

Delay 0xff

goto _UIInitPatternCustom

; Parse the custom pattern

_UIInitPatternCustomParse:

LcdCursorOff

banksel _UICurrentPatternH

clrf _UICurrentPatternH

clrf _UICurrentPatternL

_UIParsePattern _UIInputStackPtr+0x1, _UICurrentPatternL, 0x0

_UIParsePattern _UIInputStackPtr+0x2, _UICurrentPatternL, 0x1

_UIParsePattern _UIInputStackPtr+0x3, _UICurrentPatternL, 0x2

_UIParsePattern _UIInputStackPtr+0x4, _UICurrentPatternL, 0x3

_UIParsePattern _UIInputStackPtr+0x5, _UICurrentPatternL, 0x4

_UIParsePattern _UIInputStackPtr+0x6, _UICurrentPatternH, 0x0

_UIParsePattern _UIInputStackPtr+0x7, _UICurrentPatternH, 0x1

_UIParsePattern _UIInputStackPtr+0x8, _UICurrentPatternH, 0x2

_UIParsePattern _UIInputStackPtr+0x9, _UICurrentPatternH, 0x3

_UIParsePattern _UIInputStackPtr+0xa, _UICurrentPatternH, 0x4

_UIInitPatternLoopEnd:

LcdClear

LcdDisplay _UIMessageAskPattern

banksel _UIPatternCount

movfw _UIPatternCount

220

banksel PORTA

LcdDisplayNumber

movlw d'58'

LcdDisplayW

LcdSwitchLine

UIDisplayPatternF _UICurrentPatternH, _UICurrentPatternL, 0x0

Delay 0xff

_UIInitPatternLoopEnd2:

StackSave ; Save to designated register

banksel _UIPatternCount

rlf _UIPatternCount, w

addlw Pattern-0x2

movwf StackPtr

movff _UICurrentPatternH, Stack

incf StackPtr, f

movff _UICurrentPatternL, Stack

StackRestore

banksel _UIPatternCount ; Check if all bottles have been entered

movfw _UIPatternCount

banksel BottleNumber

subwf BottleNumber, w

btfsc STATUS, Z

goto _UIInitPatternEnd

banksel _UIPatternCount

incf _UIPatternCount, f

banksel PORTA

goto _UIInitPatternLoop

_UIInitPatternEnd:

221

; banksel CurrentLoadBottle

; clrf CurrentLoadBottle

; LcdClear

;DisplayAllPatternLoop:

; btfsc CurrentLoadBottle, 0

; goto LoopOdd

; goto LoopEven

;LoopOdd:

; LcdSwitchLine

; goto LoopNext

;LoopEven:

; LcdClear

; goto LoopNext

;LoopNext:

; StackSave

; banksel CurrentLoadBottle

; rlf CurrentLoadBottle, w

; banksel Pattern

; addlw Pattern

; movwf StackPtr

; movff Stack, CurrentLoadPatternH

; incf StackPtr, f

; movff Stack, CurrentLoadPatternL

; StackRestore

; banksel CurrentLoadBottle

; incf CurrentLoadBottle, f

; UIDisplayPatternFF CurrentLoadPatternH, CurrentLoadPatternL, CurrentLoadBottle

;

; Delay 0xff

; Delay 0xff

;

; banksel CurrentLoadBottle

; movfw CurrentLoadBottle

;

222

; banksel BottleNumber

; subwf BottleNumber, w

; btfss STATUS, Z

; goto DisplayAllPatternLoop

;

; banksel CurrentLoadBottle

; clrf CurrentLoadBottle

; banksel PORTA

return

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIConfirmStart: Let user to confirm start or cancel">

_UIConfirmStart:

LcdClear

LcdDisplay _UIMessageWaitPond

LcdSwitchLine

LcdDisplay _UIMessageCancel

_UIConfirmStartWait:

KeypadWaitChar

CheckKey PondKey, _UIConfirmStartYes

CheckKey CancelKey, _UIConfirmStartNo

goto _UIConfirmStartWait

_UIConfirmStartYes:

retlw 0x1

_UIConfirmStartNo:

retlw 0x0

;</editor-fold>

;<editor-fold defaultstate="collapsed" desc="_UIDisplayAllPattern: Display all the pattern information at the end of the operation">

_UIDisplayAllPattern:

223

banksel CurrentLoadBottle

clrf CurrentLoadBottle

LcdClear

DisplayAllPatternLoop:

btfsc CurrentLoadBottle, 0

goto LoopOdd

goto LoopEven

LoopOdd:

LcdSwitchLine

goto LoopNext

LoopEven:

LcdClear

goto LoopNext

LoopNext:

StackSave

banksel CurrentLoadBottle

bcf STATUS, C

rlf CurrentLoadBottle, w

banksel Pattern

addlw Pattern

movwf StackPtr

movff Stack, CurrentLoadPatternH

incf StackPtr, f

movff Stack, CurrentLoadPatternL

StackRestore

banksel CurrentLoadBottle

incf CurrentLoadBottle, f

UIDisplayPatternFF CurrentLoadPatternH, CurrentLoadPatternL, CurrentLoadBottle

Delay 0xff

Delay 0xff

banksel CurrentLoadBottle

movfw CurrentLoadBottle

224

banksel BottleNumber

subwf BottleNumber, w

btfss STATUS, Z

goto DisplayAllPatternLoop

banksel CurrentLoadBottle

clrf CurrentLoadBottle

banksel PORTA

return;</editor-fold>

end

225

UI2.INC ifndef _UIInitBottleNumber

extern _UIInitBottleNumber

extern _UIInitPattern

extern _UIConfirmStart

extern _UICancel

extern _UIDisplayAllPattern

endif

UIInitBottleNumber: macro

fcall _UIInitBottleNumber

endm

UIInitPattern: macro

fcall _UIInitPattern

endm

UIConfirmStart: macro Run, Cancel

fcall _UIConfirmStart

xorlw b'00000000'

btfsc STATUS, Z

goto Cancel

goto Run

endm

UIDisplayAllPattern: macro

fcall _UIDisplayAllPattern

endm

226

13.3.3 PC INTERFACE ORIGINAL SOURCE CODE Note: for entire solution folder and code, please ask for a digital copy. Only important code are shown

here to save the space.

PICUSB2.CS using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms; namespace PICusb { public partial class PicUsb2 : Form { private FormPICusb MainForm { get; set; } private List<LogEntry> Logs { get; set; } private int Selected { get; set; } public PicUsb2(FormPICusb form1) { this.MainForm = form1; InitializeComponent(); this.Selected = -1; this.button2.Enabled = false; } private class LogEntry { public DateTime StartTime { get; set; } public TimeSpan Duration { get; set; } public int BottleNumber { get; set; } public int ChipsLeftA { get; set; } public int ChipsLeftC { get; set; } public bool Success { get; set; } public List<Pattern> Patterns { get; set; } public int Length { get; set; } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append(String.Format("Time: {0}{1}", StartTime, Environment.NewLine)); sb.Append(String.Format("Duration: {0}{1}", Duration, Environment.NewLine)); sb.Append(String.Format("Status: {0}{1}", Success ? "Successful" : "Failed", Environment.NewLine)); sb.Append(String.Format("Number of containers: {0}{1}", BottleNumber, Environment.NewLine)); sb.Append(String.Format("Chips left A: {0}, C: {1}{2}", ChipsLeftA, ChipsLeftC, Environment.NewLine)); sb.Append(String.Format("Container information:{0}", Environment.NewLine)); for (int i = 0; i < Patterns.Count; i++) { sb.Append(String.Format("Container {0}: {1}{2}", i + 1, Patterns[i].ACPattern, Environment.NewLine));

227

} return sb.ToString(); } } private class Pattern { public string ACPattern { get; set; } public bool Success { get; set; } } private void button1_Click(object sender, EventArgs e) { try { this.MainForm.readEEPROM(); for (int i = 0; i < PICkitFunctions.DeviceBuffers.EEPromMemory[0]; i++) { this.textBox1.AppendText(PICkitFunctions.DeviceBuffers.EEPromMemory[i].ToString()); this.textBox1.AppendText(" "); } LoadPatterns(); LoadLogs(); UpdateEEProm(); this.saveFileDialog1.FileName = "ChipWasher_" + DateTime.Now.ToString("yyyy-mm-ddTHHmmss") + ".log"; this.saveFileDialog1.DefaultExt = ".log"; this.saveFileDialog1.FileOk += SaveFile; this.saveFileDialog1.ShowDialog(); this.button2.Enabled = true; ClearLogs(); MessageBox.Show("Cleared logs successfully"); } catch { MessageBox.Show("Machine not connected"); } } private void LoadPatterns() { this.PatternBox.Items.Clear(); // Load the pre-load patterns for (int i = 0; i < 6; i++) { int index = i * 2 + 1; uint high = PICkitFunctions.DeviceBuffers.EEPromMemory[index]; uint low = PICkitFunctions.DeviceBuffers.EEPromMemory[index + 1]; string pattern = this.ConvertPattern(high, low); this.PatternBox.Items.Add(pattern); } } private void LoadLogs() { this.Logs = new List<LogEntry>(); List<uint> buffer = new List<uint>();

228

this.LogBox.Text = ""; // Load the logs for (int i = 13; i < PICkitFunctions.DeviceBuffers.EEPromMemory.Length; i++) { if (PICkitFunctions.DeviceBuffers.EEPromMemory[i] != 255) { buffer.Add(PICkitFunctions.DeviceBuffers.EEPromMemory[i]); } else { if (buffer.Count != 0) { this.Logs.Add(this.ParseLogEntry(buffer.ToArray())); buffer.Clear(); } } } foreach (var log in this.Logs) { this.LogBox.AppendText(log.ToString()); this.LogBox.AppendText(Environment.NewLine); } } private void SaveFile(object sender, EventArgs e) { File.WriteAllText(this.saveFileDialog1.FileName, this.LogBox.Text); } private void ClearLogs() { PICkitFunctions.DeviceBuffers.EEPromMemory[0] = 0xd; for (int i = 13; i < PICkitFunctions.DeviceBuffers.EEPromMemory.Length; i++) { PICkitFunctions.DeviceBuffers.EEPromMemory[i] = 0xff; } WriteEEProm(); } private void ResetEEProm() { PICkitFunctions.DeviceBuffers.EEPromMemory[1] = 0x1f; PICkitFunctions.DeviceBuffers.EEPromMemory[2] = 0x1f; PICkitFunctions.DeviceBuffers.EEPromMemory[3] = 0x00; PICkitFunctions.DeviceBuffers.EEPromMemory[4] = 0x00; PICkitFunctions.DeviceBuffers.EEPromMemory[5] = 0x1f; PICkitFunctions.DeviceBuffers.EEPromMemory[6] = 0x00; PICkitFunctions.DeviceBuffers.EEPromMemory[7] = 0x19; PICkitFunctions.DeviceBuffers.EEPromMemory[8] = 0x13; PICkitFunctions.DeviceBuffers.EEPromMemory[9] = 0x06; PICkitFunctions.DeviceBuffers.EEPromMemory[10] = 0x0c; PICkitFunctions.DeviceBuffers.EEPromMemory[11] = 0x15; PICkitFunctions.DeviceBuffers.EEPromMemory[12] = 0x0a; ClearLogs(); } private void UpdateEEProm() {

229

// Update the patterns if (this.Logs != null) { int length = 0; foreach (var item in this.Logs) { length += item.Length; } length += 13; PICkitFunctions.DeviceBuffers.EEPromMemory[0] = (uint)length; } int index = 1; foreach (var item in this.PatternBox.Items) { uint high, low; this.AntiConvertPattern(item.ToString(), out high, out low); PICkitFunctions.DeviceBuffers.EEPromMemory[index] = high; PICkitFunctions.DeviceBuffers.EEPromMemory[index + 1] = low; index += 2; } WriteEEProm(); } private void WriteEEProm() { // Write device uint num = 0u; PICkitFunctions.RunScript(0, 1); if (PICkitFunctions.DevFile.PartsList[PICkitFunctions.ActivePart].EEWrPrepScript > 1) { if (PICkitFunctions.DevFile.Families[PICkitFunctions.GetActiveFamily()].EEMemHexBytes == 4) { PICkitFunctions.DownloadAddress3((int)(PICkitFunctions.DevFile.PartsList[PICkitFunctions.ActivePart].EEAddr / 2u)); } else { PICkitFunctions.DownloadAddress3(0); } PICkitFunctions.RunScript(10, 1); } int num4 = (int)PICkitFunctions.DevFile.Families[PICkitFunctions.GetActiveFamily()].EEMemBytesPerWord; //uint eEBlank = this.getEEBlank(); int num12 = (int)PICkitFunctions.DevFile.PartsList[PICkitFunctions.ActivePart].EEWrLocations; if (num12 < 16) { num12 = 16; } int num3 = PICkitFunctions.DeviceBuffers.EEPromMemory.Length - 1; int num8 = (num3 + 1) / num12; if ((num3 + 1) % num12 > 0) {

230

num8++; } num3 = num8 * num12; byte[] array2 = new byte[num12 * num4]; int repetitions = num12 / (int)PICkitFunctions.DevFile.PartsList[PICkitFunctions.ActivePart].EEWrLocations; int num13 = 0; do { int num9 = 0; for (int j = 0; j < num12; j++) { uint num14 = PICkitFunctions.DeviceBuffers.EEPromMemory[num13++]; if (PICkitFunctions.DevFile.Families[PICkitFunctions.GetActiveFamily()].ProgMemShift > 0) { num14 <<= 1; } array2[num9++] = (byte)(num14 & 255u); num += (uint)((byte)(num14 & 255u)); for (int k = 1; k < num4; k++) { num14 >>= 8; array2[num9++] = (byte)(num14 & 255u); num += (uint)((byte)(num14 & 255u)); } } PICkitFunctions.DataClrAndDownload(array2, 0); PICkitFunctions.RunScript(11, repetitions); } while (num13 < num3); PICkitFunctions.RunScript(1, 1); } private string ConvertPattern(uint high, uint low) { string result = ""; uint mask = 0x10; for (int i = 0; i < 5; i++) { if ((high & mask) != 0) { result += "C"; } else { result += "A"; } mask = mask >> 1; } mask = 0x10; for (int i = 0; i < 5; i++) { if ((low & mask) != 0) { result += "C"; } else

231

{ result += "A"; } mask = mask >> 1; } return result; } private int ConvertDate(uint hexDate) { int ten, one; ten = ((int)hexDate & 0xf0) / 0x10; one = ((int)hexDate & 0x0f); return ten * 10 + one; } private LogEntry ParseLogEntry(uint[] raw) { LogEntry result = new LogEntry(); int year = this.ConvertDate(raw[0]) + 2000; int month = this.ConvertDate(raw[1]); int day = this.ConvertDate(raw[2]); int hour = this.ConvertDate(raw[3]); int minute = this.ConvertDate(raw[4]); int second = this.ConvertDate(raw[5]); result.StartTime = new DateTime(year, month, day, hour, minute, second); int minute2 = (int)raw[6]; int second2 = (int)raw[7]; result.Duration = new TimeSpan(0, minute2, second2); if (raw[8] > 128) { result.Success = true; result.BottleNumber = (int)raw[8] - 128; } else { result.Success = false; result.BottleNumber = (int)raw[8]; } result.ChipsLeftA = (int)raw[9]; result.ChipsLeftC = (int)raw[10]; result.Patterns = new List<Pattern>(); for (int i = 11; i < raw.Length; i = i + 2) { Pattern pattern = new Pattern(); uint high, low; if (raw[i] >= 128) { pattern.Success = true; high = raw[i] - 128; } else { pattern.Success = false; high = raw[i]; } low = raw[i + 1]; pattern.ACPattern = this.ConvertPattern(high, low);

232

result.Patterns.Add(pattern); } result.Length = raw.Length + 1; return result; } private void AntiConvertPattern(string pattern, out uint high, out uint low) { int mask = 0x10; high = 0; low = 0; foreach (char c in pattern.Substring(0, 5)) { if (c == 'C') { high += (uint)mask; } mask = mask >> 1; } mask = 0x10; foreach (char c in pattern.Substring(5, 5)) { if (c == 'C') { low += (uint)mask; } mask = mask >> 1; } } private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { if (this.PatternBox.SelectedIndex != -1 && this.PatternBox.SelectedIndex != this.Selected) { this.Selected = this.PatternBox.SelectedIndex; string pattern = this.PatternBox.Items[this.PatternBox.SelectedIndex].ToString(); string replace = Microsoft.VisualBasic.Interaction.InputBox("Enter pattern to replace", "Replace pre-loaded pattern", pattern, 0, 0); if (replace.Length != 10) { return; } foreach (char c in replace) { if (c != 'C' && c != 'A') { MessageBox.Show("Invalid pattern"); return; } } this.PatternBox.Items[this.PatternBox.SelectedIndex] = replace; } } private void button2_Click(object sender, EventArgs e) {

233

try { this.UpdateEEProm(); MessageBox.Show("Updated device successfully"); } catch { MessageBox.Show("Machine not connected"); } } private void button3_Click(object sender, EventArgs e) { try { ResetEEProm(); MessageBox.Show("Reset device successfully"); } catch { MessageBox.Show("Machine not connected"); } } } }

234

PICUSB.DESIGNER.CS namespace PICusb { partial class PicUsb2 { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PicUsb2)); this.button1 = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); this.button2 = new System.Windows.Forms.Button(); this.PatternBox = new System.Windows.Forms.ListBox(); this.LogBox = new System.Windows.Forms.TextBox(); this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); this.groupBox1 = new System.Windows.Forms.GroupBox(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.button3 = new System.Windows.Forms.Button(); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(393, 28); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(97, 25); this.button1.TabIndex = 0; this.button1.Text = "Download"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); //

235

// textBox1 // this.textBox1.Location = new System.Drawing.Point(106, 253); this.textBox1.Multiline = true; this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(374, 53); this.textBox1.TabIndex = 1; // // button2 // this.button2.Location = new System.Drawing.Point(393, 59); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(97, 25); this.button2.TabIndex = 2; this.button2.Text = "Update"; this.button2.UseVisualStyleBackColor = true; this.button2.Click += new System.EventHandler(this.button2_Click); // // PatternBox // this.PatternBox.FormattingEnabled = true; this.PatternBox.Location = new System.Drawing.Point(6, 17); this.PatternBox.Name = "PatternBox"; this.PatternBox.Size = new System.Drawing.Size(85, 199); this.PatternBox.TabIndex = 3; this.PatternBox.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); // // LogBox // this.LogBox.Location = new System.Drawing.Point(7, 17); this.LogBox.Multiline = true; this.LogBox.Name = "LogBox"; this.LogBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.LogBox.Size = new System.Drawing.Size(250, 198); this.LogBox.TabIndex = 7; // // groupBox1 // this.groupBox1.Controls.Add(this.LogBox); this.groupBox1.Location = new System.Drawing.Point(120, 12); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(265, 222); this.groupBox1.TabIndex = 8; this.groupBox1.TabStop = false; this.groupBox1.Text = "Machine Logs"; // // groupBox2 // this.groupBox2.Controls.Add(this.PatternBox); this.groupBox2.Location = new System.Drawing.Point(12, 12); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(98, 222); this.groupBox2.TabIndex = 9; this.groupBox2.TabStop = false; this.groupBox2.Text = "Patterns"; // // button3

236

// this.button3.Location = new System.Drawing.Point(391, 90); this.button3.Name = "button3"; this.button3.Size = new System.Drawing.Size(97, 25); this.button3.TabIndex = 12; this.button3.Text = "Reset"; this.button3.UseVisualStyleBackColor = true; this.button3.Click += new System.EventHandler(this.button3_Click); // // PicUsb2 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(500, 240); this.Controls.Add(this.button3); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); this.Controls.Add(this.button2); this.Controls.Add(this.textBox1); this.Controls.Add(this.button1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.MaximumSize = new System.Drawing.Size(516, 279); this.MinimizeBox = false; this.MinimumSize = new System.Drawing.Size(516, 279); this.Name = "PicUsb2"; this.Text = "Chip Washer PC Terminal"; this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.groupBox2.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Button button1; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Button button2; private System.Windows.Forms.ListBox PatternBox; private System.Windows.Forms.TextBox LogBox; private System.Windows.Forms.SaveFileDialog saveFileDialog1; private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.Button button3; } }

237

PROGRAM.CS using System; using System.Windows.Forms; namespace PICusb { internal static class Program { [STAThread] private static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); FormPICusb form = new FormPICusb(); //Application.Run(form); //form.Hide(); Form form2 = new PicUsb2(form); Application.Run(form2); } } }