Fads to Obsessions and Beyond...




Free domain for life, exceptional technical support, website transfer

HX711 ADC for Weight Scale

The HX711 ADC is used to measure voltage from a load cell (wheatstone bridge) with a PIC18F248 microcontroller to measure weight. A breakout board is used as the source of the HX711 (easier/cheaper than using the HX711 directly).

The DIY food dehydrator project required measurement of weight lose due to evaporation during the development of the circuit/hardware. While this could be done via manual removal of test items and weighing on appropriate kitchen or other calibrated weight scale, in-situ weight measurement during experimental trials is desirable. The abilty to measure weight during an experimental trial (in this case the loss of water from dehydrating food versus other control variables such as ambient temperature and humidity) facilitates increased precision and accuracy of development and measurement work compared to manual weighing of experimental items.

Weight measurement [putting aside the distinction between weight and mass as "The distinction between mass and weight is unimportant for many practical purposes because the strength of gravity does not vary too much on the surface of the Earth" (1)] in general involves either a force-measuring device (e.g. spring deflection under load) or a balance (weight of unknown object compared to objects of known mass) (2).

A strain gauge, which is a fine wire "foil" the electrical resistance of which varies with how far the wire is stretched, is the electronic version of spring scales. The strain gauge is attached to a suitable beam (metal rod) upon which the unknown weight is placed. The deflection of the beam due to the unknown weight stretches or deforms the attached strain gauge, and the resultant change in electrical resistance of the strain gauge is a measure of the weight of the object.

Since the change in resistance of the strain gauge is small, typically four strain gauges are attached in a Wheatstone bridge arrangement (a full bridge) to maximise sensitivity and reduce temperature effects. Such an arrangement of strain gauges attached to a suitable beam is termed a load cell. A Google search provides numerous excellent sites explaining strain gauge measurement, Wheatstone bridge theory, and this is left to the interested reader.

Therefore, a DIY weight scale involves the use of a suitable load cell coupled with a means to measure voltage across the Wheatstone bridge arrangement, and converting the obtained voltage into a weight via a suitable calibration factor. Further, the small change in voltage expected will require suitable amplification, noise suppression, etc.

Load cells (from 1kg to 10kg) are readily available via ebay, with prices ranging from only a few dollars (including shipping in many cases). The measurement of voltage from the strain gauge indicates analog to digital (ADC) conversion with appropriate prior amplification via op-amp circuity. Conveniently, the HX711 is a precision 24-bit ADC designed for weight scales that includes a low-noise programmable gain amplifier and a simple digital interface for control and retrieval of data (all for the cost of a few dollars, even in small quantities, via ebay).

A low cost load cell from ebay (and a salvaged load cell from a damaged digital scale) was explored in-conjunction with a HX711 break-out board, interfaced via a PIC18F248 (with RS232 connection to PC) to determine the utility of these components for a DIY weight scale.

For reference, other features of the HX711 from the datasheet:

    • On-chip active low noise PGA with selectable gain of 32, 64 and 128
    • On-chip power supply regulator for load-cell and ADC analog power supply
    • Operation supply voltage range: 2.6 to 5.5V
    • On-chip oscillator requiring no external component with optional external crystal

See the various sections below for circuit details, schematic diagrams, software/firmware and other details.


The schematic for the HX711 breakout board with connections to the PIC18F248 is given in the Schematics Section below. The ancillary circuitry for the PIC18F248 also includes connection via RS232 to a PC (enables PC control of the HX711 to set parameters and retrieve data).

Power Supply

A typical "wall-wart" power-supply is used (a surplus laptop charger in this case) in conjunction with a voltage regulator (LM317T) to provide the regulated 5V required by the PIC microcontroller.

The HX711 breakout board also requires a 2.7-5.5V supply, which is the same supply as for the PIC microcontroller in this case. In turn, the HX711 provides the excitation voltage for the attached load cell.

Firmware/Software

The HX711 provides simple digital control and a serial interface for retrieval of data. Two control pins, a clock and data line, are all that is required for the actual interface to the microcontroller. The particular breakout board used that contains the HX711 does not provide access to select the output rate of the HX711 via the microcontroller (all the "inexpensive" HX711 breakout boards available online/ebay are similar).

