Sie sind auf Seite 1von 121

Technical Manual Computer Controlled Scales

Group FOCUS

MTRX 3700 Mechatronics 3 Major Project 2006

Date Revision Prepared by Distribution

: : : :

13 June 2006 64 Group Focus MTRX 3700 Lecturer (David Rye)

1 of 122

2 of 122

3 of 122

A. INTRODUCTION......................................................................................................................... 7 A.1. DOCUMENT IDENTIFICATION....................................................................................................7 A.2. SYSTEM OVERVIEW..................................................................................................................7 A.3. DOCUMENT OVERVIEW............................................................................................................7 A.4. REFERENCE DOCUMENTS .........................................................................................................7 SYSTEM DESCRIPTION................................................................................................................. 9 A.5. INTRODUCTION.........................................................................................................................9 A.6. OPERATIONAL SCENARIOS........................................................................................................9 A.7. SYSTEM REQUIREMENTS ........................................................................................................10 A.8. MODULE DESIGN.....................................................................................................................11 A.9. MODULE REQUIREMENTS : POWER MANAGEMENT SYSTEM .................................................14 A.10. CONCEPTUAL DESIGN: POWER CONTROL SYSTEM ..............................................................15 A.11. MODULE REQUIREMENTS : SOFTWARE FILTER....................................................................18 A.12. CONCEPTUAL DESIGN: SOFTWARE FILTER..........................................................................19 A.13. MODULE REQUIREMENTS : STATISTICS MODULE.................................................................23 A.14. CONCEPTUAL DESIGN: STATISTICS MODULE.......................................................................25 A.15. MODULE REQUIREMENTS : LCD...........................................................................................26 A.16. CONCEPTUAL DESIGN: LCD.................................................................................................28 A.17. MODULE REQUIREMENTS : WEIGH/COUNT..........................................................................30 A.18. CONCEPTUAL DESIGN: WEIGH/COUNT................................................................................32 A.19. MODULE REQUIREMENTS .....................................................................................................36 A.20. CONCEPTUAL DESIGN...........................................................................................................41 B. USER INTERFACE DESIGN..................................................................................................... 51 B.1. CLASSES OF USER...................................................................................................................51 B.2. INTERFACE DESIGN.................................................................................................................51 C. HARDWARE DESIGN................................................................................................................ 53 C.1. SCOPE OF THE CCS SYSTEM HARDWARE..............................................................................54 C.2. HARDWARE DESIGN................................................................................................................54 C.3. HARDWARE VALIDATION........................................................................................................58 C.4. HARDWARE CALIBRATION PROCEDURES ...............................................................................58 C.5. HARDWARE MAINTENANCE AND ADJUSTMENT .....................................................................59 D. SOFTWARE DESIGN................................................................................................................. 60 D.1. SOFTWARE DESIGN PROCESS .................................................................................................60 D.2. SOFTWARE QUALITY ASSURANCE..........................................................................................60 D.3. SOFTWARE DESIGN DESCRIPTION..........................................................................................60 D.4. PRECONDITIONS FOR SOFTWARE............................................................................................62 E. SYSTEM PERFORMANCE........................................................................................................ 63

F. SAFETY IMPLICATIONS.......................................................................................................... 65
5 of 122

G. CONCLUSIONS.......................................................................................................................... 65

A. APPENDIX B: CIRCUIT SCHEMATICS................................................................................ 69

B. APPENDIX 3 FILTER PERFORMANCE.............................................................................. 75

........................................................................................................................................................... 76

........................................................................................................................................................... 77

........................................................................................................................................................... 78

........................................................................................................................................................... 79

C. APPENDIX 4: CODE LISTINGS ............................................................................................... 81

6 of 122

A. Introduction
A.1. Document Identification
This document describes the design of the Computer Controlled Scales (CCS). This document is prepared by Group FOCUS for assessment in MTRX 3700 in 2006.

A.2. System Overview


The CCS measures weights as well as counting number of objects. The maximum weight the Focus accepts is 1.2 Kg. The CCS system is made up of the following subsystems, whose details are outlined in this report. LCD Hardware User Interface Weigh/Count Text To Speech Factory User Options Filter Statistics Power

A.3. Document Overview


This report details the design process of the CCS. It first describes the whole system as a whole before going into detail for each individual module. Interface designs as well as test carried out are also detailed.

A.4. Reference Documents


The present document is prepared on the basis of the following reference documents, and should be read in conjunction with them. 74HC04/ 74HCT04 Phillips Hex Inverter,2003 July 23 Fairchild Semiconductor LM555/NE555/SA555 Single Timer Datasheet BUZ71 N - CHANNEL 50V - 0.085W - 17A TO-220 STripFET] POWER MOSFET Datasheet National Semiconductor LM124/LM224/LM324/LM2902 Low Power Quad Operational Amplifiers, August 2000 Motorola SN54/74LS04 Hex Inverter Datasheet Fairchild Semiconductor BC548/BC548A/BC548B/BC548C NPN Transistor DataSheet Fairchild Semiconductor FDC6325L Integrated Load Switch, August 1998 National Semiconductor LM741 Operational Amplifier, August 1998 Texas Instruments SN5414, SN54LS14,SN7414, SN74LS14 HEX SCHMITTTRIGGER INVERTERS, Datasheet Fairchild Semiconductor BC556/557/558/559/560 PNP Transistor DataSheet HEXFET Power MOSFET IRF9540N Datasheet Fairchild Semiconductor MM74C922 MM74C923 16-Key Encoder 20-Key Encoder, August 1997 PIC18FXX2 Data Sheet, Microchip WTS701 User Manual

7 of 122

KS0066U LCD Driver Datasheet, Samsung

A.4.1.
Table

Acronyms and Abbreviations


1 -1 lists the acronyms and abbreviations used in this document. Table 1-1: Acronyms and Abbreviations. Acronym ACFR CTS PDL TBD TLA USYD CCS TTS ROM RAM LCD MCU USART ASCII MNML AD CCP1 CCP2 Meaning Australian Centre for Field Robotics Continuous or Continuously Program Design Language To Be Done, also To Be Defined Three Letter Acronym The University of Sydney Computer Controlled Scales Text to Speech Read only Memory Random Access Memory Liquid Crystal Display Microcontroller Unit (PIC18F452) Standard Serial Transmission Protocol American Standard Code for Information Interchange PIC Minimal board Analog to Digital PIC18F452 Timer register PIC18F452 Timer register

8 of 122

System Description
This section is intended to give a general overview of the basis for the CCS system design, of its division into hardware and software modules, and of its development and implementation.

A.5. Introduction
The CCS can generally be divided into two components, hardware and software. Hardware components include: LCD screen Text To Speech (TTS) chip PIC18F452 MNML board Keypad grid Buttons RS232 serial port Cantilever Load Beam and Bridge Rectifier Circuit The software component can be further divided into six modules, these are: Main function module LCD module T2S module Filter module Statistics module Factory mode module. This report aims to explore each of the above in detail.

A.6. Operational Scenarios


The flow char below is a representation of how each module is linked to each other. The CCS can be operated in one of two modes, user and factory mode. The user mode is divided into two sub modes: user remote and user local mode. For user local mode a 9V battery is required to power the scale. When the scale is first powered up, it is in the weighing mode. When the user places an item in the bowl, the LCD will display the weight of the item. This is calculated via a pre-determined function which converts a voltage into a weight. To change this function would require the running of user factory mode and the calibration module. A switch on the scale allows the user to change the display between grams and ounces. The other function the CCS is designed for is the counting of objects placed in the holding bowl. The number of items counted will be displayed on the LCD as well as output as speech. A mute switch allows the speaker to be turned off. The scale also has a taring button which resets the display to zero when pressed and any subsequent weights will be measured with this new relative zero. If the scale is connected to an IBM-compatible PC with Windows HyperTerminal installed, the user remote mode will be activated. All inputs and outputs will be displayed on the HyperTerminal program.

9 of 122

The factory mode is not available to the normal user, only authorised persons with the correct password will be allowed to access this mode. In this mode, extra options become available, these includes having the mean and variance of the last weightings printed to screen, printing of raw data. To turn off the scale, press the off button. Factory Mode The factory mode is designed for diagnostic and more in depth use than that of the casual user. The factory mode, apart from providing the same functions as that of the user remote mode, ie count and weigh, also provides a calibrate and statistics mode. The calibration function is important in maintaining the accuracy of the scale as the algorithm through which the weight of items is calculated can be updated through activation of the calibration mode. If suspicious values are being returned by the device, the calibration mode is important in making sure that the device able to operate correctly throughout the life of the device. The statistics module allows the user to examine the raw and filtered data that is being outputted from the device and hence observe the accuracy and consitency of the values being returned by the device. The mean and variance functions are also able to give a more accurate reading on the precise weight of an item Rather than taking a reading at one point in time, a value may be calculated over a number of points in time giving an average value and removing some erratic results.

A.7. System Requirements


The operational scenarios considered place certain requirements on the CCS system, and on the modules that comprise it. The CCS is powered by a 9V battery when running in user local mode. If in user remote or factory mode, it is powered by 12V voltage input To run either the user remote or factory mode, an IBM-compatible PC with Windows HyperTerminal installed is required.

10 of 122

A.8. Module Design


When the CCS is designed, we decided to split everything into hardware and software couples, i.e. for each hardware component there is software written to support it. As illustrated in the diagram below, the CCS system can be broken down into several hardware and corresponding software pairs.

Factory Mode Factor mode is divided in three main modules: Calibration mode => Fits appropriate functions between intervals of weights to give the most accurate weight value. Shows statistics mode => Displays all the statistical data requested by the user. User remote mode => Divided into two sub modules. The determine weight module calculates the weight currently placed on the scales and the count module measures the number of items currently placed on the scales based on information the user had entered when requested.

Figure F1 below shows how these functions are broken into separate modules

11 of 122

FACTORY MODE

CALIBRATION

SHOW STATISTICS

USER REMOTE MODE

DETERMINE WEIGHT

COUNT

Fig F1: Factory mode divided into modules

Each module calls a series of other functions which each perform a single task to assist its corresponding main module. The figure below shows which functions are called by which modules.

CALIBRATION (aka in code Display_calibrate)

transmit_text

calculations

Fig F2(a): Calibration module calling corresponding functions.

SHOW STATISTICS (aka in code Display_stats)

transmit_text

Fig F2(b): Show startistics module calling corresponding functions.

12 of 122

USER REMOTE (aka in code user_remote)

Display _weight

show_weight _grams

Show_ weight _ounce s

COUNT (aka in code count_mode)

Initialise

transmit_text

transmit_characte r

DETERMINE WEIGHT (aka in code determine_weight)

determine_fn

Fig F2(c): User remote module calling corresponding functions.

13 of 122

A.9. Module Requirements: Power Management System


The operational scenarios considered place certain requirements on the power control and distribution system, and on the modules that comprise it. The power sub-system both distributes power to the various hardware elements and provides implementation of the two minute inactivity timer.

A.9.1.

Functional Requirements

This section describes the functional requirements of the power management sub-system; those requirements that must be met if the module (and system) is to function correctly and according to specification. Power control is implemented purely in hardware and is interfaced to both hardware and software sub-systems A.9.1.1. Inputs The power sub-system is the first contact point for the power supplied to the unit from all sources. These include battery power input through the 9v battery snap and AC adaptor power input through the switching jack. Power system input voltage is limited to 12v owing to the use of 16v rated capacitors and 16v maximum rating on the NE555. Implementation of the two minute timer requires that this sub-system take input from the power-on button and feedback from the microcontroller indicating that an event has occurred considered as activity, e.g. serial bus communications. The sub-system must also take input from the keypad indicating that a key has been pressed constituting valid activity. Inputs from other subsystems are TTL compatible. A.9.1.2. Process The two minute period is implemented around a NE555 timer IC configured as a mono-stable timer. The 555 circuit provides a two minute high output on power-up, switching power to a BUZ71 power control MOSFET, in turn switching the power relay. The ability to restart the period is provided by a transistor which discharges the 555s timing capacitor. This transistor is fully switched at the TTL on state voltage with minimal current. Noise below 0.7v on the restart_period line is insufficient to bias the transistor to on state and is thus ignored. A.9.1.3. Outputs It is imperative that there be minimal voltage drop through the power circuit as the regulator voltage overhead is of concern operating a 5v regulator from 9v, even with the use of the ZSR500 low dropout regulator. The output of the power controller is full input voltage to the MML18 onboard regulator. This was achieved by using an output switching relay. The power board also provides distribution for 5v regulated power taken from the auxiliary power pins on the MML18 board. A.9.1.4. Timing Timer period is adjustable from approximately 35 seconds to 10 minutes, and is set in accordance with specification to 2 minutes after last activity. A.9.1.5. Failure Modes

14 of 122

Over voltage will not damage the unit when powered on if below 16v. However voltages above 50v will cause breakdown across the BUZ71 switching power on to the unit. Over current protection is provided by the thermal shut-down feature of the ZSR-500 regulator. Additionally it was intended to provide a 16v zener diode as over voltage protection across the input to the power controller. Reverse polarity protection to the MML18 board is provided inherently by the ZSR-500 without the voltage loss associated with a rectifier diode.

A.9.2.

Non-Functional (Quality of Service) Requirements

A.9.2.1. Performance There do exist much simpler methods to implement a two minute timer, this method was chosen for its repeatability as well as last minute component availability. Other options considered are detailed in the hardware appendices. A.9.2.2. Interfaces It would be desirable to include a reverse polarity protection facility on the switching side of the power controller circuit. A.9.2.3. Design Constraints The number of parts used in this design, and as such associated cost, makes it a poor choice for a commercial implementation.

A.10.

Conceptual Design: Power Control System

A.10.1.1. Rationale The power module was designed to function without any processor overhead to increase the possible sampling rate of the AD conversion and subsequent data processing. Within the design evolution there were initially other timer designs formed and implemented. Both were unable to be used in the final implementation due the damage to MOSFET devices at the last minute. Details are outlined in the appendices.

15 of 122

A.10.1.2. Operation Diagram

Start-up

2 Minute Period Activity

Activit y

16 of 122

The time period invoked by the 555 timer is a function of the time taken fir the 220uf capacitor to charge from 1/3 of rail value to 2/3 of rail value, and is controlled by the selection of the variable resistor value once capacitor choice is made to standard values. The use of a low leakage capacitor allows for increased interval reliability. Time period is calculable by; Time = 1.1 x C x R Final power switching is achieved through the use of a relay in order that there is zero voltage drop between input and output.

A.10.2. Assumptions Made


This module was designed largely separate to software modules and as such was implemented entirely in hardware, this was based on the assumption that any processor overhead was best avoided, i.e. not using any timer subsystems, allowing them to be available to other modules. Upon implementation of other modules it could be seen that there was room for software implementation of the two minute timer.

17 of 122

A.11.

Module Requirements: Software Filter

The operational scenarios considered place certain requirements on the input data conditioning module, and on the processes that comprise it.

A.11.1. Functional Requirements


This section describes the functional requirements of the input conditioning module those requirements that must be met if the module (and system) is to function correctly. A.11.1.1. Inputs Input to the filter is a 16 bit unsigned integer between 0-1024 correlating to the output of a 10 bit resolution AD conversion. A.11.1.2. Process The internal working of the filter is to compare the present data value with previous data samples and perform a weighted addition of these values in such a way as to reduce the presence of unwanted frequency signal components. A.11.1.3. Outputs The filter output should represent the input data which exists below the corner frequency. Output is via a 16 bit integer. A.11.1.4. Timing Group delay is not an overriding constraint due to the low frequency of user data output. A.11.1.5. Failure modes Should the data point provided by the AD conversion exceed 1024 the filters data types will overflow. However the possibility of this occurrence is considered sufficiently remote as to not require an error trap.

A.11.2. Non-Functional (Quality of Service) Requirements


A.11.2.1. Performance Ideally the filter should not affect the pass-band data in any way except for removing noise. In order that incremental development be possible the filters gain should be unity within the passband. A.11.2.2. Interfaces A maximally flat filter pass-band is desirable for accurate weight results. In addition the code should be structured to allow retuning of the coefficients with minimal recoding; this can be achieved using symbolic constants and a centrally collated filter weight array. A.11.2.3. Design Constraints Floating point math is to be avoided at all costs due to the massive computational overhead involved when used on this processor. Computational loop time should be reduced where possible to reduce processor time conflicts between modules.

18 of 122

A.12.

Conceptual Design: Software Filter

A.12.1.1. Rationale Filtering is required between the beams differential amplifier and the weight calculation algorithm to remove both beam oscillation and noise components of the signal. An anti-aliasing filter is also required prior to input of the signal to the AD system. Frequencies of interest lie between 0-3 Hz for weight calculation. As the corner frequency of an active analogue filter is lowered to this value the resistor values required for its implementation increase to values around 5 M ohm and filters become more prone to oscillation effects. Specification requires that in user remote mode a weight sample is output every 200 milliseconds. If each output were to have 20 contributing measurements a sample frequency of 100 Hz is required as a minimum. As such 100Hz was decided as the starting frequency for implementation. To prevent aliasing of the input signal it was decided to implement an analogue low-pass filter with a 40 Hz corner frequency, followed by a 3Hz low-pass software filter, to avoid the undesirable effects observable in an analogue filter with a 3 Hz corner. A maximally flat pass-band is desirable along with a sharp cut-off curve. Ideally an infinite impulse response filter can provide very desirable characteristics, however when operated with such a low corner frequency the possibility of runaway increases. Runaway traps can be placed on the coefficients; however the filter performance and predictability will be severely compromised when these traps trigger frequently. It was decided that an agreeable compromise could be reached between optimal performance and predictability by using a 20 tap finite impulse response filter. The performance loss was justified by no possibility for runaway and easier implementation without the use of floating point numbers. The FIR filter was designed and analysed using DigiFilt to have a gain of 1. This gain value was chosen such that the filter could be implemented after other sections with minimal change to surrounding code. However the resulting filter coefficients were far smaller than 1 for a 21 tap filter. In order that these coefficients be integerised a multiplier was applied, large enough to retain accuracy in the smallest coefficient but to also avoid overflow of the integer type when multiplied by the data point (0-1024). A multiplier of 512 was chosen as it achieved both objectives and reduced computational time when the multiplier was removed simply using a left shift operation. The use of a false pointer to the current element in the circular data buffer eases the logic of math operations on the pointers. The insertion pointer is the same in all arrays during the data operation sequence. It was intended that in final implementation the compiler chosen multiplications of 16x8 bit numbers with a 16x16 routine be replaced by a more efficient 16x8 assembler routine, however the implementation was never achieved due to variable passing issues and problems in other modules.

19 of 122

Data Array

Filter Weights Array

Sum= Sum + (Data x Filter Weight) No Yes


All weights used

Remove Multiplier >>10

A.12.2. Assumptions Made


It is assumed that the noise power ratio will not exceed 10 when the analogue anti-aliasing filter has been implemented.

A.12.3. Constraints on Module X Performance


It can be seen that the amplitude plot of the filter (in appendix) there exist several amplitude spikes in the transition pass-band. The major constraint on the operation of the filter is that transition band noise be of insufficient amplitude to affect pass-band values.

20 of 122

21 of 122

22 of 122