An output rate of 10Hz is fixed via the breakout board circuit (pin 15 to gnd). The alternative 80Hz output rate could be "hacked" via soldering a wire to the HX711 breakout board pin 15 via a current limiting resistor to Vcc. However, the higher output frequency also gives increased noise, and the 10Hz output rate is generally more than sufficient for most "weighing" applications.

Similarly, while the serial interface enables digital/microcontroller selection of input channel to be used on the HX711, the actual breakout board does not enable the corresponding "switching" of the attached load cell between selected HX711 ADC channels. While additional circuity could be relatively easily added to facilitate "switching" the load cell to the appropriate channel upon signal from the microcontroller to the HX711 breakout board, this was not done. Channel A provides two levels of gain, whereas, channel B only provides a "single gain" that is lower than the gains provided by channel A. Hence support of "switching" of the load cell to use either channel A or B was not enabled. The load cell is hard wired to channel A (and the firmware/microcontroller enables selection of either a 128 or 64 level of gain).

PIC Microcontroller Interface Code

The following code example shows the simple interface required to control the HX711 and connected load cell. The code enables control of the HX711 and retrieval of data, both raw counts and as calibrated weight in grams via a connected PC (RS232 connection).

Code Snippet 1: Interface to PIC18F248


#include "HX711_lib.h"
#zero_ram //all variables automatically initialised to 0

BYTE toggleReadCount;
long readCount;

#int_timer0  
void timer0_isr(void) { 
   set_timer0(TIMER0_PRELOAD); // Reload the Timer - prescaler = 32, 16-bit, period ~840 msec
   HX711exit = true;
} 

#int_timer1
void timer1_interrupt() { /* Timer1 has wrapped around to 0. */
   toggleReadCount=1;
   set_timer1(3035); //prescaler=8, 10Mhz, preload=3036 -> Freq 5hz, period=0.2sec
}

void main() {
   char recChar;  //the received character from the serial port via keyboard
   int8 continousReadings=0;
   float tempCelsius;
   long ADCvalue; 
   long consecutiveReadings = 0;  
   toggleReadCount=0;
   readCount=0;

   setup_adc_ports(AN0_AN1_AN2_AN4_VSS_VREF); //RA0_RA1_ANALOG_RA3_REF);
   setup_adc(ADC_CLOCK_DIV_32);    
   set_adc_channel(1); //0 = AN0 (pin2), 1=AN1 (pin3), etc

   setup_timer_0(T0_INTERNAL | T0_DIV_32);
   set_timer0(TIMER0_PRELOAD); // Reload the Timer - prescaler = 32, 16-bit, period ~840 msec
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //prescaler 8
   enable_interrupts(GLOBAL); 
   enable_interrupts(INT_TIMER0); 
   disable_interrupts(INT_TIMER1);
 
   printf("startn\r");
   delay_ms(500); //settling time for HX711 power-on      
   
   while(TRUE){     
      if (kbhit()) {      
         recChar = getc();
         switch (recChar) {
            case 'c':
            case 'C': HX711calCounts = HX711_readAveraged(10) - HX711offset; //calibration assumes already done tare 
                      printf("calibration =%Ld counts\n\r",HX711calCounts);
                      HX711_weight();
                      break;
            case 'd':
            case 'D': ADCvalue = Read_ADC();
                      tempCelsius = ADCvalue*0.24414; //*0.00244/1000 = mV; 10mV=1 Deg C, .: just * 0.244 = Deg C
                      printf("%2.1f Deg C\n\r",tempCelsius);
                      break;
            case 'r':
            case 'R': if (continousReadings == 1) {
                        continousReadings = 0;
                        toggleReadCount = 0;
                        disable_interrupts(INT_TIMER1);
                        //printf("Disable Continous Readings \n\r");
                      } else {
                        continousReadings = 1;
                        readCount = 0;
                        toggleReadCount = 0;
                        set_timer1(3035); //prescaler=8, 10Mhz, preload=3036 -> Freq 5hz, period=0.2sec
                        enable_interrupts(INT_TIMER1);
                        //printf("Enable Continous Readings \n\r");
                      }
                      break;
            case 't': 
            case 'T': HX711_tare();
                      break;      
            case 'w': 
            case 'W': HX711_weight();                             
                      break; 
            case 'z':
            case 'Z': HX711_zero();
                      break;
            default:  printf("Unknown cmd\n\r");
                      break;
         }
      }
      if (toggleReadCount==1) {
         toggleReadCount = 0;
         readCount++; //300 counts of 0.2sec = read every 60 secs
      }
      if (readCount>=150) { //300 counts of 0.2sec = read every 60 secs       
         disable_interrupts(INT_TIMER1);
         ADCvalue = Read_ADC();
         tempCelsius = ADCvalue*0.24414; //2.5Vref/1024 ADC bits = 0.00244*1000 = mV/ADC count;     
         //remember - not zeroed automatically on powerup of PIC at the moment
         consecutiveReadings=consecutiveReadings+1;
         HX711reading.weight_int = HX711_readAveraged(10);
         printf("%Ld,%Ld,%2.1f\n\r",consecutiveReadings,HX711reading.weight_int,tempCelsius);           
         readCount = 0;
         toggleReadCount = 0;
         set_timer1(3035); //prescaler=8, 10Mhz, preload=3036 -> Freq 5hz, period=0.2sec
         enable_interrupts(INT_TIMER1);
      }
   }
}
			

Code Snippet 2: HX711 Library Code


#define HX711_clock  PIN_B5
#define HX711_data   PIN_B6
#define calWeight    100
#define TIMER0_PRELOAD  0
#define _C2 1
/* signed long properties */
#define LONG_MAX 2147483647        /* signed long maximum*/
#define LONG_MIN (-2147483647-_C2) /* signed long minimum*/
   
int8 HX711gain=1; //makes default=channel A gain 128, which is HX711 power on default
int8 HX711exit=false;
signed int32 HX711offset;
unsigned int32 HX711calCounts;

union {
   signed int32 weight_int;
   float weight_float;
} HX711reading;

unsigned int32 HX711_read() {
   signed int32 inputData=0;
   unsigned int8 i;
   
   output_low(HX711_clock);   //ensure serial clock low ready for HX711 data retrieval
   HX711exit = False; 
   set_timer0(TIMER0_PRELOAD); // Reload the Timer - prescaler = 32, 16-bit, period ~840 msec   
   while (input(HX711_data) && !HX711exit); //wait for HX711 data go low, .: data ready for retrieval
   if (HX711exit) {printf("HX711 not ready\n\r");};
   for (i=0; i<24; i++) { //clock in the data
      output_high(HX711_clock); 
      delay_us(5);
      output_low(HX711_clock); 
      inputData=inputData << 1;
      if (input(HX711_data)) {
         inputData++;
      }
   }
   for (i=0;i maximum) maximum = temp;   
      averagedReading=averagedReading+temp;
   }
   averagedReading=averagedReading - minimum - maximum;
   averagedReading=averagedReading/numReadings;
   return (averagedReading);
}

void HX711_weight() { 
   if (HX711calCounts != 0) { // calibrated
      HX711reading.weight_float = (HX711_readAveraged(10) - HX711offset) * calWeight / (float)HX711calCounts;
      printf("weight=%5.2f gms\n\r",HX711reading.weight_float);
   } else { // not calibrated
      HX711reading.weight_int = HX711_readAveraged(10)- HX711offset;
      printf("weight=%Ld counts\n\r",HX711reading.weight_int);
   }
}

void HX711_setGain(int8 theGain) { 
   switch (theGain) {
       case 64: // channel A gain 64
         HX711gain = 3;
         break;
      case 128: // channel A gain 128
         HX711gain = 1;
         break;
   }
   HX711_read(); //perform a HX711 read to enable setting gain at end 
   delay_ms(500); //settling time for HX711 power-on, gain/channel change
}

void HX711_zero() {
   HX711offset = HX711_readAveraged(10); 
   printf("HX711 offset =%Ld counts\n\r",HX711offset);           
   HX711_weight();  
}

void HX711_powerDown() {
   output_low(HX711_clock); //just in case CLK pin high
   output_high(HX711_clock);  
   delay_us(60);  //PD_SCK change from low->high and stay high >60us = power down mode
}

void HX711_powerUp() {
   if (input(HX711_clock)) { //in power down mode
      output_low(HX711_clock); //resets HX711, back to normal mode
      delay_ms(500); //settling time for HX711 power-on before measurements
   }
}
			

Downloads

Description Downloads
HX711 library file: CCS C Source Code Download
Example PIC code with PIC18F248/PC serial interface: CCS C Source Code Download
Hex Code Download