A.13.

Module Requirements: Statistics Module

The operational scenarios considered place certain requirements on the statistics module, and on the functions that comprise it.

A.13.1. Functional Requirements


This section describes the functional requirements of the statistics module those requirements that must be met if the module (and system) is to function correctly. A.13.1.1. Inputs Input to the statistics module is the circular data storage buffer weight_data; containing postfilter, weight converted data, the variable samples_used indicating the number of samples used to determine a weight output, and the false data pointer indicating the current data point. The data_index is error trapped inherently in the looping constructs contained within the mean_weight and weight_variance functions. If the pointer is not within the valid range for any reason it will be adjusted with no more than one second of false measurements output. A.13.1.2. Process Data population mean is computed for the sample set contributing to the weight output using a straight averaging algorithm, implemented as a loop with iterations equal to the number of data samples used. The averaging algorithm appears as follows; Mean=(Sum of sample [1 through x] )/(Number of constituent samples) Variance is computed based on a population adjusted algorithm as opposed to a sample set algorithm. This is appropriate as at the time of operation the entire sample population is known and greater divergence need not be allowed for. Variance= (Sample [ 1 through x] Mean )2 / (Number of constituent samples)

A.13.1.3. Outputs Output of both values is to 2 d.p. accuracy through multiplication by 100 prior to division operations and subsequent return passing. This must be accounted for when displaying or utilising these values. It is felt that this resolution is required especially for the meaningful output of variance. The mean and variance functions are run every sample period and the variance output is designed to be used as a measure of weight stability leading to display of a stabilised weight reading.

A.13.1.4. Timing Both functions are engineered to require minimal computational time. A.13.1.5. Failure modes Failure of the functions due to out of range input values will result through data type overflow, however for this to occur the critical error would be in the passing function and as such no error trap or rectification is included within this module.

23 of 122

A.13.2. Non-Functional (Quality of Service) Requirements


A.13.2.1. Performance Minimisation of variable data type sizes reduces computational routine complexity and thus time. Data types have been chosen so as not to overflow in operating conditions but to remain as compact as possible.

A.13.2.2. Design Constraints Minimising data type sizes has been traded off against greater resolution. Floating point math is to be avoided at all costs due to the massive computational overhead involved when emulated on this processor.

24 of 122

A.14.

Conceptual Design: Statistics Module

Calculation of the weight variance provides a simple manner in which to quantify the stability of the measured data point. This information can be used to determine whether or not a stable reading has been achieved and subsequently invoke the display_weight function. As the variance can be used to this end it was decided to invoke the weight_variance function every sample, requiring that the mean_weight function also be invoked beforehand. The mean function is able to be used to average the weight before display to provide further weight stabilisation. Both functions were designed to provide a simple return value, allowing their utilisation wherever desired. The return values were made global so as to be available not only to the calling function but also remain valid for use by the serial functions without requiring that the function be invoked again. To remove the possibility of there being a change to the number of samples used between calls to the mean_weight and weight_variance functions a local copy of the variable is made upon entry to the mean_weight function. The C18 specific short long int data type is used where more than 16 bits are required but less than 32 bits.

Sample

Weight Data Array

Mean Weight

Weight Variance

Varianc e < Desired

Y A

Display Weight

A.14.1. Assumptions Made


It is assumed that the data elements in the weight array are all less than 1200, failing this the data types used will overflow, causing smaller values than expected to be returned.

25 of 122

A.15.

Module Requirements: LCD

The operational scenarios considered place certain requirements on the LCD, and on the modules that comprise it.

A.15.1. Functional Requirements


This section describes the functional requirements of LCD those requirements that must be met if the module (and system) is to function correctly. A.15.1.1. Inputs

To setup the LCD to receive inputs, it must be initialised accordingly. Following a successful initialisation, commands can be sent from software to write various strings on the LCD screen. The strings that are written to screen depend on the functional requirements. The two lines are therefore utilised to serve its functional requirement. Line 1 is used to display weight or count data to the user, whereas Line 2 is used to label the buttons that are physically placed below it. Hence, there are two types of strings that are required:. The first is the RAM string, where the data is constantly changing and needs to be calculated by the MCU before being printed to screen. The second set of strings are hard coded into ROM as they specifically either label the data, which describes a certain mode, or label a button. The LCD interfaces to the microcontroller requiring four data lines and three control lines. Another three lines (0V reference, +5V, and 0.6V contrast pin) are also required to power the device. Information that is to be displayed on the screen is sent via the data lines whereas slave commands are sent via the control lines. In this way, the appropriate instructions are sent with the required data to display a desired result. A.15.1.2. Process

There are three main processes within this module: Initialisation Parse Integer Print String to LCD RAM Initialisation This process is called once when the system is powered up. The purpose is to ready the device to receive data and display it appropriately. Parse Integer This process simply converts an integer into its comprising digits. These digits are then stored in data memory. This is done so that the oscillations from the strain gauge are clearly visible. If a simple standard C programming library function were to be used, the result could potentially result in a poor response time. By parsing the number and storing the digits, the program can repeatedly refer to these stored digits and print the numbers appropriately. Print String to LCD RAM This simple process is as per the manufacturers data sheet. A ASCII character is loaded into the LCD buffer. This process is repeatedly called to print a string. A.15.1.3. Outputs

Any output is considered successful if the information displayed on the screen makes logical sense. That is, if a label were to be printed, the label must be visible. Likewise, if a fluctuating number is required to show that the strain gauge is oscillating, the numbers should fluctuate in phase with the frequency of vibration of the cantilever load beam. A.15.1.4. Timing

26 of 122

The weight reading, or any change in the deflection of the cantilever load beam must be immediately present. That is, if additional weight is added to the scales, the number on the screen should move up accordingly. Any latency reflects a poor response within the software and cannot be deemed acceptable for the purposes of this operational scenario.

A.15.2. Non-Functional (Quality of Service) Requirements


The requirements listed below are to be met to ensue Engineering quality and more importantly ease of use when it comes to its basic operational functionality. A.15.2.1. Performance

The purpose of this module is to display current state data along with any weight measurements computed by other modules. Hence, the information must be clearly represented. Any change in any of these data requires a swift change in the information on the screen. A.15.2.2. Interfaces

Displayed information must be easy to read, easy to comprehend and make common sense. That is, the information presented on the LCD screen should be self explanatory. The user should not have to refer to the Operational Manual to determine what state the machine is currently in. Similarly, the options that are available to the user must also be clearly obvious. Once the machine has changed state, the change in state must be obvious to the user and any other relevant instructions or information must be clearly displayed. A.15.2.3. Design Constraints

The KS0066U Samsung LCD is a 2 x 16 dot matrix display. This implies only 32 characters including formatting space characters can only be displayed at one time. Therefore, the strings that are to be printed to screen must be short and simple to convey the maximum information in this restricted space. Secondly, there is no background lighting for the module. This could make reading the display a little more difficult. To overcome this, the device must be mounted to ensure the easy viewing from an appropriate viewing angle. Finally, it is important to keep track of the current position of the cursor. To avoid this problem, the LCD buffer is continuously refreshed to ensure the cursor is always at the start of the buffer.

27 of 122

A.16.

Conceptual Design: LCD

The LCD module performs the main task of conveying information to the user. This is done by printing strings to screen. For standard labels and Mode Descriptors, the strings are hard coded into memory and sent whenever there is a state transition. Printing strings from ROM is the simplest task. The string is sent using a pointed to a buffer loading method. The buffer loading routine places the ASCII code of the character in the string onto the Data bus. The way in which this is done is a standard LCD process which is detailed in the LCD datasheet. The routing therefore keeps repeating this process until it reaches the end of the string, which is designated by a null character. This ends the process by telling the LCD that the transmission is complete. The data is displayed on the screen To display the weight data, parsing is required. The other software modules manipulate a integer cast data variable to determine the current weight on the scale. This number is then required to be displayed on the LCD screen. To do this, the digits must be parsed out of the Integer and converted into its corresponding ASCII representation. The parsing method is as follows: Grams When the user wishes to display the current weight on the scale in grams, the software calculates the current weight and stores it in the grams variable. The product specification demands that the final weight reading in grams must be correct to +/- 1g. Hence, the integer representation of this number needs to be displayed. The algorithm therefore uses simple division to determine the respective digits. (NB. tenEn implies ten raised to the exponent n. tenen implies ten raised to the exponent n). The general method is described below. Suppose we want to find the digit in the nth place value.

digit =

( weight ) mod(10n +1 ) 10n

This algorithm extracts the nth digit from the number. Eg: Weight = 137;

tenE 2 = tenE1 =

(137) mod(1000) = 1; 100 (137) mod(100) = 3; 10 (137) mod(10) = 7; 1

tenE 0 =

The parse digit process is repeatedly called to update the respective variables tenEn. This process is interrupted by the ISR to update the weight variable. This ensures a quick reponse time as well as an accurate representation of the weight on the scale. Ounces When the user want the weight to be represented in Imperial units, the weight integer needs to be converted into ounces. This will therefore require the use of floating point arithmetic. However, any such operation is best avoided. The stored weight value is therefore multiplied by 10 before it is divided by the appropriate conversion factor. The above algorithm described in the Grams section is then used to determine the various digits. The aim of multiplying the weight number by ten moves the first decimal into the ones column (place value). The printing function then moves the first decimal place back into is correct position so that it appears in a manner that would seem logical to the user.

28 of 122

When printing strings to the screen, the second line of the LCD requires only one write operation. This is because it serves the purpose of a label for the buttons that are meant to be below it. These will only change when the system changes state. The current state is repeatedly printed on the first line. This is to ensure that the cursor is always at the end of the mode label. The next write function is always an update of the weight reading. Following this, the weight label is reprinted. This is looped to ensure all changes are written on the visible part of the screen and not just to the LCD buffer. The final step in the parsing process utilises the Lookup nature of the ASCII chart. The parsing algorithm will always yield a number between zero and nine. This is because any division when the variable is cast as a integer results in a truncation of the numbers following the decimal place. Hence, this number is used as an index. The ASCII values for the numbers from zero to nine are (decimal) 48 to 57. Hence, following the algorithm, the parsed digits are added with (decimal) 48 before being stored. Hence there is no need for calling string parsing methods which come standard in most C programming compiler libraries.

A.16.1. Assumptions Made


No assumptions were made to implement this model.

A.16.2. Constraints on LCD Performance


The digits that are sent to the LCD are printed. Should the weight calculation yield a valid result in terms of the mathematics but an invalid result in terms of operation, the LCD will display that result accordingly. These errors need to be trapped using extra software in the respective modules. One glaring constraint is in the event of an improper mathematical operation. These will never arise whilst calculating and displaying a weight as most factors and coefficients are hardcoded into the software. The only problem arises when the user is required to enter the number of items when in the Count mode. The default divisor is set to 01 but should the user enter 1, the result is 1. Normally, if the weight of the single object is relatively large, there should be no problems in terms of display. The user will be able to logically determine that he has entered a value that does not make sense and will reset the program. However, problems arise when the weight of the single item is too small. The resulting division produces a number that does not give an index between 0 and 9. Addition with (decimal) 48 will therefore give a character that is obviously not in the set of single digit integers. The user must interpret this as a setup error and reset the system by re running the Count Setup procedure.

29 of 122

A.17.

Module Requirements: Weigh/Count

The operational scenarios considered place certain requirements on the Weigh/Count Module, and on the processes that comprise it.

A.17.1. Functional Requirements


This section describes the functional requirements of the Weigh/Count module those requirements that must be met if the module (and system) is to function correctly. A.17.1.1. Inputs This module is purely arithmetic in that its duty is to convert data into various forms. The input is the voltage from the Strain Gauge, which is converted into an integer that is either in grams or ounces. If the Count mode is enabled, the module will determine the number of items on the scale and will calculate and store this integer. In addition, the user is asked to enter a certain base value. This base value is the weight of one item. This number is determined in a special Count Setup state, which asks the user to place a certain number of identical items on the scale before entering the number of items into the system. This value is then used to determine the weight of one object. This is then used as a reference denominator to manipulate future weights placed on the scale to determine the number of items. The last input is the use of the TARE option. This is a button that is wired to trigger an interrupt. When pressed, the system stores the current weight in program memory and subsequently subtracts this offset from all future weight readings. This is otherwise known as zeroing the balance. To remove the offset, the user must simply remove all weights from the scale and then press the tare button once more. A.17.1.2. Process The only physical conversion is the change from an analog voltage, which comes from the strain gauge, to a digital 10 bit number. The subsequent conversions are purely mathematical and can be modelled by simply multiplying the 10 bit number by a certain coefficient. This coefficient is determined by the operational mode and the various other demands the user places on the system. Therefore, this module is required to perform the appropriate mathematical conversion processes to convert a voltage into a 10 bit number, which then should be converted into a value that reflects the weight on the scale in grams or ounces. This integer number should then be stored for later reference. In addition, should the system be in Count mode, the software should perform appropriate mathematical operations to convert the 10 bit number into another integer that reflects the number of items that are on the scale. This depends on the base value the user has entered into the system. A.17.1.3. Outputs All outputs are stored within a variable in data memory. These variables are referenced and then manipulated to visually and/or audibly present them to the user.

A.17.2. Non-Functional (Quality of Service) Requirements


The requirements listed below are to be met to ensue Engineering quality and more importantly ease of use when it comes to its basic operational functionality. A.17.2.1. Performance The module should convert the numbers as quickly as possible. This ultimately depends on the design of the software. However, the AD Converter can be configured to convert at specific times to maximise performance and measurement accuracy. However, performance is sacrificed at the expense of using floating point arithmetic in the software. This is interpreted by the compiler and is magnified into several lines of code. However, the option of minimising code was chosen to quickly debug hard coded coefficient values and to save time.

30 of 122

A.17.2.2. Interfaces The AD converter expects a voltage. This is converted into various forms depending on the mode of operation and is then stored within ROM.

A.17.2.3. Design Constraints The numbers that are to be displayed range from (decimal) 0 to 1500. The resolution of the AD converter is 10 bits and so this data must be scaled to represent that range. To do this, a larger data type needs to be used to handle the size of the data. Performing multiplications and division by large numbers (~16 bit) take time since the standard compiler routine creates a listing that is quite lengthy. This in any case cannot be avoided and so we choose this option at the expense of performance. In any case, implementing integer arithmetic routines to deal with floating point numbers was not done due to time constraints .

31 of 122

A.18.

Conceptual Design: Weigh/Count


AD conversion; Number Conversion into standard Weight Units;

There are two vital components to this module:

The AD module interfaces to the Strain Gauge via its input channels. Simply, pin AN0 on PORTA of the MCU is connected to the Output of the strain gauge. The output signal ground reference line is connected to the ground of the MCU MNML board. AD Module The AD is configured to accept a voltage between 0 and 3.3V on pin AN0. The other pins on PORTA are configured to be digital. This prevents any fast switching on these pins, which prevents any noise from interfering with the Strain Gauge Signal. The voltage is then converted into a 10bit number. The maximum resolution of the AD converted is used to improve precision. The option of attaching a reference voltage to increase conversion resolution was dismissed to minimise complexity. The AD converter converts the voltage in a very small amount of time. Therefore, to remove some of the oscillations of the beam, the AD conversion was triggered to start every 10ms, producing a sampling frequency of 100Hz. There is no need to consider aliasing as we are looking for the steady state value of the strain gauge. The trigger was driven in software by setting the GO bit when a 10ms capture compare interrupt fired on CCP1. The other alternative was to implement a hardware interrupt where a capture compare on CCP2 triggers a special event. This method however only saves a few microseconds. The result of the conversion is saved in a variable in program memory. As this process is interrupt driver, the weight variable is constantly changing. This implies that at any given point in time, the number displayed on the LCD is not the latest measured value. There is a good chance that a converted value is never displayed. Some of the routines are very long, and are hence interrupted to update the weight variable. For example, the LCD could be printing a weight on screen but the weight variable would have updated almost 100 times before the next update is written to screen. Since we are only concerned with the steady state value, this is not a problem. However, since we are also collecting statistical data such as the mean and variance, it is important that all this sampling frequency is implemented. By obtaining a rough shape of the transient response, we can calculate the mean and variance, which fixes the cut-off frequency and filter coefficients. This will remove the low frequency oscillations, which will allow the user to see the steady state value sooner. Number Conversion Following a AD conversion, the number is both buffered in an array for statistical purposes and passed to this module. This value then tested to fit in a certain category. The categories are defined as certain number ranges corresponding to 200g intervals starting from 0 to and ending at 1200g. Each category has a certain mapping function. It was experimentally found that the relationship between weight and voltage was linear. Hence, the 10 bit number was multiplied by a gradient and an offset to find its representation as a weight in grams. Due to complications with the calibrate function, this method was not tested with the scales and so was not implemented. Instead, the gradient and offset values were hard coded for all categories. This gave a weight reading with a +/- 10g accuracy. The experimental values are shown below. The graph represents the relationship between the converted value and the weight that is placed on the scale. As we can see, these gradient and offset values were used.

32 of 122

AD Output to Weight Correlation


1200 1000 y = 1.6389x - 3.6138 800 600 400 200 0 0 500 AD Output (decimal)
33 of 122

Weight (g)

1000

Weight 5 10 15 20 25 30 35 40 45 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 1000

Output 6 8 11 15 19 20 24 26 29 33 63 94 124 153 184 215 244 278 307 339 370 402 430 462 489 520 551 581 611

NB Refer to Appendix fort Experimental Data The algorithm with respect to the Count Mode is however not as simple. Essentially, the user enters the number of items via the LCD user interface. This number defines the number of items that are on the scales. The program then takes this number and divides the latest weight reading to determine the weight of one object. This number is then stored to divide future weight readings to calculate the number of items on the scale. (NB all items must be identical to ensure validity). This new number is stored. The interesting feature of this design is that the program uses the result of the AD conversion directly. There is no need to reference the variables that store the weight in grams or ounces. The reason is rather simple. The weight of a single object is with reference to a converted analog value. Since the relationship between the converted analog value and the weight is linear, the software can use this result to determine the number of items on the scale. Eg: weight of n items = D1 (10 bit number) weight of 1 item # items = D1/n; = (D2)*(n/D1);

The linear relationship can be exploited to give good results. If however, the relationship between the weight placed on the scale and the resultant digital 10 bit number from the AD conversion were not linear, the above logic will fail. In that instance, we would have to find the weight in normal weight units such as grams or ounces and then perform the division and multiplication to determine the new number of items on the scale. All stored numbers, such as current weight or number of items, are referenced by the LCD printing routines, which eventually display the number to the user.

34 of 122

A.18.1. Assumptions Made


In implementing the hard coded coefficient method, we assume that the strain gauge characteristic does not change with time. Normally, this error can be removed with a simple calibration, however due to design complications with the calibrate module, this assumption had to be made. The subsequent complications were clearly apparent.

A.18.2. Constraints on Weigh/Count Performance