The Testing/Experimental Results Section details the firmware (written in CSS C code) required to enable control of the HX711 breakout board and attached load cell (i.e., selected gain of channel A, data retrieval, and power up/down of the HX711).

Note: Image loading can be slow depending on server load.

  • HX711 Basic SchematicHX711 Basic Schematic

    Silver Membership registration gives access to full resolution schematic diagrams.

    HX711 Basic Schematic

This project did not require a PCB.

The construction was done using prototyping board. See the photographs and schematic diagram sections.

Qty Schematic Part-Reference Value Notes/Datasheet
Resistors
1R110K1/4W, 10% 
Diodes
1D11N4002
Integrated Circuits
1U1PIC18F248PIC microcontroller datasheet
1U27805Linear Voltage Regulator  datasheet
1U4MAX232ERS232 Driver/Receiver datasheet
Capacitors
2C1,C222pFceramic disk
1C30.33uFaluminium or tantalum electrolytic
1C40.1uFaluminium or tantalum electrolytic
5C5-C91uFaluminium or tantalum electrolytic
Miscellaneous
1X110MHzCrystal Oscillator
1X2HX711Break-out board datasheet
1X3Load CellFull-Bridge 5V
1J1CONN-H55-pin connector for ICSP
1P1CONN9-pin connector for RS232
1SW1SW-SPDT 
Description Downloads
HX711 - Bill of Materials Text File Download

The first step is testing the basic connections of the HX711 to power supply, the load cell and the microcontroller.

The HX711 serial communications protocol results in the data line (DT pin on the HX711 breakout board), which is normally in the "high" state, being pulled low by the HX711. This provides a simple test if the HX711 is connected and responding correctly (this is also the signal from the HX711 that data is ready for retrieval). The HX711_read() routine in the CCS C code library tests for this condition.

Once the HX711 indicates data ready for retrieval, pulsing the clock line shifts out the data (24 data bits, MSB first). The data is provided as a 24 bit number in 2's complement format. Using a signed 32-bit integer in the CCS C code to store this retrieved data means no transformation is required, except for extending the 24bits to 32bits taking into account the 2's complement MSB.

The example CCS C code enables control of the HX711 to retrieve counts corresponding to the voltage generated by the load cell when a weight is applied (see Downloads Section). When no load is being applied to the load cell, the counts retrieved from the HX711 correspond to the "offset" that must be taken into account when calculating weight. This offset is the weight of the physical "pan" upon which loads are placed onto the load cell and any inherent in-balance within the Wheatstone Bridge arrangement of the strain gauges within the load cell.

The example code is hard wired to take ten (10) sequential readings of which the highest and lowest are rejected, and the remaining are averaged and reported as the "reading". This is a simple "noise" reduction method. Similarily, the calibration weight is hard wired to 100gm and the reported weight in grams. These values are easily changed in the code by altering #define's.

In addition to reporting calculated weight in grams, the example code enables reporting of ambient temperature to enable testing of the response of the load cells not only to applied weight but temperature.

Load cells have a wide variety of engineering specifications that define performance and applicability (3). A number of common tests (i.e., those for which I have the equipment and or can approximate the relevant conditions adequately) are detailed below for a low-cost 5kg load cell purchased from ebay, and a 300gm load cell salvaged from a commerical jewellry scale.

Zero Balance

Zero balance is the difference from the load cell (the signal between the A- and A+ pins of the HX711 breakout board) when no load is applied. This is typically stated in terms of percentage of full scale. Therefore, zero balance is the "offset" that needs to be applied when measuring and calibrating weights, and represents inherent differences between the strain gauges (and strain gauge connections) that form the load cell. Full scale is simply the output from the HX711 when the load cell is full loaded.

In order to produce data for the zero balance load cell test, the load cell was simply connected to the HX711 without applied load and data from the HX711 collected at 15 second intervals via the RS232 connection to PC. Each data point at each successive 15 second interval was in turn the average of 10 readings taken as quickly as possible with the HX711 (10 Hz frequency). The frequency/amount of data was designed to give sufficient information to access if environmental variables (i.e., temperature) were being held reasonably constant. The load cell was isolated in a plastic container to minimise influence of air currents and change in ambient room temperature etc. The results are shown in the following Graph 1.