The Performance depends on the validity and accuracy of the calibrate function. If this module is either non-existent or poorly designed, the error in the displayed weight will be obvious to the user. That is, a 50g weight will not read as 50g on the scale. Moreover, this error is not constant. Due to our findings that the strain gauge characteristic is linear, the error will increase or decrease depending at which end of the weight scale we are operating at. The user would also like to read a weight as soon as possible. Any oscillations are normally regarded as a measurement error on the part of the user. If we as the designer cannot remove these hardware induced oscillations, the resultant effect is that the user cannot rely on our product. This implies that this module relies heavily on the filter output to ensure that the input data to this module is the same after the oscillations at the strain gauge have subsided to a particular frequency.

35 of 122

A.19.

Module Requirements

The operational scenarios considered place certain requirements on the CCSS, and on the modules that comprise it. This section describes the functional requirements and non-functional requirements of each module. Before each module is analysed, each individual function are defined in terms of its purpose, inputs, processes and outputs. FACTORY MODE Initialise function => declares all the requirements for serial transmission and reception as well as receive interrupts. It has no inputs or outputs other then configuring the necessary registers. transmit_text => sends a string to the serial terminal. Inputs are a pointer to the start of the string as well as the final character in the string so that the function knows when to stop transmitting. Outputs the string in hyperterminal. transmit_character => sends a character to the serial terminal. The only input required is the character to be displayed. Output is the character displayed in hyperterminal. determine_fn function => determines the weight-voltage function to be used in calculating the weight depending on the current voltage reading from the scales. Inputs are an index to indicate the location of the gradient and offset in their corresponding arrays, the voltage arrays used for calibrating and the current voltage reading. calc_weight function => calculates the weight on the scales using the function determined by determine_fn. Its input parameters are the determined gradient, the determined offset and the current voltage reading. show_weight_grams => after allowing the user to select grams or ounces via a keyboard entry the sub routine converts the weight integer into ascii form and publishes this number to the screen show_weight_ounces => after allowing the user to select grams or ounces via a keyboard entry the subroutine performs a mathematical calculation upon the raw weight so as to convert the figure to the relevant ounces number. This new number is then converted to ascii form and published to the screen rx232lsr function => is an interrupt sub-routine that is triggered whenever a character is entered. It simply reads the value in the receive register. Therefore it input are just the entered character. calculations function => calculates the gradient and offset at each interval of weights. Its inputs are the voltage values corresponding the weight intervals, the weight themselves as well as a counter which refers to the position in which the gradient and offset are to be stored within an array. Display_start_menu => This transmit the main menu strings to the remote terminal through the serial communication port. These strings are sent using the transmit_character and transmit_text functions Display_stats => This displays the relevant strings for the module using the transmit_text and transmit_character functions. The subroutine loops to output the raw and filtered data from the circular buffer and concludes by printing the calculated data mean and variance. The function waits for user input before terminating and returning to the main function. display_user_remote => displays the relevant strings for the weigh and count menu through use of the transmit_text and transmit_character subroutines. display_weight => displays the string used for the weigh function using the tranmit_text and transmit_character functions. Password => allows the entry of three characters from the remote terminal. A counter is incremented for every correct entry. If the counter reaches three the password is deemed

36 of 122

to be correct and a flag is then set allowing continuation into the statistics and calibration modules

A.19.1. Functional Requirements of Module Calibration


This section describes the functional requirements of Module Calibration those requirements that must be met if the module (and system) is to function correctly. A.19.1.1. Inputs The only input required by the calibration module, are the voltage readings given by the strain gauge and converted by the A/D convertor and cleaned through the filter at 200 gram intervals. There should be five readings, one with no weights on the scales, another at 200 grams, 400 grams and so on to 1000 grams. Note that before the calibration module can be used, the password needs to be entered. Thism security procedure prevents any personnel other than the technician or producer of the CCS from tampering with the calibration of the system. A.19.1.2. Process The calibration module takes the input voltage readings and from those points will generate a weight-voltage relationship for each 200 gram interval using the calculations function. A.19.1.3. Outputs Using the calculations function at each interval, CALIBRATION module will output a corresponding gradient and voltage offset which are essential parts to the weight-voltage relationship. It is this relationship that is used later to determine the weight placed on the scales. The gradient and voltage offset is then stored in array to be referred to later.

A.19.2. Non-Functional (Quality of Service) Requirements


A.19.2.1. Performance The Calibration function does not require the user or technician to enter any values via the keypad. The only input is the voltage values at each 200 gram interval. Even though the filter should be sufficient to reject noise readings such as those created by the vibrations of the strain gauge and electrical noise, to ensure most accurate results of calibration, it is recommended that the objects to be weighed are placed in scales gently without shaking the scales. Also, allow a few seconds for the scales to settle before pressing a key to indicate you have placed the requested weight on the scales. A.19.2.2. Design Constraints It would have been more user-friendly when requesting the user to place certain weights on the scales to specify the weights such as place 600 grams on scales rather than displaying add 200 grams to the scales. The reason why this was not done was because more strings would have been required and hence, more idata would have been necessary to store strings and the space available was limited and so producing the current statement needed the least amount of space.

37 of 122

A.19.3. Functional Requirements of Module Statistics


The statistics module was not fully implemented in the final version of the project due to integration difficulties. As such dummy data was placed into an array for the raw and filtered data and also for the mean and variance. This meant that these variables could be called and hence displayed but would bot be updated as the program ran. This section describes the functional requirements of Module Statistics those requirements that must be met if the module (and system) is to function correctly. A.19.3.1. Inputs The inputs to the statistics function are raw and filtered data that is stored in the circular buffer directly from the A/D convertor at regular intervals. As the analog to digital convertor converts data it outputs a binary number corresponding to the raw voltage outputted from the conversion. This data is then stored into a 50 cell circular buffer. The raw voltage also undergoes software filtering which removes noise from the signal and then this result is stored into a similar circular buffer. Keyboard inputs through hyperterminal from a remote terminal access the module and therefore publish the information upon the remote terminal screen. A.19.3.2. Process The internal processes include calculation of the mean and the variance of the filtered data which is then outputted at the conclusion of the printed raw and filtered data. These calculations are updated as a new value A/D conversion value enters the circular buffer. These statistics are calculated as follows. Mean = X/N Variance

The result of each calculation would be published only to 1 decimal place as this would reflect the limited accuracy of the filtered data. Any more accuracy from the statistics module would suggest accuracy which cannot be justified by the performance of the hardware and software in this project. A.19.3.3. Outputs Outputs that must be created for the statistics module to function correctly include the addition of new data to the circular buffer so as to allow new calculations of the mean and variance. Serial signals must also be ouputted so as to allow the relevant statistics results to be called and displayed on the remote terminal. A.19.3.4. Timing The statistics results may be called at any time as the values are constantly updated and the mean and variances continually updated as the program runs.

38 of 122

A.19.4. Non-Functional (Quality of Service) Requirements


A.19.4.1. Performance The accuracy of the statistics module is not required to be high given that the data that is operated upon is not of a high degree of accuracy itself. None the less by computing the statistics of the filtered data over the planned 50 values rather than say, 10 values, the accuracy of the data provided is improved. The data that is outputted is only be published to 1 decimal place as this reflects the limited accuracy of the device itself. The statistics module operates by calling the previously calculated values of the mean and variance and therefore the computational loop time of this particular module is low A.19.4.2. Interfaces The user interface provides the raw and filtered data to be listed and then the more crucial information of the mean and variance follows. The implemented version of the module only publishes 6 values of the raw and filtered data, however the unimplemented but planned version would have listed all 50 values of the circular buffer. The statistics data is accessed easily from the user remote menus and the data is published automatically as soon as the module is accessed after the password is passed. A.19.4.3. Design Constraints The design constraints include the accuracy of the data provided to the statistics module. This limits the accuracy of the statistics module. The limited space available on the chip also restricts the number af values that may be stored and then used in the module. Commercially the statistics function is not of a high importance as the everyday user of the device would be relatively uninterested in the ouput of this module.

A.19.5. Functional Requirements of Module User Remote


This section describes the functional requirements of Module User Remote those requirements that must be met if the module (and system) is to function correctly. A.19.5.1. Inputs User remote mode first requires the user to input what units to display the weight currently on the scales. User enters g for grams or o for ounces. In the determine weight sub-module, the determine function is called which will require the array of gradients and voltage offsets which was produced by the calibration function. It also needs an input of the current voltage on the strain gauge (current weight reading on scales). Count mode requires the user to enter the number of items currently placed on the scales. If incorrect inputs are entered, the program will inform the user the input is valid and request the user to re-enter input requested. A.19.5.2. Process In the determine weight module, the determine_fn function is used to work out which gradient and which offset is to be used in calculating the weight. Program continually runs this to update the weight displayed in real time. Count mode takes the user input of number of items and matches that with the current weight on the scales. Then by dividing the current weight with the number of items, it works out the weight of one item and when the user places different weights, the count mode will determine the number of items currently on the scales. The program also runs this constantly to update the count number.

39 of 122

A.19.5.3. Outputs The determine weight function outputs the weight in grams. After the user has specified whether to display in grams or ounces, User remote module will display the weight in the desired units using either the show_weight_grams function or the show_weight_ounces function. Both these functions use transmit_text and transmit_character to display the weight. Count mode module displays the number of items currently on the scales using transmit_text and transmit_character functions.

A.19.6. Non-Functional (Quality of Service) Requirements


A.19.6.1. Performance To ensure most accurate results are produced, objects into scales as gently as possible. Also allow time for the scales to settle. The filter should be able to reject any noise produced by the vibrations on the strain gauge and/or produced by electrical means but it is recommended to follow the above instructions. A.19.6.2. Interfaces To produce required results quickly, it is best to follow instructions requested in any mode including user remote mode. Error messages will be displayed in the event of incorrect data formats are entered. However, if correct data formats are entered, the program will not know what as been entered is correct. The program assumes when the correct format is entered, the data is precise. For example, in count mode. Count mode will assume the number of items currently on the scales are the number of items specified by the user, so it is highly advised that entered data are double checked.

40 of 122

A.20.

Conceptual Design

This section gives the necessary details on how each module works and why they were designed that way they have. FACTORY MODE Figure F2.5 is a flowchart of factory mode showing how the algorithm works.

BEGIN

Display_start_menu

User selects mode = choice

CASE : choice

1 passwor d No Is passwor d correct? Yes Calibration

2 passwor d

3 User Remote mode

Default Display error message

Is passwor d correct? Yes show_stats

No

Fig F2.5: Flowchart of factory mode.

41 of 122

A.20.1. Calibration Module


The Calibration module or Display_calibrate works by the following steps: 1. The module first asks the user to remove all weights on the scales. Once the user is satisfied, the module requests the user to press any key to indicate this. This continues with requests of 200 gram increments to 1000 grams. Note that the receive interrupt is disabled and poles in the program since the program is not required to do anything else while the user is calibrating. 2. Calibration module takes these readings and stores them all into an array called voltage_array. 3. Calibration then calls the calculation function a number to calculate the gradient and offset for each interval of weights and stores them into two separate arrays. The way calculations function computes the gradient is by a simple rise over run formula. That is, it takes two points of the graph of the weight-voltage relationship and takes the ratio of the difference in weight over the difference in voltage. Note that the gradient has been multiplied by 256 to maintain higher resolution in any decimal places. The reason for multiplying by 256 was to keep the code as efficient as possible. C performs multiplication and division faster via binary numbers.

gradient =

weight 2 weight1 voltage2 voltage1

This equation can only be applied when the relationship is linear. After several tests, it was found an almost linear relationship existed as shown in Figure F3.

42 of 122

3500 3000 2500 2000 1500 1000 500 0 0

y = 3.0514x + 6.087

500

1000

1500

Fig F3: Plot of Weight vs Voltage The voltage offset is the difference between the weight=0 voltage point to the zero voltage point as shown in Figure F4. The gradient and voltage offset could have been taken to be the single values found in the testing shown in Figure F3. However, the line fitted in Figure F3 is not completely a straight line and so to obtain higher accuracy, the gradient and voltage offset is calculated in 200 gram intervals. Hence, the user is asked to place weights at 200 gram intervals. Figure F4 illustrates how the gradient and offset can be different. Ofcourse, smaller intervals would lead to higher accuracy but any smaller intervals would cause further unnecessary calibration that would lead to only slight increases in accuracy.

43 of 122

The voltage offset is determined using the following method derived from a straight line graph equation, point gradient formula. Letting m be the gradient:

weight weight1 = m(voltage voltage1) weight weight1 = mvoltage mvoltage1


Since we are trying to find the point where the voltage reading give zero weight, we set weight to zero.

weight1 = mvoltage mvoltage1 mvoltage = mvoltage1 weight1 voltage = voltage1 weight1/ m


Note that the gradient was divided by 256 to avoid errors in calculating offset as a result of attempting to increase the accuracy of results.

A.20.1.1. Assumptions made - Looking at Figure F3, we can see the graph is not linear. However, we have assumed it is linear and use linear methods to calculate gradient and offset values. This is compensated by calibrating different weight-voltage functions at every 200 gram intervals. It is assumed that the user places the requested weights during calibration. There is no way for the system to know whether the user has placed the correct weight or not.

44 of 122

A.20.1.2. Constraints on Module Calibration Performance - It is possible inaccurate calibration can happen if the user does not place the weight gently on the scales and wait for vibrations to stop before pressing any key. The filer should be able to separate out the noise from the actual signal.

Figure F5 is a Flowchart below shows how the calibrate module algorithm.

45 of 122

BEGIN

Set counter to zero

User removes all weights

Store voltage value in voltage_array(counter)

counter++

Is calibrati on done? No User 200 grams to scales

Yes

Set counter to zero

Yes Display Calibration Successful

Have all gradients and offsets been calculated ? No Calculations

END

counter++

Fig F5: Flowchart of Calibrate module

46 of 122

A.20.2. Statistics Module


Figure F6 is a Flowchart below shows the statistics module algorithm. BEGIN

Enter Statistics Mode

Display Headings Raw & Filtered

Publish Counter value of raw & filtered data

Counter = 50? No Yes Display mean and variance data

counter++

User Input? No Yes Exit Statistics

END

Fig F6: Flowchart of show_stats module

The statisctics module is accessed though the factory remote mode of the device. The module is password protected as this part of the function of the device should not be able to be

47 of 122

accessed by the casual user. The module was designed so as to simply print all necessary data as soon as it was called. The statistics mode outputs a variety of data (1) Raw Data This data is the raw voltage values outputted from the A/D convertor to be stored in a circular buffer. The statistics mode lists each piece of data stored in the circular buffer which consists of 50 values. (2) Filtered Data This data is the filtered version of the raw data. The software filtering attempts to remove noise that will be present in the raw voltages. The filtered data is similarly stored in a circular buffer which is updated with each A/D conversion. (3) Mean As each new value is submitted to the circular buffer the mean of the values is recalculated. This means that the mean value can be simply called at any time. (4) Variance Similarly the variance of the circular buffer values is calculated as each new value enters the circular buffer and can be called at any time. The statistics module increases a counter as each raw and filtered value is extracted from the circular buffer and printed through the serial communications to the remote terminal. Upon printing the last value the counter limit is reached and this signals that the program may proceed to printing the mean and variance values. This is simply achieved by using the values stored in these variables which are global. The numerical functions used to calculate the statistics are as follows Mean = X/N Variance

A.20.2.1. Assumptions made We assume that 50 values are enough to provide a reasonable degree of accuracy in the calculation of the mean value for the module. A.20.2.2. Constraints on Module Statistics Performance Constraints on the module include the limited amount of space on the chip so as to restrict the amount of raw and filtered data that may be stored and hence operated on by the statistics module

A.20.3. User Remote Module


User remote mode consists of two sub-modules. By default, User remote is on Determine weight module. Determine weight calculates currently on the scales by calling a few functions. 1. Determine weight first calls the determine_fn function. determine_fn return the index location of the gradient and offset required to calculate the weight. Its does this by finding which intervals the current voltage reading lies and returns that position. determine_function also returns a flag called zero_weight indicating if the voltage is less or equal to the zero weight voltage value. If so, Determine weight module will simply display the weight as zero. 2. Once the gradient and offset have been determined, determine weight calls calc_weight to calculate the weight. calc_weight does this by first subtracting the voltage reading with the voltage offset (moving the line of fit to zero voltage = zero weight). Then it multiplies the new voltage with the gradient to give the weight. Note that the weight is divided by 256 to avoid errors from maintaining higher resolution in the gradient calculation but achieve more accurate results.

48 of 122

User Remote then asks the user if they wish to display the weight in grams or ounces. If the user selects grams, User remote will call the show_weight_grams function which will display the weight as it is. If the user selects ounces, User remote will call the show_weight_ounces function which converts the weight value from grams to ounces by dividing the weight by 28.35. This is because 1 ounce = 28.35 grams. It then displays the weight in ounces. Note that for this part of the program, receive interrupts are disabled as the program is not required to run any other part of the modules. If the user enters an invalid choice, nothing will happen. Program continues to wait for a valid entry. User remote constantly loops, always updating the displayed weight until the user enters a valid command. The 2nd module part of User remote is Count mode. Only when the user requests this mode will the program display Count mode. Count mode essentially counts the number of items placed on the scales based on information given by the user. Once in Count mode, the program follows these steps: 1. Receive interrupts are disabled since the program does not need to perform other operations while waiting for the user the user input. The user is asked to enter the number of items currently on the scales. They can go back if they wish by pressing b. 2. Once entered, interrupts are enabled to allow the user to press b at any time to o back to the Determine weight module. 3. Count mode calls the determine weight module to measure the current weight. Count mode stores this as the weight of the number of items entered by the user. 4. Count mode than calculates the weight of one item by dividing the weight with the number of items. Notice the weight of one item is multiplied by 256 to obtain higher accuracy as mentioned before. 5. The current weight in the scales is determined using determine weight mode. 6. This weight is then divided by the weight of one item giving the number of items currently on the scales. 7. Count mode continues to update the count number until the user enters a valid command.

A.20.3.1. Assumptions made - User enters correct count number. A.20.3.2. Constraints on Module User Remote Performance - The number of items calculated has limited accuracy since the count number is declared as an integer and so any decimal places with the calculated values are cut off rather than rounded. This is however improved by multiplying the weight of one item by 256 to keep further decimal places but needs to be divided later on. The above also applies to the calculate weight calculations. Figure F7 is a flowchart of the User remote algorithm and Figure F8 is the flowchart for count mode.

49 of 122

BEGIN

Initialise

display_user_remote

Determine_weight

User enters grams or ounces

grams

Grams or ounces?

ounces

show_weight_gram s

show_weight_ounce s

Count mode ?

Yes

Count_mode No

Return to main? Yes END

No

Fig F7: Flowchart of User Remote mode

50 of 122

B. User Interface Design


The user interface is designed with the rules of usability in mind. Examples of these include simple instructions, allowing for ease of navigations, and grouping of similar instructions/buttons together.

B.1. Classes of User


Users are divided base on the amount of knowledge required to operate the scale. For using in user local mode, users are only required to know how to read user manual and which button activates which function. A visually impaired user will rely heavily on the Text To Speech interface which tells them the current display and state of the scale. They will also rely on the feel of different buttons for different function. User remote mode users should not be visually impaired, as this mode requires input and output to be chosen and displayed via the HyperTerminal program. These users should have some computer knowledge such as how to set up HyperTerminal. The user manual is also required for these users as there are detailed instructions about the operations of the CCS. The Factory mode only can be access by authorised persons with passwords. These are most likely technicians who are aiming to repair or modify to scale. They will have substantial amount of knowledge on the technical aspects of the CCS..