Before discussing the determined zero balance, one observation from Graph 1 is that upon initial power-up the HX711/load cell requires ~2 minutes before a stable reading is obtained (note, the firmware already included a 500ms "settling time" before reading from the HX711 as recommended in the data sheet). This observation was reproducible between load cells and between successive readings for a single load cell. In order to ascertain if the HX711 or the load cell was responsible for this observation, "zero balance" readings were obtained from the HX711 at differing times between successive power-up events. The shorter the time between power-up events, the lower was the "initial dip" in the zero balance reading. This leads to the conclusion that the load cells are expriencing some "self heating" when powered-up, and this leads to slightly higher readings until the load cell equilibrates with the surroundings.

In order to calculate the "zero balance" data from the repeated measurements with no applied load (see Graph 1) were taken for the period 2 minutes to 5 minutes. This was to eliminate the initial "power-up" settling time for the load cell and provide sufficient data to produce a represenative average, however, not overly extend the measuring time which then may lead to inclusion of confounding variation due to temperature, creep and similar effects.

The actual "zero balance" was measured to be 10498 counts for the 5kg load cell which is 0.67% FS - compared to the load cell data sheet specification of ±2% FS.

  • Graph 1: HX711 zero balance - counts versus time

    Graph 1: HX711 zero balanceGraph 1: HX711 zero balance

    Silver Membership registration gives access to full resolution diagrams.

    Graph 1: HX711 zero balance

Temperature Effect on Zero Balance

The ambient temperature is a major variable in the measurement of weigh using the load cell/strain gauges, as the electrical resistance of the strain gauges obviously varies with temperature (even though the Wheatstone Bridge arrangement compensates for temperature, for the full bridge arrangement, to a degree). The "Temperature Effect on Zero Balance" is the pertinent performance measure and is the change in zero balance (usually representated as %FS) due to a 1 degree Celsius change in ambient temperature.

In order to produce data for Temperature Effect on Zero Balance load cell test, the load cell was simply connected to the HX711 without applied load and data from the HX711 collected at 15 second intervals via the RS232 connection to PC, while temperature was monitored simultaneously via a LM35 sensor. The ambient temperature was varied using room air-conditioning. The actual load cell was covered with a plastic container to minimise influence of air currents and dampen out temperature change. Graph 2 presents the collected data set. After an initial equilibration period, the room air-conditioning was started (~ min 20) and then air-conditioning ceased (~ min 60) after which the room was allowed to equilibrate with ambient temperature again.

  • Graph 2: HX711 temperature effect on zero balance

    Graph 2: HX711 temperature effect on zero balanceGraph 2: HX711 temperature effect on zero balance

    Silver Membership registration gives access to full resolution diagrams.

    Graph 2: HX711 temperature effect on zero balance

In order to calculate the temperature effect on zero balance, portions of the data set (highlighted in Graph 2 via the grey shaded areas) were used to calculate the linear regression between measured temperature and HX711 counts (with no applied load). These linear regressions are displayed in Graph 3.

Due to the 10-bit ADC (and 2.5V voltage reference) being used on the PIC18F248 to measure the temperature via the LM35 sensor, the measured temperature data is not really "continous" as the restricted ADC resolution (and only using a portion of the ADC span) results in "binning" of the temperature data. However, the linear regressions are still statistically strong. The data has been treated seperately depending if the temperature was increasing or decreasing during the weight measurement. While the slopes of the linear regression of these two treatments are different, does not particularly indicate hystersis effect, and thus the all the data was pooled. The pooled data linear regression resulted in R2 0.83 with a slope of 1085 counts/degree Celsius, which is 0.069 %FS (compared to the 5kg load cell datasheet value of <0.005 %FS).

  • Graph 3: Linear Regression temperature on HX711 zero balance

    Graph 3: Linear Regression temperature on HX711 zero balanceGraph 3: Linear Regression temperature on HX711 zero balance

    Silver Membership registration gives access to full resolution diagrams.

    Graph 3: Linear Regression temperature on HX711 zero balance

Creep

Creep is the performance measure of the change in load cell signal the occurs over time while under load and all other variables remain constant. This generally measured at near load capacity and for a time of 30 minutes.