B.2. Interface Design


B.2.1. User Inputs and Outputs

Customer can use this mode by inserting a 9V battery into the scale and turning it on. Inputs to the scale includes the weights on the scale and the keys entered. The default mode for the scale is weighting mode, once the scale is on and item been placed onto the bowl, the total weight will display on the LCD. Pressing the option select key can change the state the scale from weighing to counting the number of items, the speaker will output the result. The speaker can be turned off by pressing the mute key. The tare key will set the displayed back to zero and the Gram and Ounce switch is use to change the weighing units.

B.2.2.

Input Validation and Error Trapping

The System can accept data from the User in two ways. In the Remote Setting, data is entered via a numeric keypad and a button array. In the Local Factory Setting, the User inputs data via a standard computer keyboard. B.2.2.1. User Local Mode: Data Entry Validation and Error Trapping

Data is entered via the keypad to setup the count mode. To do this, a number between 0 and 99 can be entered. For two digit numbers, the user can enter the value as it is written on paper. However, for digits between 0 and 10, the user is required to place a zero in front of the single digit. If the user does not enter any value, the default setting is 01. The user may enter a number as many times as required. For example: Press 0, 1 Press 0 1 4 Press 0 1 4 7 Press 0 1 4 7 3 achieves achieves achieves achieves 01 41 47 37

51 of 122

3.2.2.2

Factory User Data Input Error Checking

Each menu handled error checking in similar fashions. The main menu consisted of three options: calibrate show statistics user remote

To choose one of these options, the user must select 1, 2 or 3. If this was not done, an error message would be displayed saying Invalid option, try again. And the options would be displayed again. This is done using a case statelement, checking if 1, 2, or 3 was entered otherwise by default the error message would be displayed. In calibrate mode, the user needs to enter a password to calibrate the scales. If an incorrect password is not entered, the program will tell the user the password is incorrect and they can not access this mode. The program then returns to the main menu. It does this by comparing what has been entered to the expected value. Once in calibration mode, the user does not need to enter anything via the keyboard other than pressing any key when they have placed the requested weight on the scales. Hecnce, error checking is not required. In show statistics, the user only needs to enter the correct password to access this module. The program checks this the same way as is done in calibration mode. Once the password is entered and entrance is granted, the statistics are displayed and the user can press any key to return to the main menu and so no error checking is necessary here. In user remote mode, no password is required. It does however, ask if the weight wants to be displayed in grams of ounces and the user does so by entering g or o. If the user enters an invalid options, nothing will happen. The program will continue to wait for a valid option to be entered. It does this again by comparing what is expected to be the input. The user can chose count mode from here by pressing c. The program continually checks for this after g or o has been entered. Once in count mode, the user is asked to enter the number of items on scales. If the user does not enter a number, the program will display an error message and ask the user to try again. This is done by checking each character the user enters, ensuring they lie between in hex values, 30 and 39 since between these values represent a digit between 0 and 9. Also, since count can only allow a 3 digit number to be entered, the program checks to see if 3 number have been entered. If so, the program will immediately display the number of items on the scale preventing the user from entering higher numbers. It checks this through the user of a counter, incrementing each time a number has been entered "When calculating the weight, the determine weight function uses error checking procedures on the weight voltage measured by the strain gauge. If the voltage measured happens to be less or equal to the voltage corresponding to zero weight, the program will interpret this as no weight on the scales and so will display zero in user remote mode. Also, when the voltage reading exceeds the voltage corresponding to 1000 grams, the last components of the weightfunction relationship are used, that is the gradient and voltage offset for the interval between 800 and 1000 grams.

52 of 122

C. Hardware Design
There are two types of hardware that is used within this system: Manufactured Hardware; Designed Hardware;

The Manufactured hardware comprises of the various pieces of hardware that were implemented as black box systems. The hardware was obtained and then implemented according to the manufacturers instructions and interfacing requirements. These modules include: LCD Required a minimum of seven pins to interface to the MCU. An additional 0V, 5V and 0.6V lines were required to power and display the device. The 0.6V was achieved by using a simple voltage divider between a 5V potential using a 10K and a 1.2K resistor (1% tolerance). Text to Speech Required an SPI interface between the MCU and itself. The datasheet for this hardware indicates that the RESET pin should be attached to a pin that could be set or cleared. Good operation and functionality was achieved only when this RESET pin was grounded. Apart from this, a speaker (4 ohm, 0.2W) was attached to the differential output on the board to hear the text readout. The CODEC and AUX pins were not used. The power from the board is very small and so appropriate amplification is required. This could be achieved using a 9V battery powered pre amplifier. However, to minimise cost and save time, the speaker was placed in a simple plastic cup, which behaved as a speaker cone. The sound was amplified adequately to be audible in a relatively silent room. Strain Gauge Pre Designed strain gauge attached to a Cantilever Load beam to yield a voltage between 0 and 3.3 3.7 V to map the deflection of the beam as a voltage. The device requires a 5V potential to operate. The output analog signal is relative to a ground pin. Any interface therefore demands that the ground pin is connected to the same ground as that of the device to which the output pin is connected. Microcontroller See Section 4.2.2. The 5V-regulated output is multiplexed to power the interfaced devices. The serial port is used to interface to a standard Desktop computer. The transmitted data is displayed using the Microsoft Windows HyperTerminal Software over a USART serial interface at 9600 baud. Details of the Designed Hardware are described in the next section. Samsung KS0066U LCD driver on an ALTRONICS board; Winbond WTS701 Text to Speech Module; Strain Gauge Microchip PIC18F452 Microcontroller on the PIC MNML board.

53 of 122

C.1. Scope of the CCS System Hardware


The scope of hardware design includes the design of; power switching and distribution, user input via keypad, serial connection sensing and the provision for signal connections between pre-made hardware modules. Whilst discussion regarding the design of the Text To Speech, LCD, MML18 and differential amplifier module are not within the scope of this document, the methods by which these were integrated into a coherent system is. Software based integration and usage processes are detailed elsewhere, within the relevant module documentation.

C.2. Hardware Design


C.2.1. Power Supply

Power is sourced from a 9v battery and alternatively through a DC power jack. The jack is of a switching type which effectively switches the battery out of the circuit when connected. Incoming power is switched through the power switching module after which it passes to the power input of the MML18. Power is regulated by the ZSR-500 low dropout 5v regulator on the MML18 board. Regulated 5v power is sourced from the auxiliary connections on the MML18 board and is distributed to other hardware sections via the power distribution board. Without a heat sink the ZSR-500 is capable of providing 200 mA continuously.

C.2.2.

Computer Design

The scales are based around a Microchip PIC18F452 MCU supported on a MNML-PIC-18 carrier board. This board provides access to the 452s ports via header pins and contains all necessary hardware for MCU operational support. Further details of the MNML-PIC-18 board are provided via the design notes supplied with the board; to be found in the hardware appendix. The MCU ports are utilised as follows: PORTA PORTB PB0 PB1 PB2 PB3 PB4 Timer Period Update Keypad data available interrupt Keypad data LSB Keypad data Keypad data PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 Analogue data from differential amplifier unimplemented Reserved for later implementation of VrefReserved for later implementation of Vref+ unimplemented unimplemented unimplemented unimplemented

54 of 122

PORTC PORTD PORTE

PB5 PB6 PB7

Keypad data MSB Debugger Debugger

PC0 PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8

unimplemented SPI TTS SS LATCH SPI TTS R/B SPI CLK SPI SDO SPI SDI unimplemented unimplemented unimplemented

PD0 PD1 PD2 PD3 PD4 PD5 PD6 PD7 PD8

LCD DATABUS LCD DATABUS LCD DATABUS LCD DATABUS unimplemented LCD CONTROL LCD CONTROL LCD CONTROL LCD GROUND

PB0 PE1 PE2 PE3

unimplemented unimplemented unimplemented unimplemented

Following advice received during the project walkthrough with ACFR staff it was decided to avoid having high speed data moving through the simulated digital pins available on Port A to reduce the introduction of noise in the AD conversion on PA 0. Time permitting there was intention to implement a 3.5v positive reference into PA3 to increase the resolution of the conversion of the differential amplifiers output, which has maximum amplitude of 3.2v. This was to be achieved using an LM324 variable voltage source following difficulties obtaining a packaged voltage reference. Further details are included in the hardware appendix.

55 of 122

C.2.3.

Sensor Hardware

Serial port activity is monitored through connection to the RTS/CTS line loop in the port connection. In order to sample this line a set of intermediate plugs were used to allow probing of this line without direct connection to the serial port on the MNML18 board. Depending on the serial handshaking system in place the RTS line may stay high throughout the serial session or pulse high every byte transaction. A 30 second hysterisis period is implemented to cater for both these situations, allowing one pulse every 30 seconds to keep the serial sense input to the microcontroller to remain high. A 30 second timer based around an NE555 timer IC configured as a monostable timer for which the timing capacitor can be drained to prevent the 2/3 voltage cut-off level being reached. This system was tested and found to function appropriately.

Although final implementation was not achieved, an anti-aliasing active analogue filter was designed for use between the output of the differential amplifier and the AD converter. The filter was designed with a 40 Hz corner frequency and unity gain, based around a 741 Op-amp. The possibility of increasing gain to 1.56 to improve AD conversion resolution was also explored. Shielded cables were made to reduce noise in the links between amp and filter and filter and AD.

56 of 122

C.2.4.

Operator Input Hardware

Operator input is via 9 numerical digits from a tactile keypad and an additional 5 tactile switches. The additional switches are wired so as to emulate the A B C D & # keys on an alphanumeric keypad. All are multiplexed into a 4 bit data bus via the Fairchild MM74922 key decoder chip. Prior to the decision to use the 74922 several options for de-bouncing the switches were considered; including the use of a capacitive/resistive array, flip-flops and a key-scan mechanism using the microcontroller. The availability of low bounce conductive rubber switches as well as dedicated de-bounce ICs; such as those manufactured by Maxim, was also explored.

57 of 122

Choice upon the 74922 was made to reduce construction time, complexity and room for intermittent hardware errors. The 74922 requires minimal support hardware, provides switch rail pull up resistors and has low quiescent power draw. The 74922 output is via an internal tri-state buffer which requires driving the OE pin low to present data on the bus; this is achieved by inverting the data available pin DA through a 7404 hex inverter IC. A 74LS04 hex inverter was used to drive TTL logic levels from the tri-state CMOS level outputs of the 74922 chip. Inversion of the signal occurred as a result but was easily reversed in software. A non-inverting buffer would have removed the need for this; however the 7404 was on hand and could also provide the inversion of DA to feed OE.

C.2.5. C.2.6.

Operator Output Hardware Hardware Quality Assurance


Battery level is optimal; Circuitry is insulated from static discharge; Power shuts off after two minutes idle time; Hardware is designed to prevent any heat build up.

There are a few measures taken to assure the quality of the hardware:

C.3. Hardware Validation


Key data outputs were tested using the PicDem2 Plus boards Port D and a modified ISR to determine appropriate operation.

C.4. Hardware Calibration Procedures


The following steps are taken to calibrate the FOCUS scales in factory mode. 1. Connect the scales to the computer via serial port. 2. Press 1 to enter calibration mode. 3. A password will be requested. Enter the password.

58 of 122

4. Follow the instructions given by the program. First, remove all weights from the scale and press enter when this has been done. 5. Add weight 200 grams to the scales and press enter. 6. Continue to add 200 gram weights as instructed by the program. This will continue until 1000 grams has been placed on the scales. 7. Once calibration is complete, the program will respond to the user displaying Calibration successful. Note: It is recommended to improve accuracy of calibration that when placing weight to scales to place them gently and wait for vibrations on scales to settle before pressing enter.

C.5. Hardware Maintenance and Adjustment


There should not be many adjustments required to ensure the valid operation of this instrument. However, as per industrial regulations, weighting scales need to be calibrated every six months. For the consumer, this will require taking the scales to the factory to re calibrate the scales. However, every scale will vary day to day, and hence the TARE option is implemented. TARE the scales so that any offset error is removed. Subsequent measurements will then be in reference to this new zero point. Keep the instrument away from oscillating AC sources. These include items such as induction cook tops, electric motors, generators and also transformers. Static build-up can damage the hardware, especially the power FETs. Note that poor battery levels will lead to poor LCD resolution or no display at all. A constant voltage needs to be applied to all the peripherals within the system or else the output will be unreliable and also invalid. Check the battery voltage levels before placing them into the system. Remove the battery when the system is not in use.

59 of 122

D. Software Design
The software requirements and overview have been dealt with elsewhere in this document. The present section addresses the design and implementation of the software that forms the CCS.

D.1. Software Design Process


The Software design was based on the flowchart described in section 2.2. The various states would have separate modules, whereas the various operations that change the state would either be a main routine or a sub process within a particular module.

D.1.1.

Software Development Environment

The processor used for the scale is the PIC18F452 MNML board therefore all the coding are designed in the fashion for this processor. C language is main programming language used for the scale for easier understanding. The environment used for programming is MPLAB.

D.1.2.

Software Implementation Stages and Test Plans

The software is divided into different module first, some are written to support corresponding hardware, others are for the scale to perform certain function. Global variables are set to be the same in all individual modules to make integration in later stage easier to perform. A/D conversion, LCD component and HyperTerminal are the modules are completed first. Then keypad and Text to Speech module are written, and then finally the coding for calibration, statistics, count and weight are required. The integration will take place, first all the software for assisting the performance of hardware are required which are A/D conversion, LCD, HyperTerminal and Text to Speech. Once all these hardware are reacting in the fashion desired, coding for varies mode are implemented, and then test will be conducted for the scale under different mode conditions to test the overall accuracy of it. Each module goes through individual unit testing, where a selection of inputs and outputs are recorded and the outputs compared with expected values. Next a selection of modules are integrated and tests carried out again. When the results are satisfactory, the whole system is compiled with all the software and hardware modules and final tests are carried out.

D.2. Software Quality Assurance


The coding from everyone is required to be understandable, this ensures that all group members can understand each others code. Everyone should try keeping to one style of coding. Extensive documentation were written during the coding phrase so that the code is easier to debug later on. For technical documentations, each group member uses a different colour font to prevent confusion in later days.

D.3. Software Design Description


D.3.1.

Architecture
Samsung KS0066U LCD Driver Software; Winbond WTS701 Text to Speech Driver Software; Strain Gauge Functions; Filter Software;

The Software was to consist of certain modules. These include:

60 of 122

Statistics and Data Collection; Factory Mode and User Local Software; Main Initialise, Run Commands and Interrupt Service Routine.

The primary function was to utilise the Strain gauge to display a weight reading on the LCD screen. As an option, the user would also be able to press a button to speak the weight. The diagrams below describes the Communication between the various modules.

D.3.1.1.

Weigh Mode Architecture

The diagram below describes the interface between the software modules that yield a weight reading on the screen.

NB: The ISR is an Interrupt Service Routine and can trigger at any point throughout this process. The return position will never be in a predefined place and so the return position is denoted by an disconnected arrow. D.3.1.2. Count Mode Architecture The Architecture follows that which is illustrated in section 5.3.1.1. The only difference is that the function block that denotes the grams or ounce conversion is replaced by a Count Setup function. Here, the Weigh/Count module is called to setup the weight of one item before

61 of 122

determining the number of items in a given weight sample. executions follows that as described in the diagram. D.3.1.3.

The process following these

Factory Mode and User Remote Software Architecture

Following an interrupt setup to trigger for a physical serial port connection, the system changes into the factory mode or User Remote mode. Here, the software calls its own internal functions to perform the various tasks it contains. Further details of this module can be found in the relevant section.

D.3.2.

Software Interface

This section is detailed in the contents of Chapter 2

D.3.3.

Software Components

This section is detailed in the contents of Chapter 2

D.4. Preconditions for Software


D.4.1.

Preconditions for System Startup


All external wirings must be connected; o o User Shielded cable from scales to CCS module must be connected; Factory Serial Cable must be plugged inl

D.4.2.

Preconditions for System Shutdown

The System can be shutdown at any time. This includes pulling the power plug or disconnecting the battery. This however is not advisable, and it is recommended that the system be left alone for two minutes. After this, the system will shut down. If the system does not speak upon a restart, disconnect all power sources and leave the unit alone for five minutes. Reconnect all cables and return the power. The system will be stable once again. .

62 of 122

E. System Performance
E.1.1. Performance Testing

The system was able to iterate through the respective features of weigh and count modes. The Factory mode, although demonstrated separately was also functioning as an individual unit.

E.1.2.

State of the System as Delivered

The final state of the system as delivered on 8 June 2006 was essentially the bare pieces. The following modules were not complete: Calibrate; Text to Speech Statistics User Local and some Factory Settings; External Casings.

The LCD, T2S, Scales, and Power were integrated. However, the rest of the functions were not integrated and as a result, all the above discussed modules were not fully functional. The system was however able to measure weight and display this on the screen with up to a -10g error. The system was also able to count items placed on the tray with up to -1 item accuracy. Furthermore, these results could be visibly seen on the LCD screen, and audibly heard throughout the testing process. (The T2S failed to function on demonstration). The power circuitry all performed to design specifications, with the shutdown timer physically implemented with a potentiometer. The keypad and buttons all triggered correctly. This is because the data and interrupt pins for all the buttons were common to one line.

E.1.3.

Future Improvements
Code Logic and sequencing; T2S reliability; Audible Sound output Pre amplifier may be required; LCD error messages implemented to show the user that he has entered an invalid input; Overflow and underflow checking; Integer arithmetic to minimise program memory usage when parsing integers; Remove nested while loops; Serial functions should be interrupt driven; A prettier final enclosure; Scale tuning Calibration with the use of one weight. Code Portability; Low frequency cutoff filter remove basket pendulum oscillations; Weighing accuracy;

The following could improve:

63 of 122

Rather than declaring most variables as global variables, it would be more efficient and improve robustness by declaring variables locally wherever possible. This will also prevent error with idata overload as since strings being declared globally, will last throughout the entire run time where as defining them locally will be erased when the corresponding function is complete.

64 of 122

F. Safety Implications
Make sure all wires are properly connected to prevent an electrical short this could start a fire. Wear Insulated footwear when operating on the inside of the unit; Do not plug unit into AC power source Maximum into power unit is 12V Regulated DC supply

G. Conclusions
The fundamental aspect of this process is not the task itself but the way in which engineers communicate and cooperate as a team and contribute with dedication as an individual to get a job done. Without this, not only will the final product suffer, but friendships and impressions of people can change forever.

65 of 122

66 of 122

Appendix A: Scale Output Voltage Data