In order to produce data for the assessment of creep load cell test, the load cell was connected to the HX711 initially without applied load and data from the HX711 collected at 15 second intervals via the RS232 connection to PC, while temperature was monitored simultaneously via a LM35 sensor. This was to ensure that a stable equilibrium state was achieved (and that the ambient temperature was constant). Then a known 5kg weight was applied to the load cell, and measurement of response from the HX711 and load cell recorded for 30 minutes. Graph 4 presents the collected data set.

  • Graph 4: Assessment of load cell creep

    Graph 4: Assessment of load cell creepGraph 4: Assessment of load cell creep

    Silver Membership registration gives access to full resolution diagrams.

    Graph 4: Assessment of load cell creep

Graph 4 shows that after initial power-up there was an increase of ~1000 counts over the 10 minute period. The corresponding LM35 temperature data indicates that ambient temperature increase by approximately one degree Celsius. With reference to the previous section detailing the examination of temperature effect on zero balance, this increase of 1000 counts for 1 degree Celsius is consistent with previous results.

During the measurement period for assessment of creep (with 5kg applied weight), Graph 4 shows a relatively constant output from the HX711 + load cell, with the LM35 showing ambient temperature remained approximately constant during the period. Using the initial and final HX711 counts reading for the period that the 5kg weight was applied, results in a calculated value for creep of 0.008 %FS. This compares to the 5kg load cell datasheet value of <0.005 %FS.

Linearity/Calibration

Linearity is the algebraic difference between load cell output at a specific load and the corresponding point on the straight line drawn between minimum and maximum loads. Linearity is normally expressed in units of %FS. It is common for characterization to be measured at 40-60 %FS. It is desirable that linearity is high (or non-linearity is low!) so that a simply one-point linear calibration curve can be used.

In order the determine the linearity of the 5kg load cell, I had available a 100gm calibration weight and a commerical 3-decimal point electronic scale (see Photographs Section). This enabled production of secondary calibration weights of known mass by using known amounts of water (1ml = 1gm @ 25oC) in suitable containers. A series of weights across the calibration range (approximately 25gm, 50gm, 100gm, 200gm, 500gm, 1000gm, 2000gm and 5000gm) was used.

Graph 5 below shows the results of recording the counts due to each calibration weight against the pre-determined weight and then using a linear regression. The R2 value of 1 indicates a perfect linear relationship. The slope of 294 counts/gram is a measure of potential sensitivity

  • Graph 5: Load cell calibration

    Graph 5: Load cell calibrationGraph 5: Load cell calibration

    Silver Membership registration gives access to full resolution diagrams.

    Graph 5: Load cell calibration

The use of the HX711 breakout board, rather than the HX711 directly, makes the use of the component relatively straight forward. The HX711 itself has connection for 5V and the data and clock lines are 5V tolerant (so level shifting not required for use with typical 5V PIC microcontrollers). Obviously, double check polarity of power connections etc.

The load cells tested with the HX711 operated adequately with 5V that the HX711 breakout boards supply for energising the strain gauges in the load cell. However, if a higher voltage is required by a particular load cell (and or a higher voltage is desired to increase sensitivity) this cannot be done by the HX711.

The only other likely "gotcha" is that the HX711 reports data in 2's complement format. The CCS C compiler makes this rather easy to handle by simply using an appropriately sign interger variable. Otherwise, it is up to the user to transform the received 24-bit 2's complement number to enable processing.

Mounting of Load Cell

The Photographs Section demonstrates how the load cell was mounted to enable weighing of items. One side of the load cell is attached to a "base plate" such that the load cell can "pivot" or "bend" when a load is applied. The other side of the load cell has a "weight pan" attached such that physical objects can be placed onto the load cell. It is recommended that the "weight pan" forces the user to place objects such that they are over the central axis of the load cell.

While not shown in the photographs of the prototype load cell mount, it is also recommended that a "stop" is placed under the "weight pan" side of the load cell, which physically inhibits the load cell being bent beyond physical tolerance if extremely heavy loads are applied.


Comments/Questions (1)

Topic: HX711 ADC weigh scale
Sort
cardservicios says...
Hola cuánto es el costo para la descarga del peroyecto
2nd November 2018 10:57am
Page 1 of 1

Add Comment/Question

Only Logged-In Members can add comments

"If we could sell our experiences for what they cost us, we'd all be millionaires".

Please donate any amount to help with hosting this web site.

If you subscribe (only $2/annum) you can view the site without advertisements and get emails abouts updates etc.

X

Sorry!

Only logged-in users with correct Membership Level can download.


Membership starts at only $2, so join now!