A.1. Experimental Data
Weight 0 5 10 15 20 25 30 35 40 45 50 75 100 125 150 175 200 225 250 300 350 400 450 500 550 600 650 700 Voltage 1 22.1 24.2 37.7 52.8 67.1 83.1 97.7 112 126 142 158 234 311 388 464 540 618 691 765 925 1070 1220 1370 1530 1680 1820 1970 2120 Voltage 2 22 23.9 38.1 52.5 67.4 83.1 97.3 113 127 143 159 235 312 389 Voltage 3 20.9 24.6 38.2 52.6 67.8 82.5 97.9 Voltage 4 21.1 24.8 38.6 52.7 67.5 82.9 97.4 Voltage 5 21.5 24.5 38.3 Voltage 6 21.6 24.7 38.2 Average Voltage 21.53333333 24.45 38.18333333 52.65 67.45 82.9 97.46666667 112.5 126.5 142.5 158.5 234.5 311.5 388.5 464 540 618 691.5 765 925 1070 1220 1375 1530 1685 1825 1975 2135 #ref. Floor voltage 0 2.917 16.65033333 31.117 45.917 61.367 75.93366667 90.967 104.967 120.967 136.967 212.967 289.967 366.967 442.467 518.467 596.467 669.967 743.467 903.467 1048.467 1198.467 1353.467 1508.467 1663.467 1803.467 1953.467 2113.467

97.3

97.2

692

1380 1530 1690 1830 1980 2150

1700 1840 2000 2160

1850

67 of 122

750 800 825 850 875 890 900 910 925 950 1000 1025 1050 1075

2270 2470 2550 2630 2660 2720 2740 2790 2840 2910 3040 3120 3220 3300

2300 2420 2540 2620 2670

2320 2470 2630

2830 2920 3050

2285 2445 2545 2625 2665 2720 2740 2790 2835 2915 3045 3120 3220 3300

2263.467 2423.467 2523.467 2603.467 2643.467 2698.467 2718.467 2768.467 2813.467 2893.467 3023.467 3098.467 3198.467 3278.467

68 of 122

A. Appendix B: Circuit Schematics

69 of 122

70 of 122

71 of 122

72 of 122

73 of 122

74 of 122

B. Appendix 3 Filter Performance

75 of 122

76 of 122

77 of 122

78 of 122

79 of 122

80 of 122

C. Appendix 4: Code Listings


Place code listings here, using style Code Appendix The column width will fit approximately 88 characters per column. Each file should start on a new page, or at least at the top of a new column. /********************************************************************* * * External LCD access routines * ********************************************************************* * FileName: Main.c * Dependencies: alcd.h * Processor: PIC18 * Complier: MCC18 v1.00.50 or higher * HITECH PICC-18 V8.10PL1 or higher * Company: Microchip Technology, Inc. * *This is the Main program. With disregard to normal main routine architecture, // this module has a number of submodules within it. Rather than making the ..modules independednt and private, they were all smacked into this one file. * THIS SOFTWARE IS PROVIDED IN AN AS IS CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * HiTech PICC18 Compiler Options excluding device selection: * -FAKELOCAL -G -E -C * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ganesha Thayaparan 8/8/06 Original (Rev 1.0) ********************************************************************/ #include "p18f452.h" #include "xlcd.h" void void void void void void void getDigits(void); AD_Complete(void); init_Itx(void); init_ADConv(void); HighISR(void); dispWeight(void); checkUnits(void); COUNT";

unsigned unsigned unsigned unsigned unsigned

int int int int int

tene1; tenE0; tenE1; tenE2; tenE3;

void main(void) { TRISB = 0; ADCON1=0x8E; //ADCON1 = 0x00; XLCDInit(); XLCDL2home(); XLCDPutRomString(bbb); XLCDL1home(); XLCDPutRomString(aaa); //ADCON1= 0x0E; ADCON0= 0x41; T0CON= 0xC7; // // // { init_Itx(); while(INTCON != 0xC4); { } //ADCON0bits.GO = 1; while(1) getDigits(); dispWeight(); XLCDL1home(); XLCDPutRomString(aaa); //prepare for LCD

void XLCDDelay15ms (void) { int i; for(i=0;i<10000;i++) { Nop(); } return; } void XLCDDelay4ms (void) { int i; for(i=0;i<2500;i++) { Nop(); } return; } void XLCD_Delay500ns(void) {

rom const char aaa[] = "Weight:"; rom const char bbb[] = " unsigned unsigned unsigned unsigned double grams = 0; double ounces = 0; int digData = 0; char unit_flag = 0;

81 of 122

Nop(); Nop(); Nop();

void XLCDDelay(void) { int i; for(i=0;i<1000;i++) { Nop(); } return; } void getDigits(void) { unsigned int weight; unsigned int calbr; calbr = digData - 0; if (unit_flag == 1) { ounces = ((calbr*16.34) - 31.32)/28.4; weight = 10*ounces; } else { grams = calbr*16.34 - 31.32; weight = grams; } //} tenE3 = weight/10000; tenE2 = (weight - tenE3*10000)/1000; tenE1 = (weight - tenE3*10000 - tenE2*1000)/100; tenE0 = (weight - tenE3*10000 - tenE2*1000 - tenE1*100)/10; tene1 = weight - tenE3*10000 - tenE2*1000 - tenE1*100 - tenE0*10; tenE3 = tenE3 + 48; tenE2 = tenE2 + 48; tenE1 = tenE1 + 48; tenE0 = tenE0 + 48; tene1 = tene1 + 48; return;

void init_Itx(void) { RCONbits.IPEN = 1; PIE1bits.ADIE = 1; IPR1bits.ADIP = 1; //INTCON = 0b11000000; INTCONbits.GIEH = 1; INTCONbits.GIEL = 1; IPR1bits.CCP1IP = 1; PIE1bits.CCP1IE = 1; CCPR1L = 0xe8; CCPR1H = 0x03; intervals CCP1CON = 0b00001011; T1CON = 0b10000001; } void init_ADConv(void) {} #pragma code high_vector=0x08 void interrupt(void) {

//enalbe priority on interrupts //enalbe AD conversion interrupt //enable AD itx high priority //turn on interrupts

//prescale 1:1 to trigger compare at 10ms //enable special event trigger on compare //enable timer 1, 1:1 prescale

} #pragma code

_asm GOTO HighISR _endasm INTCON = 0b11000000;

#pragma interrupt HighISR void HighISR(void) { //PORTB = 0x01; if(PIR1bits.CCP1IF == 1) { //timer interrupt PIR1bits.CCP1IF = 0; ADCON0bits.GO = 1; }

//reset flag for next capture //start AD conversion

void AD_Complete(void) { digData = ADRESH; getDigits(); XLCDPut(' '); XLCDPut(' '); XLCDPut(tenE3); XLCDPut(tenE2); XLCDPut(tenE1); XLCDPut(tenE0); XLCDL1home(); XLCDPutRomString(aaa); return;

if (PIR1bits.ADIF == 1) { //AD conversion complete interrupt PIR1bits.ADIF = 0; //reset flag for next conversion digData = ADRESH; //store digital data digData <<= 8; digData += ADRESL; }

void dispWeight(void) { XLCDPut(' '); XLCDPut(tenE3); XLCDPut(tenE2); XLCDPut(tenE1);

82 of 122

XLCDPut(tenE0); XLCDPut('.'); XLCDPut(tene1); if (unit_flag == 1) { XLCDPut('o'); XLCDPut('z'); } else { XLCDPut(' '); XLCDPut('g'); } return;

83 of 122

/********************************************************************* * * External LCD access routines * ********************************************************************* * FileName: ALCD.c * Dependencies: alcd.h * Processor: PIC18 * Complier: MCC18 v1.00.50 or higher * HITECH PICC-18 V8.10PL1 or higher * Company: Microchip Technology, Inc. * * This program initialises and calls the various commands on the LCD // whic will allow various stings to be seen on the LCD * THIS SOFTWARE IS PROVIDED IN AN AS IS CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * HiTech PICC18 Compiler Options excluding device selection: * -FAKELOCAL -G -E -C * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ganesha Thayaparan 8/6/06 Original (Rev 1.0) ********************************************************************/ #include "p18f452.h" #include "alcd.h" void alcd_init(void); void alcdCommand(unsigned char cmd); char alcdCheckBusy(void); void alcd_init(void) { //Clear Dataport and its TRIS alcd_dataportTRIS &= 0xf0; //check PORT config before clearing whole port alcd_dataport &= 0x10; //Clear Control Port and TRIS alcd_RSPinTRIS = 0; alcd_EPinTRIS = 0; alcd_RWPinTRIS = 0; alcd_RSPin = 0; alcd_EPin = 0; alcd_RWPin = 0; //Setup for 4 Bit Lower by Datasheet specification Delay15ms(); Delay15ms(); Delay15ms(); //-----NEW STEP----------//Clear Lower nibble

alcd_dataport &= 0xf0; alcd_dataport |= 0b00000010; //PORTC = 0x02; alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; alcd_dataport &= 0xf0; alcd_dataport |= 0b00000010; //PORTC = 0x02; alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; alcd_dataport &= 0xf0; alcd_dataport |= 0b00001100; //PORTC = 0x0C; alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; Delay15ms(); alcdCommand(0x0c); Delay15ms(); alcdCommand(0x01); Delay15ms(); } alcdCommand(0x06);

void alcdCommand(unsigned char cmd) { Delay(); alcd_RSPin = 0; alcd_RWPin = 0; alcd_EPin = 0; alcd_dataport &= 0xf0; //clear port alcd_dataport |= ((cmd>>4)&0x0f); alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; alcd_dataport &= 0xf0; alcd_dataport |= cmd&0x0f; alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; } return;

void alcdWrite(unsigned char data) { Delay();

84 of 122

alcd_RSPin = 1; alcd_RWPin = 0; alcd_EPin = 0; alcd_dataport &= 0xf0; //clear port alcd_dataport |= ((data>>4)&0x0f); alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; alcd_dataport &= 0xf0; alcd_dataport |= data&0x0f; alcd_EPin = 1; //clock in Delay500ns(); alcd_EPin = 0; } return;

void alcdPutString(rom char *string) { Delay15ms(); while(*string) //keep looping until the null term (end of string) is reached { //while(alcdCheckBusy()); alcdWrite(*string); string++; } } char alcdCheckBusy(void) { if (alcd_dataport&0x08) { alcd_EPin = 0; Delay500ns(); alcd_EPin = 1; Delay500ns(); alcd_EPin = 0; Delay500ns(); alcd_dataportTRIS = 0x00; //set for input return 1; } else { alcd_EPin = 0; Delay500ns(); alcd_EPin = 1; Delay500ns(); alcd_EPin = 0; Delay500ns(); alcd_dataportTRIS = 0x00; //set for input return 0; } }

85 of 122

/********************************************************************* * * External LCD access routines * ********************************************************************* * FileName: XLCD.c * Dependencies: xlcd.h * Processor: PIC18 * Complier: MCC18 v1.00.50 or higher * HITECH PICC-18 V8.10PL1 or higher * Company: Microchip Technology, Inc. * * This module intialises and calls the various functions of the winbond * text to speech module. What seems to be missing here is the simple stop * command which enables the buffer to empty before sending another string. * Instead, various delays have been put in and the T2S module is given real * time to empty its buffer contents. * THIS SOFTWARE IS PROVIDED IN AN AS IS CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * HiTech PICC18 Compiler Options excluding device selection: * -FAKELOCAL -G -E -C * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ganesha Thayaparan 8/6/06 Original () ********************************************************************/ #include "p18f452.h" #include "alcd.h"

SSPSTATbits.CKE = 1; SS = 1; RESET = 0; t2sDelay(); //t2s init SS = 0; loadBuff(0x14); loadBuff(0x00); SS = 1; t2sDelay(); SS = 0; loadBuff(0x02); loadBuff(0x00); SS = 1; t2sDelay(); SS = 0; loadBuff(0x4e); loadBuff(0x00); SS = 1; t2sDelay(); SS = 0; loadBuff(0x4f); loadBuff(0x01); SS = 1; t2sDelay(); SS = 0; loadBuff(0x50); loadBuff(0x43); ohm speaker SS = 1; t2sDelay(); SS = 0; loadBuff(0x51); loadBuff(0x03); SS = 1; t2sDelay(); SS = 0; loadBuff(0x52); loadBuff(0x02); SS = 1; t2sDelay(); SS = 0; loadBuff(0x77); loadBuff(0x05); SS = 1; } void loadBuff(unsigned char byte) { while(RB==0); SSPBUF = byte; while(!SSPSTATbits.BF); rxData = SSPBUF; //return rxData;

// data transmitted on falling edge of SCK */

//start tx

//clock command //set clock speed

//start tx //power up command //power up

//start tx //setup for itx //no itx

//start tx //CODEC control //ignore - disconnected //start tx //set analog audio //power up buffer and drifer, use 8

void void void void

t2sInit(void); loadBuff(unsigned char byte); t2sDelay(void); t2sSaySomething(unsigned char *string);

//start tx //set volume //0dB volume //start tx //speech rate command //set default speed //start tx //pitch command //set pitch to default

unsigned char rxData; void t2sInit(void) { char return1,return2; //TRISCbits.TRISC5 = 0; TRISCbits.TRISC1 = 0; TRISCbits.TRISC2 = 1; //PIC initialisation TRISCbits.TRISC5 = 0; TRISCbits.TRISC3 = 0; TRISCbits.TRISC4 = 1; //SSPCON1bits.SSPEN = 1; SSPCON1bits.CKP = 1; SSPCON1bits.SSPEN = 1; SSPSTATbits.SMP = 1; //clear SDO //clear SCK //idle on cke high, enable SSP ports // input data sampled at end of data output time */

//wait for busy flag to set

86 of 122

} void t2sDelay(void) { int i = 0; for(i=0;i<100;i++) { Nop(); } return; } void t2sSaySomething(unsigned char *string) { t2sDelay(); SS = 0; loadBuff(0x81); loadBuff(0x00); while(*string) //keep looping until the null term (end of string) is reached { //while(alcdCheckBusy()); loadBuff(*string); string++; } loadBuff(0x1A); SS = 1; t2sDelay(); } void readWeight(unsigned int weight) // simple parsing alogrithm that will extract the digits // out of the argument 'weight' { unsigned int tenE0,tenE1,tenE2,tenE3; tenE3 = weight/1000; tenE2 = (weight%1000)/100; tenE1 = (weight%100)/10; tenE0 = (weight%10); tenE3 tenE2 tenE1 tenE0 += += += += 48; 48; 48; 48; }

loadBuff(tenE1); } loadBuff(tenE0); loadBuff(' '); loadBuff('g'); loadBuff('r'); loadBuff('a'); loadBuff('m'); loadBuff('s'); loadBuff(0x1A); SS = 1;

void readWeight2(unsigned int weight) //make sure the ounce value is multiplied by ten before it is passed to this method { unsigned int tene1,tenE0,tenE1,tenE2,tenE3; tenE3 = tenE2 = tenE1 = tenE0 = //tene1 weight/1000; (weight - tenE3*1000)/100; (weight - tenE3*1000 - tenE2*100)/10; (weight - tenE3*1000 - tenE2*100 - tenE1*10); = weight - tenE3*10000 - tenE2*1000 - tenE1*100 - tenE0*10;

tenE3 += 48; tenE2 += 48; tenE1 += 48; SS = 0; loadBuff(0x81); loadBuff(0x00); if (tenE3 != 0x30) { loadBuff(tenE3); } if (tenE2 != 0x30) { loadBuff(tenE2); } loadBuff(' '); loadBuff('p'); loadBuff('o'); loadBuff('i'); loadBuff('n'); loadBuff('t'); loadBuff(' '); loadBuff(tenE1); loadBuff(' '); loadBuff('o'); loadBuff('u'); loadBuff('n'); loadBuff('c'); loadBuff('e'); loadBuff('s'); loadBuff(0x1A); SS = 1; while(!RB);

SS = 0; loadBuff(0x81); loadBuff(0x00); if(tenE3 != 0x30) { loadBuff(tenE3); } if(tenE2 != 0x30) { loadBuff(tenE2); } if(tenE1 != 0x30)

87 of 122

} void readWeight3(unsigned int weight) { unsigned int tenE0,tenE1,tenE2,tenE3; tenE3 = weight/1000; tenE2 = (weight%1000)/100; tenE1 = (weight%100)/10; tenE0 = (weight%10); tenE3 tenE2 tenE1 tenE0 += += += += 48; 48; 48; 48;

SS = 0; loadBuff(0x81); loadBuff(0x00); loadBuff(tenE3); loadBuff(tenE2); loadBuff(tenE1); loadBuff(tenE0); loadBuff(' '); loadBuff('i'); loadBuff('t'); loadBuff('e'); loadBuff('m'); loadBuff('s'); loadBuff(0x1A); SS = 1; }

88 of 122

#include "p18f452.h" #define alcd_dataport #define alcd_dataportTRIS #define alcd_EPin #define alcd_EPinTRIS #define alcd_RWPin #define alcd_RWPinTRIS #define alcd_RSPin #define alcd_RSPinTRIS #define SS #define RESET #define RB #define SDO #define SDI #define SCK void void void void void void void PORTCbits.RC1 PORTDbits.RD4 PORTCbits.RC2 PORTCbits.RC5 PORTCbits.RC4 PORTCbits.RC3 TRISD PORTD PORTDbits.RD7 TRISDbits.TRISD7 PORTDbits.RD6 TRISDbits.TRISD6 PORTDbits.RD5 TRISDbits.TRISD5

void determine_weight(void); void start_program(void);

alcd_init(void); Delay(void); Delay15ms (void); Delay4ms (void); Delay500ns(void); alcdPutString(rom char *string); alcdWrite(unsigned char data);

void runButton(void); void alcdCommand(unsigned char cmd); void t2sInit(void); void t2sSaySomething(unsigned char *string); #define #define #define #define alcdL1home() alcdCommand(0x80) alcdL2home() alcdCommand(0xc0) alcdClear() alcdCommand(0x01) alcdReturnHome() alcdCommand(0x02)

void readWeight(unsigned int weight); void readWeight2(unsigned int ounces); void readWeight3(unsigned int weight); extern unsigned int digData; extern unsigned int weight; extern char selection; extern char read; //unsigned int grad_array[5]; //unsigned int offset_array[5]; int getArray(unsigned char position, unsigned char select);

89 of 122

/****************************************************************************** MODULE Finite Element Response Software Filter FILE FilterCXXXXXX.c ddmmyy

/****************************************************************************** F O R W A R D D E C L A R A T I O N *******************************************************************************/ unsigned short int filter(void); /****************************************************************************** E N T R Y R O U T I N E D E F I N I T I O N Entry routines is the start of the filter function and exit returns int data type fil_data to the calling function. *******************************************************************************/ #pragma code unsigned short int filter(void) { char i,j; unsigned short long sum; /* 24 bits C18 type */ j = data_index - FIR_WEIGHTS; if(j < 0) {j = j + MAX_DATA_SAMPLES;} sum = 0; for(i=0; i<FIR_WEIGHTS; i++) { sum = sum + (weights[i] * AD_data_buffer[j]); j = j + 1; if(j >= MAX_DATA_SAMPLES) {j = 0;} } sum=(sum>>10); /*Right shift 10 places equiv. to /512 */ filter_data[data_index]= (unsigned short int) sum; return filter_data[data_index]; } /* filter() */

ENTRY (PUBLIC) ROUTINE - May be called from outside this module int filter(void) INITIALISATION ROUTINES Implementation of the store_data.h to enumerate buffers and constants and arrays. DESCRIPTION 21 tap FIR Filter with; -corner frequency -stopband att -passband att -passband ripple LAST UPDATE 1 June 2006 5Hz -60 dB 1dB 1 dB

by Tycho

*******************************************************************************/

/****************************************************************************** I M P O R T S *******************************************************************************/ #include <stdlib.h> #include "store_data.h" /* standard C header file */ /* public definitions required for filter.c */

/* Relevant constants as defined in store_data.h */ /* #define BUFFER_SIZE 100 #define FIR_WEIGHTS 21 #define MAX_DATA_SAMPLES 90 */ /****************************************************************************** P R I V A T E D A T A D E F I N E D T Y P E S A N D M O D U L E V A R I A B L E S *******************************************************************************/ #pragma romdata static char weights[FIR_WEIGHTS]={0, 1, 2, 6, 12, 21, 31, 42, 52, 59, 61, 59, 52, 42, 31, 21, 12, 6, 2, 1, 0}; /* Weights are multiplied by 512 to integerise for calcs. */

/************************************************************************************* ENTRY OF DATA Attn; John Insertion routine...... /* data_buffer[data_index]=dig_data if(data_index >= MAX_DATA_SAMPLES) data_index = 0;

*/ /*************************************************************************************/

90 of 122

/****************************************************************************** MODULE High ISR FILE HighISR.c ENTRY (PUBLIC) ROUTINE main - the C main() function provides compile time test functionality INITIALISATION ROUTINES Must run Setup routine prior to enabling interrupts. Interrupt must first be enabled before ISR function. Must include store_data header file containing global data refeenced. DESCRIPTION This module is the high ISR for use in the scales. Initially designed to test button press functionality it is then incrementally updated to reflect growing program complexity. LAST UPDATE 29 May 2006 added flags press_flag. Tycho *******************************************************************************/ /****************************************************************************** P R I V A T E D A T A N A M E D C O N S T A N T S A N D M A C R O S *******************************************************************************/ #if !defined (MAX_DATA_SAMPLES) # define MAX_DATA_SAMPLES 90 # endif /****************************************************************************** I M P O R T S *******************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <p18f452.h> //#include "store_data.h" /****************************************************************************** P R I V A T E D A T A D E F I N E D T Y P E S A N D M O D U L E V A R I A B L E S *******************************************************************************/ /* extern unsigned char button=0;.................. */ unsigned char button=0; unsigned int digData=0; /* standard C header file */

unsigned unsigned unsigned unsigned

char button_press_flag=0; char tare_flag=0; char mute_flag=0; short int tare=0;

extern unsigned short int filter_data[MAX_DATA_SAMPLES]; extern signed char data_index; /* points to most recently received data sample */ /****************************************************************************** F O R W A R D D E C L A R A T I O N S *******************************************************************************/ void high_isr (void); void SetupInterrupts (void); /****************************************************************************** E N T R Y R O U T I N E D E F I N I T I O N *******************************************************************************/ #pragma code void main(void) { SetupInterrupts(); registers */ while (1); } /* testing functionality */ /* Setup Interrupts initialises appropriate

/****************************************************************************** HIGH INTERRUPT SERVICE ROUTINE *******************************************************************************/ #pragma code high_vector=0x08 void interrupt_at_high_vector (void) { _asm GOTO high_isr _endasm } #pragma code #pragma interrupt high_isr void high_isr (void) { INTCONbits.GIE=0; if (INTCON3bits.INT1IF=1) button */ /* Disable all interrupts */ /* Interrupt caused by button press, capture /*

character to "button" and return, re-enablng interrupts. */ { /* TESTING FOR EVB */ //button=~PORTD; //button= (button&(0b00001111)); //Nop(); /* END TEST CODE */

91 of 122

/* MML18 CODE */ button=~PORTB; button= (button&(0b00111100)); button>>=2; /* END MML18 CODE */ if (button==12) { tare_flag=1; tare=filter_data[data_index]; /* tare=digData; */ implementation. */ button_press_flag=0; } else if (button==16) { mute_flag=(~mute_flag); button_press_flag=0; } else { }

/*********************************************************************************/

/*----------------------------------------------------------------------------FUNCTION SetupInterrupts /* Pre-Filter initialises interrupt settings

SYNOPSIS void SetupInterrupts (void); PARAMETER takes none. REMARKS Contains code for both testing on PicDem 2 Plus and MML18 boards. ------------------------------------------------------------------------------*/ void SetupInterrupts (void) { INTCONbits.GIE=1; */

button_press_flag=1; /* Clear flag for RB1 */

/* Global Interrupt Enable /* External Interrupt RB1

INTCON3bits.INT1IF=0; } else if (PIR1bits.CCP1IF==1) required */ { PIR1bits.CCP1IF=0; ADCON0bits.GO=1; } else if (PIR1bits.ADIF==1) required */ { PIR1bits.ADIF=0; digData=ADRESH; digData<<=8; digData=ADRESL; } else { Nop(); } INTCONbits.GIE=1; return; }

/*For other interrupts used, copy as

INTCON2bits.INTEDG1=1; relevant */ INTCON3bits.INT1IP=1; INTCON3bits.INT1IE=1; // TRISBbits.TRISB0=0; TRISBbits.TRISB1=1; /* PicDem 2 Plus CODE TRISDbits.TRISD0=1; TRISDbits.TRISD1=1; TRISDbits.TRISD2=1; TRISDbits.TRISD3=1; END PicDem 2 Plus CODE MML18 CODE TRISBbits.TRISB2=1; TRISBbits.TRISB3=1; TRISBbits.TRISB4=1; TRISBbits.TRISB5=1; END MML18 CODE */

/*For other interrupts used, copy as

/* /*

*/ */

/* /* */ }

*/

/* Re-enable interrupts */

92 of 122

/*------------------------------------------------------------------------* $Id: p18f452.h,v 1.7 2004/10/20 22:49:39 kuhrtt Exp $ * MPLAB-Cxx PIC18F452 processor header * * (c) Copyright 1999-2004 Microchip Technology, All rights reserved *-------------------------------------------------------------------------*/ #ifndef __18F452_H #define __18F452_H extern volatile near unsigned char extern volatile near union { struct { unsigned RA0:1; unsigned RA1:1; unsigned RA2:1; unsigned RA3:1; unsigned RA4:1; unsigned RA5:1; unsigned RA6:1; }; struct { unsigned AN0:1; unsigned AN1:1; unsigned AN2:1; unsigned AN3:1; unsigned :1; unsigned AN4:1; unsigned OSC2:1; }; struct { unsigned :2; unsigned VREFM:1; unsigned VREFP:1; unsigned T0CKI:1; unsigned SS:1; unsigned CLK0:1; }; struct { unsigned :5; unsigned LVDIN:1; }; } PORTAbits; extern volatile near unsigned char extern volatile near union { struct { unsigned RB0:1; unsigned RB1:1; unsigned RB2:1; unsigned RB3:1; unsigned RB4:1; unsigned RB5:1; unsigned RB6:1; unsigned RB7:1; }; struct { unsigned INT0:1; unsigned INT1:1; unsigned INT2:1; unsigned CCP2:1; unsigned :1; PORTA;

PORTB;

unsigned PGM:1; unsigned PGC:1; unsigned PGD:1; }; } PORTBbits; extern volatile near unsigned char extern volatile near union { struct { unsigned RC0:1; unsigned RC1:1; unsigned RC2:1; unsigned RC3:1; unsigned RC4:1; unsigned RC5:1; unsigned RC6:1; unsigned RC7:1; }; struct { unsigned T1OSO:1; unsigned T1OSI:1; unsigned :1; unsigned SCK:1; unsigned SDI:1; unsigned SDO:1; unsigned TX:1; unsigned RX:1; }; struct { unsigned T1CKI:1; unsigned CCP2:1; unsigned CCP1:1; unsigned SCL:1; unsigned SDA:1; unsigned :1; unsigned CK:1; unsigned DT:1; }; } PORTCbits; extern volatile near unsigned char extern volatile near union { struct { unsigned RD0:1; unsigned RD1:1; unsigned RD2:1; unsigned RD3:1; unsigned RD4:1; unsigned RD5:1; unsigned RD6:1; unsigned RD7:1; }; struct { unsigned PSP0:1; unsigned PSP1:1; unsigned PSP2:1; unsigned PSP3:1; unsigned PSP4:1; unsigned PSP5:1; unsigned PSP6:1; unsigned PSP7:1; }; } PORTDbits;

PORTC;

PORTD;

93 of 122

extern volatile near extern volatile near struct { unsigned RE0:1; unsigned RE1:1; unsigned RE2:1; }; struct { unsigned AN5:1; unsigned AN6:1; unsigned AN7:1; }; } PORTEbits; extern volatile near extern volatile near unsigned LATA0:1; unsigned LATA1:1; unsigned LATA2:1; unsigned LATA3:1; unsigned LATA4:1; unsigned LATA5:1; unsigned LATA6:1; } LATAbits; extern volatile near extern volatile near unsigned LATB0:1; unsigned LATB1:1; unsigned LATB2:1; unsigned LATB3:1; unsigned LATB4:1; unsigned LATB5:1; unsigned LATB6:1; unsigned LATB7:1; } LATBbits; extern volatile near extern volatile near unsigned LATC0:1; unsigned LATC1:1; unsigned LATC2:1; unsigned LATC3:1; unsigned LATC4:1; unsigned LATC5:1; unsigned LATC6:1; unsigned LATC7:1; } LATCbits; extern volatile near extern volatile near unsigned LATD0:1; unsigned LATD1:1; unsigned LATD2:1; unsigned LATD3:1; unsigned LATD4:1; unsigned LATD5:1; unsigned LATD6:1; unsigned LATD7:1; } LATDbits; extern volatile near extern volatile near unsigned LATE0:1; unsigned LATE1:1; unsigned LATE2:1;

unsigned char union {

PORTE;

unsigned char struct {

LATA;

unsigned char struct {

LATB;

unsigned char struct {

LATC;

unsigned char struct {

LATD;

unsigned char struct {

LATE;

} LATEbits; extern volatile near extern volatile near unsigned RA0:1; unsigned RA1:1; unsigned RA2:1; unsigned RA3:1; unsigned RA4:1; unsigned RA5:1; unsigned RA6:1; } DDRAbits; extern volatile near extern volatile near unsigned TRISA0:1; unsigned TRISA1:1; unsigned TRISA2:1; unsigned TRISA3:1; unsigned TRISA4:1; unsigned TRISA5:1; unsigned TRISA6:1; } TRISAbits; extern volatile near extern volatile near unsigned RB0:1; unsigned RB1:1; unsigned RB2:1; unsigned RB3:1; unsigned RB4:1; unsigned RB5:1; unsigned RB6:1; unsigned RB7:1; } DDRBbits; extern volatile near extern volatile near unsigned TRISB0:1; unsigned TRISB1:1; unsigned TRISB2:1; unsigned TRISB3:1; unsigned TRISB4:1; unsigned TRISB5:1; unsigned TRISB6:1; unsigned TRISB7:1; } TRISBbits; extern volatile near extern volatile near unsigned RC0:1; unsigned RC1:1; unsigned RC2:1; unsigned RC3:1; unsigned RC4:1; unsigned RC5:1; unsigned RC6:1; unsigned RC7:1; } DDRCbits; extern volatile near extern volatile near unsigned TRISC0:1; unsigned TRISC1:1; unsigned TRISC2:1; unsigned TRISC3:1; unsigned TRISC4:1;

unsigned char struct {

DDRA;

unsigned char struct {

TRISA;

unsigned char struct {

DDRB;

unsigned char struct {

TRISB;

unsigned char struct {

DDRC;

unsigned char struct {

TRISC;

94 of 122

unsigned TRISC5:1; unsigned TRISC6:1; unsigned TRISC7:1; } TRISCbits; extern volatile near unsigned extern volatile near struct { unsigned RD0:1; unsigned RD1:1; unsigned RD2:1; unsigned RD3:1; unsigned RD4:1; unsigned RD5:1; unsigned RD6:1; unsigned RD7:1; } DDRDbits; extern volatile near unsigned extern volatile near struct { unsigned TRISD0:1; unsigned TRISD1:1; unsigned TRISD2:1; unsigned TRISD3:1; unsigned TRISD4:1; unsigned TRISD5:1; unsigned TRISD6:1; unsigned TRISD7:1; } TRISDbits; extern volatile near unsigned extern volatile near union { struct { unsigned RE0:1; unsigned RE1:1; unsigned RE2:1; }; struct { unsigned :4; unsigned PSPMODE:1; unsigned IBOV:1; unsigned OBF:1; unsigned IBF:1; }; } DDREbits; extern volatile near unsigned extern volatile near union { struct { unsigned TRISE0:1; unsigned TRISE1:1; unsigned TRISE2:1; }; struct { unsigned :4; unsigned PSPMODE:1; unsigned IBOV:1; unsigned OBF:1; unsigned IBF:1; }; } TRISEbits; extern volatile near unsigned extern volatile near struct { unsigned TMR1IE:1; unsigned TMR2IE:1; unsigned CCP1IE:1;

char

DDRD;

char

TRISD;

char

DDRE;

char

TRISE;

char

PIE1;

unsigned SSPIE:1; unsigned TXIE:1; unsigned RCIE:1; unsigned ADIE:1; unsigned PSPIE:1; } PIE1bits; extern volatile near extern volatile near unsigned TMR1IF:1; unsigned TMR2IF:1; unsigned CCP1IF:1; unsigned SSPIF:1; unsigned TXIF:1; unsigned RCIF:1; unsigned ADIF:1; unsigned PSPIF:1; } PIR1bits; extern volatile near extern volatile near unsigned TMR1IP:1; unsigned TMR2IP:1; unsigned CCP1IP:1; unsigned SSPIP:1; unsigned TXIP:1; unsigned RCIP:1; unsigned ADIP:1; unsigned PSPIP:1; } IPR1bits; extern volatile near extern volatile near unsigned CCP2IE:1; unsigned TMR3IE:1; unsigned LVDIE:1; unsigned BCLIE:1; unsigned EEIE:1; } PIE2bits; extern volatile near extern volatile near unsigned CCP2IF:1; unsigned TMR3IF:1; unsigned LVDIF:1; unsigned BCLIF:1; unsigned EEIF:1; } PIR2bits; extern volatile near extern volatile near unsigned CCP2IP:1; unsigned TMR3IP:1; unsigned LVDIP:1; unsigned BCLIP:1; unsigned EEIP:1; } IPR2bits; extern volatile near extern volatile near unsigned RD:1; unsigned WR:1; unsigned WREN:1; unsigned WRERR:1; unsigned FREE:1; unsigned :1; unsigned CFGS:1;

unsigned char struct {

PIR1;

unsigned char struct {

IPR1;

unsigned char struct {

PIE2;

unsigned char struct {

PIR2;

unsigned char struct {

IPR2;

unsigned char struct {

EECON1;

95 of 122

unsigned EEPGD:1; } EECON1bits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near struct { unsigned RX9D:1; unsigned OERR:1; unsigned FERR:1; unsigned ADDEN:1; unsigned CREN:1; unsigned SREN:1; unsigned RX9:1; unsigned SPEN:1; } RCSTAbits; extern volatile near unsigned extern volatile near struct { unsigned TX9D:1; unsigned TRMT:1; unsigned BRGH:1; unsigned :1; unsigned SYNC:1; unsigned TXEN:1; unsigned TX9:1; unsigned CSRC:1; } TXSTAbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near union { struct { unsigned TMR3ON:1; unsigned TMR3CS:1; unsigned T3SYNC:1; unsigned T3CCP1:1; unsigned T3CKPS0:1; unsigned T3CKPS1:1; unsigned T3CCP2:1; unsigned RD16:1; }; struct { unsigned :2; unsigned NOT_T3SYNC:1; }; } T3CONbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near union { struct { unsigned CCP2M0:1; unsigned CCP2M1:1; unsigned CCP2M2:1; unsigned CCP2M3:1; unsigned CCP2Y:1; unsigned CCP2X:1; }; struct { unsigned :4;

char char char char

EECON2; EEDATA; EEADR; RCSTA;

char

TXSTA;

char char char char

TXREG; RCREG; SPBRG; T3CON;

char char char

TMR3L; TMR3H; CCP2CON;

unsigned DC2B0:1; unsigned DC2B1:1; }; struct { unsigned :5; unsigned DCCPX:1; }; } CCP2CONbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near union { struct { unsigned CCP1M0:1; unsigned CCP1M1:1; unsigned CCP1M2:1; unsigned CCP1M3:1; unsigned CCP1Y:1; unsigned CCP1X:1; }; struct { unsigned :4; unsigned DC1B0:1; unsigned DC1B1:1; }; } CCP1CONbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near struct { unsigned PCFG0:1; unsigned PCFG1:1; unsigned PCFG2:1; unsigned PCFG3:1; unsigned :2; unsigned ADCS2:1; unsigned ADFM:1; } ADCON1bits; extern volatile near unsigned extern volatile near union { struct { unsigned ADON:1; unsigned :1; unsigned GO:1; unsigned CHS0:1; unsigned CHS1:1; unsigned CHS2:1; unsigned ADCS0:1; unsigned ADCS1:1; }; struct { unsigned :2; unsigned NOT_DONE:1; }; struct { unsigned :2; unsigned DONE:1; }; struct {

char char char

CCPR2; CCPR2L; CCPR2H; CCP1CON;

char char char

CCPR1; CCPR1L; CCPR1H; ADCON1;

char

ADCON0;

96 of 122

unsigned :2; unsigned GO_DONE:1; }; } ADCON0bits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near struct { unsigned SEN:1; unsigned RSEN:1; unsigned PEN:1; unsigned RCEN:1; unsigned ACKEN:1; unsigned ACKDT:1; unsigned ACKSTAT:1; unsigned GCEN:1; } SSPCON2bits; extern volatile near unsigned extern volatile near struct { unsigned SSPM0:1; unsigned SSPM1:1; unsigned SSPM2:1; unsigned SSPM3:1; unsigned CKP:1; unsigned SSPEN:1; unsigned SSPOV:1; unsigned WCOL:1; } SSPCON1bits; extern volatile near unsigned extern volatile near struct { unsigned BF:1; unsigned UA:1; unsigned R_W:1; unsigned S:1; unsigned P:1; unsigned D_A:1; unsigned CKE:1; unsigned SMP:1; } SSPSTATbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near struct { unsigned T2CKPS0:1; unsigned T2CKPS1:1; unsigned TMR2ON:1; unsigned TOUTPS0:1; unsigned TOUTPS1:1; unsigned TOUTPS2:1; unsigned TOUTPS3:1; } T2CONbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near union { struct { unsigned TMR1ON:1; unsigned TMR1CS:1; unsigned NOT_T1SYNC:1; unsigned T1OSCEN:1;

char char char

ADRES; ADRESL; ADRESH; SSPCON2;

char

SSPCON1;

char

SSPSTAT;

char char char

SSPADD; SSPBUF; T2CON;

char char char

PR2; TMR2; T1CON;

unsigned T1CKPS0:1; unsigned T1CKPS1:1; unsigned :1; unsigned RD16:1; }; struct { unsigned :2; unsigned T1SYNC:1; }; } T1CONbits; extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near union { struct { unsigned NOT_BOR:1; unsigned NOT_POR:1; unsigned NOT_PD:1; unsigned NOT_TO:1; unsigned NOT_RI:1; unsigned :1; unsigned NOT_LWRT:1; unsigned NOT_IPEN:1; }; struct { unsigned BOR:1; unsigned POR:1; unsigned PD:1; unsigned TO:1; unsigned RI:1; unsigned :1; unsigned LWRT:1; unsigned IPEN:1; }; } RCONbits; extern volatile near unsigned extern volatile near union { struct { unsigned SWDTEN:1; }; struct { unsigned SWDTE:1; }; } WDTCONbits; extern volatile near unsigned extern volatile near struct { unsigned LVDL0:1; unsigned LVDL1:1; unsigned LVDL2:1; unsigned LVDL3:1; unsigned LVDEN:1; unsigned IRVST:1; } LVDCONbits; extern volatile near unsigned extern volatile near struct { unsigned SCS:1; } OSCCONbits; extern volatile near unsigned extern volatile near struct { unsigned T0PS0:1; unsigned T0PS1:1;

char char char

TMR1L; TMR1H; RCON;

char

WDTCON;

char

LVDCON;

char

OSCCON;

char

T0CON;

97 of 122

unsigned T0PS2:1; unsigned PSA:1; unsigned T0SE:1; unsigned T0CS:1; unsigned T08BIT:1; unsigned TMR0ON:1; } T0CONbits; extern volatile near unsigned extern volatile near unsigned extern near unsigned extern near struct { unsigned C:1; unsigned DC:1; unsigned Z:1; unsigned OV:1; unsigned N:1; } STATUSbits; extern near unsigned extern near unsigned extern near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern near unsigned extern near unsigned extern near unsigned extern near unsigned extern near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern near unsigned extern near unsigned extern near unsigned extern near unsigned extern near unsigned extern near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern near unsigned extern volatile near unsigned extern volatile near union { struct { unsigned INT1F:1; unsigned INT2F:1; unsigned :1; unsigned INT1E:1; unsigned INT2E:1; unsigned :1; unsigned INT1P:1; unsigned INT2P:1; }; struct { unsigned INT1IF:1; unsigned INT2IF:1; unsigned :1; unsigned INT1IE:1;

char char char

TMR0L; TMR0H; STATUS;

char char char char char char char char char char char char char char char char char char char char char char char char char

FSR2; FSR2L; FSR2H; PLUSW2; PREINC2; POSTDEC2; POSTINC2; INDF2; BSR; FSR1; FSR1L; FSR1H; PLUSW1; PREINC1; POSTDEC1; POSTINC1; INDF1; W; WREG; FSR0; FSR0L; FSR0H; PLUSW0; PREINC0; POSTDEC0; POSTINC0; INDF0; INTCON3;

unsigned INT2IE:1; unsigned :1; unsigned INT1IP:1; unsigned INT2IP:1; }; } INTCON3bits; extern volatile near unsigned extern volatile near union { struct { unsigned RBIP:1; unsigned INT3P:1; unsigned T0IP:1; unsigned INTEDG3:1; unsigned INTEDG2:1; unsigned INTEDG1:1; unsigned INTEDG0:1; unsigned RBPU:1; }; struct { unsigned :2; unsigned TMR0IP:1; }; } INTCON2bits; extern volatile near unsigned extern volatile near union { struct { unsigned RBIF:1; unsigned INT0F:1; unsigned T0IF:1; unsigned RBIE:1; unsigned INT0E:1; unsigned T0IE:1; unsigned PEIE:1; unsigned GIE:1; }; struct { unsigned :1; unsigned INT0IF:1; unsigned TMR0IF:1; unsigned :1; unsigned INT0IE:1; unsigned TMR0IE:1; unsigned GIEL:1; unsigned GIEH:1; }; } INTCONbits; extern near unsigned extern near unsigned extern near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near unsigned extern volatile near struct { unsigned STKPTR0:1;

char

INTCON2;

char

INTCON;

PROD; char PRODL; char PRODH; char TABLAT; short long TBLPTR; char TBLPTRL; char TBLPTRH; char TBLPTRU; short long PC; char PCL; char PCLATH; char PCLATU; char STKPTR;

98 of 122

unsigned STKPTR1:1; unsigned STKPTR2:1; unsigned STKPTR3:1; unsigned STKPTR4:1; unsigned :1; unsigned STKUNF:1; unsigned STKFUL:1; } STKPTRbits; extern near unsigned extern near unsigned extern near unsigned extern near unsigned

short long TOS; char TOSL; char TOSH; char TOSU;

/*------------------------------------------------------------------------* Some useful defines for inline assembly stuff *-------------------------------------------------------------------------*/ #define ACCESS 0 #define BANKED 1 /*------------------------------------------------------------------------* Some useful macros for inline assembly stuff *-------------------------------------------------------------------------*/ #define Nop() {_asm nop _endasm} #define ClrWdt() {_asm clrwdt _endasm} #define Sleep() {_asm sleep _endasm} #define Reset() {_asm reset _endasm} #define #define #define #define #define Rlcf(f,dest,access) Rlncf(f,dest,access) Rrcf(f,dest,access) Rrncf(f,dest,access) Swapf(f,dest,access) {_asm {_asm {_asm {_asm {_asm movlb movlb movlb movlb movlb f f f f f rlcf f,dest,access _endasm} rlncf f,dest,access _endasm} rrcf f,dest,access _endasm} rrncf f,dest,access _endasm} swapf f,dest,access _endasm }

_CONFIG5H, \ _CONFIG6L, \ _CONFIG6H, \ _CONFIG7L, \ _CONFIG7H) \ const rom unsigned char _configuration[14] = { \ 0xFF, \ _CONFIG1H, \ _CONFIG2L, \ _CONFIG2H, \ 0xFF, \ _CONFIG3H, \ _CONFIG4L, \ 0xFF, \ _CONFIG5L, \ _CONFIG5H, \ _CONFIG6L, \ _CONFIG6H, \ _CONFIG7L, \ _CONFIG7H \ } /*------------------------------------------------------------------------* CONFIG1H (0x300001) *-------------------------------------------------------------------------*/ #define _CONFIG1H_DEFAULT 0x27 #define _OSC_LP_1H 0xF8 #define _OSC_XT_1H 0xF9 #define _OSC_HS_1H 0xFA #define _OSC_RC_1H 0xFB #define _OSC_EC_1H 0xFC #define _OSC_ECIO_1H 0xFD #define _OSC_HSPLL_1H 0xFE #define _OSC_RCIO_1H 0xFF #define _OSCS_ON_1H #define _OSCS_OFF_1H 0xDF 0xFF

/*------------------------------------------------------------------------* A fairly inclusive set of registers to save for interrupts. * These are locations which are commonly used by the compiler. *-------------------------------------------------------------------------*/ #define INTSAVELOCS TBLPTR, TABLAT, PROD /*------------------------------------------------------------------------* IMPORTANT: The _CONFIG_DECL macro has been deprecated. Please utilize * the #pragma config directive. Refer to the "MPLAB C18 C * Compiler User's Guide" for more information relating to the * #pragma config directive. * * Defines for configuration words: * _CONFIG_DECL should be placed between a #pragma romdata CONFIG * and a #pragma romdata. For example: , * #pragma romdata CONFIG * _CONFIG_DECL(...) * #pragma romdata * NOTE: This macro only works when using the default linker script files * and the CONFIG section exists. *-------------------------------------------------------------------------*/ #define _CONFIG_DECL(_CONFIG1H, \ _CONFIG2L, \ _CONFIG2H, \ _CONFIG3H, \ _CONFIG4L, \ _CONFIG5L, \

/*------------------------------------------------------------------------* CONFIG2L (0x300002) *-------------------------------------------------------------------------*/ #define _CONFIG2L_DEFAULT 0x0F #define _PWRT_ON_2L 0xFE #define _PWRT_OFF_2L 0xFF #define _BOR_OFF_2L #define _BOR_ON_2L #define #define #define #define _BORV_45_2L _BORV_42_2L _BORV_27_2L _BORV_25_2L 0xFD 0xFF 0xF3 0xF7 0xFB 0xFF

/*------------------------------------------------------------------------* CONFIG2H (0x300003) *-------------------------------------------------------------------------*/ #define _CONFIG2H_DEFAULT 0x0F #define _WDT_OFF_2H 0xFE #define _WDT_ON_2H 0xFF #define _WDTPS_1_2H 0xF1

99 of 122

#define #define #define #define #define #define #define

_WDTPS_2_2H _WDTPS_4_2H _WDTPS_8_2H _WDTPS_16_2H _WDTPS_32_2H _WDTPS_64_2H _WDTPS_128_2H

0xF3 0xF5 0xF7 0xF9 0xFB 0xFD 0xFF

#define _WRT1_ON_6L #define _WRT1_OFF_6L #define _WRT2_ON_6L #define _WRT2_OFF_6L #define _WRT3_ON_6L #define _WRT3_OFF_6L

0xFD 0xFF 0xFB 0xFF 0xF7 0xFF

/*------------------------------------------------------------------------* CONFIG3H (0x300005) *-------------------------------------------------------------------------*/ #define _CONFIG3H_DEFAULT 0x01 #define _CCP2MUX_OFF_3H 0xFE #define _CCP2MUX_ON_3H 0xFF /*------------------------------------------------------------------------* CONFIG4L (0x300006) *-------------------------------------------------------------------------*/ #define _CONFIG4L_DEFAULT 0x85 #define _STVR_OFF_4L 0xFE #define _STVR_ON_4L 0xFF #define _LVP_OFF_4L #define _LVP_ON_4L #define _DEBUG_ON_4L #define _DEBUG_OFF_4L 0xFB 0xFF 0x7F 0xFF

/*------------------------------------------------------------------------* CONFIG6H (0x30000b) *-------------------------------------------------------------------------*/ #define _CONFIG6H_DEFAULT 0xE0 #define _WRTB_ON_6H 0xBF #define _WRTB_OFF_6H 0xFF #define _WRTC_ON_6H #define _WRTC_OFF_6H #define _WRTD_ON_6H #define _WRTD_OFF_6H 0xDF 0xFF 0x7F 0xFF

/*------------------------------------------------------------------------* CONFIG5L (0x300008) *-------------------------------------------------------------------------*/ #define _CONFIG5L_DEFAULT 0x0F #define _CP0_ON_5L 0xFE #define _CP0_OFF_5L 0xFF #define _CP1_ON_5L #define _CP1_OFF_5L #define _CP2_ON_5L #define _CP2_OFF_5L #define _CP3_ON_5L #define _CP3_OFF_5L 0xFD 0xFF 0xFB 0xFF 0xF7 0xFF

/*------------------------------------------------------------------------* CONFIG7L (0x30000c) *-------------------------------------------------------------------------*/ #define _CONFIG7L_DEFAULT 0x0F #define _EBTR0_ON_7L 0xFE #define _EBTR0_OFF_7L 0xFF #define _EBTR1_ON_7L #define _EBTR1_OFF_7L #define _EBTR2_ON_7L #define _EBTR2_OFF_7L #define _EBTR3_ON_7L #define _EBTR3_OFF_7L 0xFD 0xFF 0xFB 0xFF 0xF7 0xFF

/*------------------------------------------------------------------------* CONFIG5H (0x300009) *-------------------------------------------------------------------------*/ #define _CONFIG5H_DEFAULT 0xC0 #define _CPB_ON_5H 0xBF #define _CPB_OFF_5H 0xFF #define _CPD_ON_5H #define _CPD_OFF_5H 0x7F 0xFF

/*------------------------------------------------------------------------* CONFIG7H (0x30000d) *-------------------------------------------------------------------------*/ #define _CONFIG7H_DEFAULT 0x40 #define _EBTRB_ON_7H 0xBF #define _EBTRB_OFF_7H 0xFF #endif

/*------------------------------------------------------------------------* CONFIG6L (0x30000a) *-------------------------------------------------------------------------*/ #define _CONFIG6L_DEFAULT 0x0F #define _WRT0_ON_6L 0xFE #define _WRT0_OFF_6L 0xFF

100 of 122

/****************************************************************************** MODULE Statistics module FILE statistics.c ENTRY (PUBLIC) ROUTINE - May be called from outside this module mean_weight(unsigned char samples_used); weight_variance(unsigned char samples_used, unsigned short long int mean); INITIALISATION ROUTINES Makes use of the data array structure established in store_data header. DESCRIPTION Computes mean and variance over a sample set of size samples_used and returns values into the global variables; mean & variance. LAST UPDATE 4 June 2006 Tycho *******************************************************************************/

extern */ extern extern extern extern */

unsigned short int weight_buffer[]; signed char data_index; unsigned char samples_used; long int variance; unsigned short long int mean;

/* size = MAX_DATA_SAMPLES

/* 32 bit */

/* 24 bit

static long int temp_var; static unsigned char store_samples_used; /****************************************************************************** F O R W A R D D E C L A R A T I O N S In C, functions are assumed to return int unless declared otherwise. Here, the return type and the type(s) of argument(s) of all functions are declared. This "function prototyping" for ANSI compilers allows the compiler to do full type checking of function arguments and return types. The statement below declares cmdint() to be a function which does not return a value. static means that the function is not visible outside this file ("private" to this module). *******************************************************************************/ unsigned short long int mean_weight(unsigned char samples_used); long int weight_variance(unsigned short long int mean); /****************************************************************************** E N T R Y R O U T I N E D E F I N I T I O N Entry routines (public routines) are those that can be called directly by functions outside this module (file). Here there is only one entry routine, the main() function. *******************************************************************************/ /* unsigned short long int mean_weight(unsigned char samples_used); long int weight_variance(unsigned short long int mean); */

/****************************************************************************** I M P O R T S *******************************************************************************/ #include <stdlib.h> //#include "store_data.h" /* standard C header file */ /* Defines the data arrays read in this file. */

/****************************************************************************** P R I V A T E D A T A N A M E D C O N S T A N T S A N D M A C R O S ******************************************************************************/ /* Relevant constants as defined in store_data.h */ /* #define BUFFER_SIZE 100 #define FIR_WEIGHTS 21 */ #if !defined (MAX_DATA_SAMPLES) # define MAX_DATA_SAMPLES 90 # endif /****************************************************************************** P R I V A T E D A T A D E F I N E D T Y P E S A N D M O D U L E V A R I A B L E S *******************************************************************************/

/*----------------------------------------------------------------------------FUNCTION mean_weight mean weight calculation.

SYNOPSIS unsigned short long int mean_weight(unsigned char samples_used); Function uses a looping addition to first add all samples used to calculate the last measurement then calculate mean value. PARAMETER samples_used -the number of samples used in the calculation of a weight value.

101 of 122

REMARKS Intermediate mean value is multiplied by 100 before division to retain 2 d.p. of accuracy. This must be taken into account when printing data to screen in user remote mode. ------------------------------------------------------------------------------*/

weight value as read at the start of the mean function. Done to remove possibility of a change to samples_used between call to mean_weight and weight_variance. mean - the previously calculated sample population mean. The x100 operation to give 2 d.p. resolution is taken into account before calculation. REMARKS Variance is given 2 d.p. resolution via a x100 operation.

unsigned short long int mean_weight(unsigned char samples_used) { char i,j; /* local loop and sample index */ mean=0; store_samples_used=samples_used; j = data_index - store_samples_used; to first value used in mean calc. */ if(j < 0) {j = j + MAX_DATA_SAMPLES;} condition */ for(i=0; i<samples_used; i++) { mean=mean+weight_buffer[i]; weight_data will not exceed 1024 */ j = j + 1; /* so long as samples_used does not exceed 63, if(j >= MAX_DATA_SAMPLES) revised to allow for 100 samples, */ {j = 0;} /* i.e. one second @ 100Hz. */ } mean=mean*100; /* Giving mean to 2 d.p. */ mean=(mean/store_samples_used); return mean; /* sets j pointer /* buffer overflow

------------------------------------------------------------------------------*/ long int weight_variance(unsigned short long int mean) { char i,j; variance=0; mean=mean/100; j = data_index - store_samples_used; if(j < 0) {j = j + MAX_DATA_SAMPLES;} for(i=0; i<samples_used; i++) { temp_var=(((weight_buffer[j]-mean)*(weight_buffer[j]-mean))); variance=(variance+temp_var); j = j + 1; if(j >= MAX_DATA_SAMPLES) {j = 0;} } variance=variance*100; /* giving variance to simulated 2 d.p. */ variance=(variance/store_samples_used); return variance;

/* */

/* mean is 16 bit.

/*----------------------------------------------------------------------------FUNCTION weight_variance weight variance calculation.

SYNOPSIS long int weight_variance(unsigned char samples_used, unsigned short long int mean); Function uses a looping calculation to first calculate variance element which is then added to intermediate variance. Finally the intermediate variance is divided by samples used, giving the variance of the weight POPULATION. (as opposed to running sample set) PARAMETER store_samples_used -the number of samples used in the calculation of a

102 of 122

/****************************************************************************** MODULE Data storage header. FILE store_data.h DESCRIPTION This header file contains the arrays in which data pertaining to weighing operations is defined and stored. LAST UPDATE 1 June 2006 first code *******************************************************************************/ #if !defined(store_data) /*#define store_data*/ /* include this file only once */

/****************************************************************************** P U B L I C D A T A N A M E D C O N S T A N T S A N D M A C R O S *******************************************************************************/ #define FIR_WEIGHTS #define BUFFER_SIZE #define MAX_DATA_SAMPLES 21 90

100

/****************************************************************************** P U B L I C D A T A D E F I N E D T Y P E S A N D G L O B A L V A R I A B L E S *******************************************************************************/ unsigned short int AD_data_buffer[MAX_DATA_SAMPLES]; unsigned short int weight_buffer[MAX_DATA_SAMPLES]; unsigned short int filter_data[MAX_DATA_SAMPLES]; signed char data_index; /* points to most recently received data sample */ unsigned char samples_used; long int variance; unsigned short long int mean; #endif /* if !defined(store_data) */ /* 32 bit */ /* 24 bit */

103 of 122

/**************************************************************** FACTORY MODE * Author: John Yeh Truong. * Date: 10th of May, 2006. * Function Description: * Factory mode provides the options of calibrating the FOCUS scales, display statistics of recent measurements and use the scales through the same functions on the scales via the computer. Only FOCUS scale producers, technician or other appropraite personel will have access to calibration and statistics options. * ****************************************************************/

int input_voltage=1; for testing. Actual value is gathered from filtered voltage double mean = 35.3; double variance = 5.7; //test

// arbitrary value

//test

* * * * *

unsigned int weight_calibrate_array[]={0, 200, 400, 600, 800, 1000}; unsigned int grad_array[5]; // Need to specify size since don't give it assign it to be anything unsigned int voltage_offset; // Define Function Prototypes void Initialise(void); void Display_start_menu(void); void Display_calibrate(void); void Display_stats(void); void show_weight_ounces(void); void transmit_text( unsigned char *pointer, unsigned char end_character); void transmit_character(char character); int determine_fn(int index, int raw_voltage); void calc_weight(int gradient, int offset, int raw_voltage); void display_user_remote(void); void display_weight(void); void show_weight_grams(void); void count_mode(void); void rx232Isr(void); void determine_weight(void); void user_remote(void); void calculations(int weight1, int weight2, int voltage1, int voltage2, int counter); void start_program(void); int Password(void); void main(void) { start_program(); prgram }

#include <p18f452.h> #defines #include <string.h> functions #include <stdlib.h> standard Library #include <math.h> // Program Defines #define BCF 0 and clear bits #define BSF 1 #define baud_rate 25 #define cr 0x0D #define lf 0x0A #define colon 0x3A #define zero 0x30 #define null 0x00 char choice; char end_character; char *pointer; char weight_string[8]; char selection='n'; unsigned char character; char read; int weight; int zero_weight=0; int index; int gradient; int offset; int raw_voltage=100; //int offset_array[]={1,10,20,30,40}; int voltage_array[]={1,10,20,30,40,50}; int bol=0; int offset_array[5]; int input_voltage = 1; int counter;

// Include PIC18F442 // Include string // Include

// Next two lines are used to set // For Serial transmission // carriage return character // line feed character // colon character // 0 // null

// Used to direct from main

//for testing //for testing

//for testing

// for testing

void start_program(void) /**************************************************************************************** Author: John Yeh Truong. * Function description: * This function acts as a main module which combines all the function together. * start_program provides the interface for the user to choose between the three * different options: Calibrate, display statistics and user remote mode. In order * to gain accesss to calibrate and display statistics, a password is required. If * an options is selected that is not avaliable, an error message will be displayed * and the program will allow the user to select an option again. * ****************************************************************************************/

104 of 122

char error_message[]="Invalid.Try again.\r\n\n\n"; int password_flag = 0; Initialise(); serial and interupts while (1) { Display_start_menu(); // menu PIE1bits.RCIE=BCF; off interupts while (PIR1bits.RCIF==0){} // wait for key choice = RCREG; switch (choice) user input { case '1': { password_flag=Password(); if(password_flag) // { Display_calibrate(); // function read=RCREG; // to clear RCREG } break; } case '2': { password_flag=Password(); if(password_flag) // { Display_stats(); // read=RCREG; // to clear RCREG } break; } case '3': { user_remote(); user remote option break; } default: { transmit_text(error_message, null); break; } } } }

//setup

Display startup // Turn user to press // checks

* Display_start_menu shows the start menu when serial is connected to the computer, * indicating what are the options to be selected. * ****************************************************************************************/ { char title[]="\n\n\rMAIN MENU\n\n\r"; char start[]=" \r\n\nOptions:\r\n\n"; char op1[]="1 Calibrate.\r\n"; char op2[]="2 Stats.\r\n"; char op3[]="3 User remote.\r\n"; transmit_text(title, null); transmit_text(start, null); transmit_text(op1, null); transmit_text(op2, null); transmit_text(op3, null);

Function description:

checks password go to calibrate

checks password Display stats

//go to

void transmit_text(unsigned char *pointer, unsigned char end_character) /**************************************************************************************** Author: John Yeh Truong. * Inputs: Pointer to start of sting, last character to be sent. This is usually null. * Function description: * transmit_text transmits a string to be displayed via serial. * ****************************************************************************************/ { unsigned char flag = 0; // flag used to indicated end of string while (flag==0) // As long as not end of string { while (TXSTAbits.TRMT==0){};// wait for transmission to finish TXREG = *pointer; // transmit next character if (*pointer == end_character) // checks if end has been reached { flag=1; // indicate end of string } else // if not end of string { pointer++; // increment pointer position } } } void transmit_character(char character) /**************************************************************************************** Author: John Yeh Truong. *

void Display_start_menu(void) /**************************************************************************************** Author: John Yeh Truong. *

105 of 122

Input: Character to be displayed. Function description:

* transmit_character displays the input character on screen via serial. * ****************************************************************************************/ { while (TXSTAbits.TRMT==0){}; // wait for transmission to finish TXREG = character; // Send Character } void Display_calibrate(void) /**************************************************************************************** Author: John Yeh Truong. * Function description: * Display_calibrate displays information regarding calibrate. It also carries out the * calibration procedures. The user is first asked to remove all weights from scales * and press enter when done. Then the user is asked to add 200 grams and press enter. * 200 grams is continullay added until 1000 grams is reached. Voltage readings from * the strain gauage are then stored in an array where functions are used to calculate * the weight-voltage realationship between the 200 gram intervals. * ****************************************************************************************/ { char text[]="Remove any weights.\n\r"; char text2[]="Press enter when done\n\n\r"; char text3[]="Add 200 grams to the scale\n\r"; char text4[]="\n\n\rCALIBRATION SUCCESSFUL\n\n\r"; while (TXSTAbits.TRMT==0){}; // wait for transmission to finish counter = 0; while (counter<6) //size of weight_calibrate_array { if (counter == 0) // if calibrate is rn for the first time { transmit_text(text, null); // send text to serial transmit_text(text2, null); // send text2 to serial for user to press key while (PIR1bits.RCIF==0);//{;} // // wait fil_data

transmit_text(text2, null); read=RCREG; // done to clear RCIF bit for user to press key while (PIR1bits.RCIF==0){bol=1;} // wait // this line reads

//voltage_array[counter] = input_voltage; the voltage reading from scales used } counter++;

// this is commented as test values are currently PIR1bits.RCIF=BCF;

} counter = 0; while (counter < 5) // size of weight_calibrate_array-1 { calculations(weight_calibrate_array[counter], weight_calibrate_array[counter+1], voltage_array[counter], voltage_array[counter+1], counter); counter++; } transmit_text(text4, null);

//voltage_array[counter] = fil_data; is the current voltage reading defined in other modules module

// this is commented as arbitrary values are used to test this } else {

transmit_text(text3, null);

106 of 122

107 of 122

108 of 122

109 of 122

110 of 122

111 of 122

112 of 122

113 of 122

114 of 122

115 of 122

116 of 122

} void Display_stats(void) /**************************************************************************************** Author: Chris Currie. * Function description: * Display_stats displays on screen or the statistical information on the most recent * weight measurements. * ****************************************************************************************/ { int counter = 0; // counter used for looping print char raw_array_ascii[4]; // variable to store ascii val of raw voltage char filtered_array_ascii[4]; // variable to store ascii val of filtered voltage char variance_ascii[2]; // characters to store ascii val of variance char mean_ascii[4]; // characters to store ascii val of mean char dec_ascii[2]; // character to store ascii val of mean decimal char dec2_ascii[2]; // character to store ascii val of variance decimal int temp1; // temp val to extract values from raw array int temp2; // temp val to extract values from filter array int buffer_size = 7 ; // Size of buffer char stats1[] = "Raw Filtered \r\n"; char stats2[] = "Mean: "; char stats3[] = " Var: "; char space[] = " "; char exit_message[] = "\n\rPress any key to exit"; int raw_voltage_array[] = {20, 36, 47, 75, 128, 253, 506}; int filtered_voltage_array[] = {22, 36, 48, 76, 125, 250, 500}; unsigned int temp_mean; // temp val unsigned int dec; // holds val of numeral after decimal point for mean unsigned int temp_variance; // temp val unsigned int dec2; // holds val of numeral after decimal point for variance // for testing // for testing

transmit_text(stats1, null); while(counter <= (buffer_size - 1)) the end of the array { temp1 = raw_voltage_array[counter]; extract from array temp2 = filtered_voltage_array[counter]; array itoa(temp1, (char*)&raw_array_ascii); ascii transformation on raw voltage itoa(temp2, (char*)&filtered_array_ascii); transformation on filtered voltage transmit_text(raw_array_ascii, null); transmit_text(space, null); transmit_text(filtered_array_ascii, null); transmit_character(cr); transmit_character(lf); counter++; } // while not at // temp val to // temp val to extract from // integer to // integer to ascii

temp_mean=mean*10; // only want to one decimal places dec=temp_mean%10; // take modulus temp_variance = variance*10; // only want to one decimal places dec2 = temp_variance%10; // take modulus itoa(dec, (char*)&dec_ascii); // integer to ascii transformation of mean decimal itoa(dec2, (char*)&dec2_ascii); // integer to ascii transformation of variance decimal itoa(mean, (char*)&mean_ascii); // integer to ascii transformation of mean itoa(variance, (char*)&variance_ascii); // integer to ascii transformation of variance transmit_character(cr); transmit_character(lf); transmit_text(stats2, null); transmit_text(mean_ascii, null); transmit_character('.'); transmit_text(dec_ascii, null); transmit_text(stats3, null); transmit_text(variance_ascii, null); transmit_character('.'); transmit_text(dec2_ascii, null); transmit_text(exit_message, null); while (PIR1bits.RCIF==0){} // wait for user to press key } }

purposes

{ while (TXSTAbits.TRMT==0){}; transmit_character(cr); transmit_character(lf); transmit_character(lf);

// wait for transmission to finish // used for formatting

void Initialise(void) /**************************************************************************************** Author: John Yeh Truong. *

117 of 122

Function description:

Initialise function does all the configuration requirements * of the serial, serial interrupt and ports. * ****************************************************************************************/ { RCSTAbits.SPEN=BSF; // enable serial port TRISC=0b10000000; // configure pins for input/output TXSTA=0b00100100; // high speed transmission enabled SPBRG=baud_rate; // select baud rate RCSTAbits.CREN=BSF; // receive enable PIE1bits.RCIE=BSF; // enable receive interupts INTCONbits.GIE=BSF; // enable global interupts INTCONbits.PEIE=BSF; // enable peripheral interupts RCONbits.IPEN=BSF; // enable priorities on interupts IPR1bits.RCIP=BCF; // low priority interupts }

int determine_fn(int index, int raw_voltage) /**************************************************************************************** Author: John Yeh Truong. * Inputs: index which represents location of weight-function realationship components.* These being gradient and voltage offset. Second input is the voltage reading form * the scales. * Output: index, location of gradient and voltage offset in their arrays. * Function descrption: * determine_fn works out the location of the componenets of the function to be calculate the current weight on the scales. It does this by working out what * interval the current weight lies and returns their location which corresponds to

index=4; // last function components are used } else if (raw_voltage<=voltage_array[0]) // Checks if coltage reading is less than zero weight voltage { index=0; bol=1; // flag is tripped zero_weight=1; // zero weight flag tripped to indicate in outer module to display zero weight } else if ((raw_voltage<voltage_array[index+1])&&(raw_voltage>=voltage_array[index])) // Checks what voltage interval current reading is in { bol=1; // flag is tripped } else { index++; // else index increased so reading can be compared to next interval } } return index; } void calc_weight(int gradient, int offset, int raw_voltage) /**************************************************************************************** Author: John Yeh Truong. * Input: gradient of equation, voltage offset and curent reading. * Function description: * Calculates weight in grams from voltage reading. * ****************************************************************************************/ { raw_voltage=raw_voltage-offset; // calculation due to offset weight=gradient*raw_voltage/256; // calculation due to gradient // weight is divided by 256 as gradient was multiplied before to increase accuracy. } void display_user_remote(void) /**************************************************************************************** Author: John Yeh Truong. * Function description: * Displays on screen the menu for user remote mode. * ****************************************************************************************/ { char first_line[]="\n\r\nUSER REMOTE\n\n\r";

used to* weight the*

function component location in their respective arrays. * ****************************************************************************************/ {

int bol=0; index=0; values selected while (bol==0) { if (raw_voltage>=voltage_array[5]) is greater than the 1000 grams voltage { bol=1; // flag is tripped

// boolean flag // index determines final

// if the voltage reading

118 of 122

char instructions[]="Select grams or ounces before choosing count mode or back\n\r\n\r"; char second_line[]="Press c to count\n\r"; char third_line[]="Press b to go back"; transmit_text(first_line, null); transmit_text(instructions, null); transmit_text(second_line, null); transmit_text(third_line, null); transmit_character(lf); formatting transmit_character(lf); transmit_character(cr); } void display_weight(void) /**************************************************************************************** Author: John Yeh Truong. * Function description: * Displys on screen 'Weight:' to indicate weight on scales. * ****************************************************************************************/ { char weight_text[]="Weight:"; transmit_character(lf); transmit_character(cr); pointer=weight_text; transmit_text(pointer, colon); transmit_character(lf); // used for formatting transmit_character(cr); }

transmit_text(grams, null);

// used for

void show_weight_ounces(void) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * Calculates weight in ounces and displays weight in ounces. * ****************************************************************************************/ { char g_or_o[]="\n\rSelect units\n\r"; char options[]="Press g for grams or o for ounces\n\r"; int flag=0; char int_weight[4]; char ounces[]=" ounces"; weight=weight/28.35; recalculate weight for ounces itoa(weight, (char*)&int_weight); conversion on weight transmit_text(int_weight, null); transmit_text(ounces, null); } // // integer to ascii

void show_weight_grams(void) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * Displays weight in grams. * ****************************************************************************************/ { char g_or_o[]="\n\rSelect units\n\r"; char options[]="Press g for grams or o for ounces\n\r"; int flag=0; char int_weight[4]; char grams[]=" grams"; itoa(weight, (char*)&int_weight); conversion on weight transmit_text(int_weight, null); // integer to ascii

void count_mode(void) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * Displays count mode menu and runs count mode. ****************************************************************************************/ { int counter=0; int bol=0; int no_of_items; char title[]="\r\nCOUNT MODE\n\n\r"; char count_mode_text[]="Enter num of items\r\n"; char go_back[]="Enter b to display weight\r\n"; char item_no_text[]="\n\n\rNum of items:\r\n"; char error_message[]="Try again\r\n"; char int_count_no[4]; storage for number of items as a string to be received char number_of_items[4]; number of items as a string to be transmitted int flag=0; int count_no; int weight_of_one_item;

// // storage for

119 of 122

int raw_no_of_items;

PIE1bits.RCIE=BCF; // disable interupts transmit_text(title, null); transmit_text(go_back, null); transmit_text(count_mode_text, null); while (PIR1bits.RCIF==0){} to press key read=RCREG; // read takes value of RCREG bol = 0 ; while (read!='b') the chracter "b" for back is not entered { read = RCREG; while (bol==0) // while flag is not tripped { read = RCREG; if ((read>=0x30)&&(read<=0x39)) entered character is a digit { transmit_character(read); digit to show number has been received bol=0; storage array number_of_items[counter]=read; counter++; // checks if // transmit the // while // wait for user

} else // if entered character is anything but a digit { transmit_text(error_message, null); counter=0; bol=0; } } if (counter==2) // max digits that can be entered are three { bol=1; number_of_items[counter]=null; } if (bol==0) { to press key } } while (PIR1bits.RCIF==0){} // wait for user

// placed into

} else if (read==cr) // if carriage return detected { number_of_items[counter]=null; place into string bol=1; } else { if (read=='b') // if user wishes to go back { bol=1; // get out of loop flag=1; // to prevent calculating number of items

// null charcter

if (flag==0) // if 1st time { no_of_items=atol(number_of_items); // ascii to integer transformation of number of items determine_weight(); // weight calculated weight_of_one_item=weight/no_of_items; flag=1; // flag set so as not to repeat this step transmit_text(item_no_text, null); } if (no_of_items==0) // if 0 is entered { raw_no_of_items=0; // then number of items is zero } else { determine_weight(); // determine weight raw_no_of_items=weight/weight_of_one_item; } count_no=(int)raw_no_of_items; // count number = rounded number itoa(count_no, (char*)&int_count_no); // integer to ascii conversion transmit_character(cr); transmit_text(int_count_no, null);

120 of 122

PIE1bits.RCIE=BSF; } }

//if voltage reading is not valid, that is if the voltage reading gives zero weight or less { weight=0; // Declares low zero_weight=0; // zero weight flag is reset

else

#pragma code low_vector=0x18 priority interupt void interrupt(void) { _asm GOTO rx232Isr _endasm } #pragma code #pragma interrupt rx232Isr

} return index; }

void rx232Isr(void) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * Interrupt is driven when recieve register receives a character, that is when user * enters a character. The entered cahracters are read into the following variables. * ****************************************************************************************/ { selection=RCREG; read=RCREG; }

void user_remote(void) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * user_remote runs the user remote mode, displaying the weight on scales by default. * ****************************************************************************************/ { int boolean=0; int bol=0; char units='x'; char GorO[]="\r\nPress g for grams or o of ounces\r\n"; while (bol==0) { bol=1; Initialise(); // esentially used to reset of configuration requirements. display_user_remote(); while (selection!='b') if user wishes to return in the main menu { if (selection=='c') // checks if user wants count mode { count_mode(); bol=0; } { // checks

void determine_weight(void) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * Runs the appropriate functions to calculate the weight on scales. * ****************************************************************************************/ { index=0; // resets index index=determine_fn(index, raw_voltage); if (zero_weight==0) // If the voltage reading is valid { gradient=grad_array[index]; // appropriate gradient is chosen offset=offset_array[index]; // appropriate offset chosen calc_weight(gradient, offset, raw_voltage); // weigh calculated through function }

determine_weight(); while (boolean==0) { PIE1bits.RCIE=0; transmit_text(GorO, null); while (PIR1bits.RCIF==0){} // waits for user to input what units to display weight read=RCREG; if (read=='g') { units='g'; display_weight(); show_weight_grams(); transmit_character(cr);

121 of 122

boolean=1; // prevents asking user what units are desired again } else if (read=='o') { units='o'; display_weight(); show_weight_ounces(); transmit_character(cr); boolean=1; // prevents asking user what units are desired again } } PIE1bits.RCIE=1; } if (units=='g') { show_weight_grams(); transmit_character(cr); } else if (units=='o') { show_weight_ounces(); transmit_character(cr); } } selection='n'; // resets selection whic is to be used in other menus }

/**************************************************************************************** Author: Chris Currie. * Function decription: * Checks if entered string matches the password. * ****************************************************************************************/ { char unsuccessful_password[] = "\n\n\r You do not have access to this part of the program\n\n\r"; char enter_password[] = "\n\r Please enter the password \n\r"; char successful[] = "\n\n\n\r ACCESS GRANTED \n\n\n\r"; int loop_counter = 0; int counter_password = 0; char password_char; transmit_text(enter_password, null); while (loop_counter <= 2) { while (PIR1bits.RCIF==0){};

input

// waits for user

void calculations(int weight1, int weight2, int voltage1, int voltage2, int counter) /**************************************************************************************** Author: John Yeh Truong. * Function decription: * Calculates the gradient and voltage offset in the current weight interval and stores* those values into their corresponding arrays, sequentially so they can be retrieved * based on their location using the variable 'index'. * ****************************************************************************************/ { places gradient = ((weight2-weight1)*256)/(voltage2-voltage1); //to keep decimal

password_char = RCREG; if(password_char == '1') // checks each character is the part of the password { transmit_character('*'); counter_password++; loop_counter++; } else { transmit_character('*'); loop_counter++; } } if (counter_password == 3) { password_flag = 1; transmit_text(successful, null); } else { password_flag = 0; transmit_text(unsuccessful_password, null); } } return password_flag;

// weight is multiplied by 256 to maintain 2 decimal point resolution which improves accuracy of weight. voltage_offset = voltage1-(weight1/(gradient/256)); // divided by 256 to avoid scaling errors grad_array[counter] = gradient; // stores gradient in array offset_array[counter] = voltage_offset; // stores voltage offset in array } int Password(void)

122 of 122

Das könnte Ihnen auch gefallen