Skip to content

Commit

Permalink
1.1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
olkal committed May 9, 2019
1 parent 52270c9 commit e390258
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 61 deletions.
24 changes: 4 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ Tare function can also be performed without halting the mcu.
Filtering and smoothing: "Moving average" method from a rolling data set combined with removal of high/low outliers is used for the retrieved value.

Selectable values in the config.h file:
- Moving average data set of 4, 8, 16, 32, 64 or 128 samples (default:16).
- Moving average data set of 1, 2, 4, 8, 16, 32, 64 or 128 samples (default:16).
- Ignore high outlier; one sample is added to the data set, the peak high value of all samples in the data set is ignored (default:1)
- Ignore low outlier; one sample is added to the data set, the peak low value of all samples in the data set is ignored (default:1)
- Enable delay for writing to sck pin. Could be required for faster mcu's
- Disable interrupts when sck pin is high. This could be required to avoid "power down mode" if you have some other time consuming (>60µs) interrupt routines running

Caution: using a high number of samples will smooth the output value nicely but will also increase settling time and start-up/tare time (but not response time). It will also eat some memory.

Expand All @@ -25,22 +27,4 @@ Wires between HX711 and load cell should be twisted and kept as short as possibl
Most available HX711 modules seems to follow the reference design, but be aware that some modules are poorly designed with under-sized capacitors, and noisy readings.
The Sparkfun module seems to differ from most other available modules as it has some additional components for noise reduction.

Update 1.1.2:
- Added example sketch "Read_1x_load_cell_interrupt_driven", it can be useful to enable an interrupt to trigger the update function if you have other time consuming code in your sketch loop (i.e. writing to a graphic LCD display) that otherwise could affect the settling time

Update 1.1.0:
- Data set configuration (data set, number of samples) has been moved from HX711_ADC.h to the new file config.h
- Included "yield" in function tare() to avoid crash on ESP8266 if wiring is incorrect
- Timeout added to the tare() function to avoid endless loop if wiring is incorrect
- Added function getSingleConversionRaw() for testing and debugging purpose
- Added function getReadIndex() for testing and debugging purpose
- Added function getConversionTime() for testing and debugging purpose
- Added function getSPS() for testing and debugging purpose
- Added function getTareTimeoutFlag() for testing and debugging purpose
- Added function disableTareTimeout() for testing and debugging purpose
- Added function getSettlingTime() for testing and debugging purpose
- Added example sketch "Calibration" with option to save the calibration value to eeprom
- In example sketches setup, option included to retrieve calibration value from eeprom
- Added example sketch "Testing" with some of the above mentioned functions for tare timeout, samplerate, conversion time, etc


Latest release and change log here: https://github.com/olkal/HX711_ADC/releases
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void setup() {
LoadCell.setCalFactor(calValue); // set calibration value (float)
Serial.println("Startup + tare is complete");
}

attachInterrupt(digitalPinToInterrupt(doutPin), whenreadyISR, FALLING);
}

Expand Down
6 changes: 6 additions & 0 deletions examples/Read_2x_load_cell/Read_2x_load_cell.ino
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ void setup() {
if (!loadcell_1_rdy) loadcell_1_rdy = LoadCell_1.startMultiple(stabilisingtime);
if (!loadcell_2_rdy) loadcell_2_rdy = LoadCell_2.startMultiple(stabilisingtime);
}
if (LoadCell_1.getTareTimeoutFlag()) {
Serial.println("Tare timeout, check MCU>HX711 no.1 wiring and pin designations");
}
if (LoadCell_2.getTareTimeoutFlag()) {
Serial.println("Tare timeout, check MCU>HX711 no.2 wiring and pin designations");
}
LoadCell_1.setCalFactor(calValue_1); // user set calibration value (float)
LoadCell_2.setCalFactor(calValue_2); // user set calibration value (float)
Serial.println("Startup + tare is complete");
Expand Down
Binary file added extra/hx711_ADC data sheet v2_0.pdf
Binary file not shown.
2 changes: 2 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ powerUp KEYWORD2
getTareOffset KEYWORD2
getTareStatus KEYWORD2
setTareOffset KEYWORD2
setSamplesInUse KEYWORD2
getSamplesInUse KEYWORD2

#######################################
# Constants (LITERAL1)
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=HX711_ADC
version=1.1.4
version=1.1.5
author=Olav Kallhovd
maintainer=Olav Kallhovd
sentence=Arduino library for the HX711 24-bit ADC for weight scales
Expand Down
129 changes: 101 additions & 28 deletions src/HX711_ADC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ void HX711_ADC::begin(uint8_t gain)
int HX711_ADC::start(unsigned int t)
{
t += 400;
while(millis() < t) {
while(millis() < t)
{
getData();
yield();
}
Expand All @@ -58,13 +59,17 @@ int HX711_ADC::start(unsigned int t)
* Running this for 1-5s before tare() seems to improve the tare accuracy */
int HX711_ADC::startMultiple(unsigned int t)
{
tareTimeoutFlag = 0;
static unsigned long timeout = millis() + tareTimeOut;
if(startStatus == 0) {
if(isFirst) {
startMultipleTimeStamp = millis();

if (t < 400) {
startMultipleWaitTime = t + 400; //min time for HX711 to be stable
} else {
if (t < 400)
{
startMultipleWaitTime = t + 400; //min time for HX711 to be stable
}
else
{
startMultipleWaitTime = t;
}
isFirst = 0;
Expand All @@ -77,11 +82,20 @@ int HX711_ADC::startMultiple(unsigned int t)
else { //do tare after stabilization time is up
doTare = 1;
update();
if(convRslt == 2) {
if(convRslt == 2)
{
doTare = 0;
convRslt = 0;
startStatus = 1;
}
if (!tareTimeoutDisable)
{
if (millis() > timeout)
{
tareTimeoutFlag = 1;
return 1; // Prevent endless loop if no HX711 is connected
}
}
}
}
return startStatus;
Expand All @@ -94,10 +108,13 @@ void HX711_ADC::tare()
tareTimes = 0;
tareTimeoutFlag = 0;
unsigned long timeout = millis() + tareTimeOut;
while(rdy != 2) {
while(rdy != 2)
{
rdy = update();
if (!tareTimeoutDisable) {
if (millis() > timeout) {
if (!tareTimeoutDisable)
{
if (millis() > timeout)
{
tareTimeoutFlag = 1;
break; // Prevent endless loop if no HX711 is connected
}
Expand Down Expand Up @@ -136,7 +153,8 @@ float HX711_ADC::getCalFactor() //raw data is divided by this value to convert t
uint8_t HX711_ADC::update()
{
byte dout = digitalRead(doutPin); //check if conversion is ready
if (!dout) {
if (!dout)
{
conversion24bit();
//if(s) Serial.print(s);
}
Expand All @@ -146,10 +164,13 @@ uint8_t HX711_ADC::update()

float HX711_ADC::getData() // return fresh data from the moving average data set
{
long k = 0;
//long k = 0;
long data = 0;
data = smoothedData() - tareOffset;
data = (data >> divBit);
//data = smoothedData() - tareOffset;
lastSmoothedData = smoothedData();
data = (lastSmoothedData >> divBit) - tareOffset ;
//data = (data >> divBit);

float x = (float)data / calFactor;
return x;
}
Expand All @@ -159,7 +180,9 @@ long HX711_ADC::smoothedData()
long data = 0;
long L = 0xFFFFFF;
long H = 0x00;
for (uint8_t r = 0; r < DATA_SET; r++) {
//for (uint8_t r = 0; r < DATA_SET; r++) {
for (uint8_t r = 0; r < (samplesInUse + IGN_HIGH_SAMPLE + IGN_LOW_SAMPLE); r++)
{
if (L > dataSampleSet[r]) L = dataSampleSet[r]; // find lowest value
if (H < dataSampleSet[r]) H = dataSampleSet[r]; // find highest value
data += dataSampleSet[r];
Expand All @@ -176,35 +199,48 @@ uint8_t HX711_ADC::conversion24bit() //read 24 bit data and start the next conv
unsigned long data = 0;
uint8_t dout;
convRslt = 0;
for (uint8_t i = 0; i < (24 + GAIN); i++) { //read 24 bit data + set gain and start next conversion
delayMicroseconds(1); // required for faster mcu's?
if(SCK_DISABLE_INTERRUPTS) noInterrupts();
for (uint8_t i = 0; i < (24 + GAIN); i++)
{ //read 24 bit data + set gain and start next conversion
if(SCK_DELAY) delayMicroseconds(1); // could be required for faster mcu's, set value in config.h
digitalWrite(sckPin, 1);
delayMicroseconds(1);
if (i < (24)) {
if(SCK_DELAY) delayMicroseconds(1); // could be required for faster mcu's, set value in config.h
if (i < (24))
{
dout = digitalRead(doutPin);
data = data << 1;
if (dout) {
data++;
if (dout)
{
data++;
}
}
digitalWrite(sckPin, 0);
}
if(SCK_DISABLE_INTERRUPTS) interrupts();
data = data ^ 0x800000; // if out of range (min), change to 0
if (readIndex == DATA_SET - 1) {
//if (readIndex == DATA_SET - 1) {
if (readIndex == samplesInUse + IGN_HIGH_SAMPLE + IGN_LOW_SAMPLE - 1)
{
readIndex = 0;
}
else {
else
{
readIndex++;
}
if(data > 0) {
if(data > 0)
{
convRslt++;
dataSampleSet[readIndex] = (long)data;
if(doTare) {
if (tareTimes < DATA_SET) {
tareTimes++;
if(doTare)
{
if (tareTimes < DATA_SET)
{
tareTimes++;
}
else {
tareOffset = smoothedData();
else
{
//tareOffset = smoothedData();
tareOffset = (smoothedData() >> divBit);
tareTimes = 0;
doTare = 0;
tareStatus = 1;
Expand Down Expand Up @@ -279,3 +315,40 @@ long HX711_ADC::getSettlingTime()
return st;
}

//overide the number of samples in use
//value is rounded down to the nearest valid value
void HX711_ADC::setSamplesInUse(int samples)
{
int old_value = samplesInUse;
int old_divbit = divBit;

if(samples <= SAMPLES)
{
if(samples == 0) {samplesInUse = SAMPLES; divBit = divBitCompiled;} //reset to the original value
else if(samples == 1) {samplesInUse = 1; divBit = 0;}
else if((samples > 1) && (samples < 4)) {samplesInUse = 2; divBit = 1;}
else if((samples >= 4) && (samples < 8)) {samplesInUse = 4; divBit = 2;}
else if((samples >= 8) && (samples < 16)) {samplesInUse = 8; divBit = 3;}
else if((samples >= 16) && (samples < 32)) {samplesInUse = 16; divBit = 4;}
else if((samples >= 32) && (samples < 64)) {samplesInUse = 32; divBit = 5;}
else if((samples >= 64) && (samples < 128)) {samplesInUse = 64; divBit = 6;}
else {samplesInUse = 128; divBit = 7;}

//replace the value of all samples in use with the last conversion value
if(samplesInUse != old_value)
{
for (uint8_t r = 0; r < samplesInUse + IGN_HIGH_SAMPLE + IGN_LOW_SAMPLE; r++)
{
dataSampleSet[r] = (lastSmoothedData >> old_divbit);
}
readIndex = 0;
}
}
}

//returns the current number of samples in use.
int HX711_ADC::getSamplesInUse()
{
return samplesInUse;
}

18 changes: 13 additions & 5 deletions src/HX711_ADC.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Note: HX711_ADC configuration values has been moved to file config.h

#define DATA_SET SAMPLES + IGN_HIGH_SAMPLE + IGN_LOW_SAMPLE // total samples in memory

#if (SAMPLES != 1) & (SAMPLES != 4) & (SAMPLES != 8) & (SAMPLES != 16) & (SAMPLES != 32) & (SAMPLES != 64) & (SAMPLES != 128)
#if (SAMPLES != 1) & (SAMPLES != 2) & (SAMPLES != 4) & (SAMPLES != 8) & (SAMPLES != 16) & (SAMPLES != 32) & (SAMPLES != 64) & (SAMPLES != 128)
#error "number of SAMPLES not valid!"
#endif

Expand All @@ -28,6 +28,8 @@ Note: HX711_ADC configuration values has been moved to file config.h

#if (SAMPLES == 1)
#define DIVB 0
#elif (SAMPLES == 2)
#define DIVB 1
#elif (SAMPLES == 4)
#define DIVB 2
#elif (SAMPLES == 8)
Expand All @@ -46,11 +48,11 @@ class HX711_ADC
{

public:
HX711_ADC(uint8_t dout, uint8_t sck); //constructor
HX711_ADC(uint8_t dout, uint8_t sck); //constructor
void setGain(uint8_t gain = 128); //value should be 32, 64 or 128*
void begin();
void begin(uint8_t gain);
int start(unsigned int t); // start and tare one HX711
int start(unsigned int t); // start and tare one HX711
int startMultiple(unsigned int t); //start and tare multiple HX711 simultaniously
void tare(); // zero the scale, wait for tare to finnish
void tareNoDelay(); // zero the scale, do tare in loop without waiting for tare to finnish
Expand All @@ -69,6 +71,8 @@ class HX711_ADC
long getTareOffset();
void setTareOffset(long newoffset);
uint8_t update(); //if conversion is ready; read out 24 bit data and add to data set
void setSamplesInUse(int samples); //overide number of samples in use
int getSamplesInUse(); //returns current number of samples in use

protected:
uint8_t conversion24bit(); //if conversion is ready: returns 24 bit data and starts the next conversion
Expand All @@ -84,7 +88,8 @@ class HX711_ADC
unsigned long conversionTime;
uint8_t isFirst = 1;
uint8_t tareTimes;
const uint8_t divBit = DIVB;
uint8_t divBit = DIVB;
const uint8_t divBitCompiled = DIVB;
bool doTare;
bool startStatus;
long startMultipleTimeStamp;
Expand All @@ -94,7 +99,10 @@ class HX711_ADC
unsigned int tareTimeOut = (SAMPLES + IGN_HIGH_SAMPLE + IGN_HIGH_SAMPLE) * 150; // tare timeout time in ms, no of samples * 150ms (10SPS + 50% margin)
bool tareTimeoutFlag;
bool tareTimeoutDisable = 0;
int samplesInUse = SAMPLES;
long lastSmoothedData;

};

#endif


23 changes: 17 additions & 6 deletions src/config.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
/*
HX711_ADC configuration
Allowed values for "SAMPLES" is 4, 8, 16, 32 or 64.
Allowed values for "SAMPLES" is 1, 2, 4, 8, 16, 32, 64 or 128.
Higher value = improved filtering/smoothing of returned value, but longer setteling time and increased memory usage
Lower value = visa versa
The settling time can be calculated as follows:
Settling time = SAMPLES + IGN_HIGH_SAMPLE + IGN_LOW_SAMPLE / SPS
Example on calculating settling time using the values SAMPLES = 16, IGN_HIGH_SAMPLE = 1, IGN_LOW_SAMPLE = 1, and HX711 sample rate set to 10SPS:
(16+1+1)/10 = 1.8 seconds settling time
(16+1+1)/10 = 1.8 seconds settling time.
Note that you can also overide (reducing) the number of samples in use at any time with the function: setSamplesInUse(samples).
*/

#define SAMPLES 16 // no of samples in moving average data set, value must be 4, 8, 16, 32 or 64
#define IGN_HIGH_SAMPLE 1 // adds one sample to the set and ignore peak high sample, value must be 0 or 1
#define IGN_LOW_SAMPLE 1 // adds one sample to the set and ignore peak low sample, value must be 0 or 1
//number of samples in moving average data set, value must be 1, 2, 4, 8, 16, 32, 64 or 128.
#define SAMPLES 16 //default value: 16

//adds extra sample(s) to the data set and ignore peak high/low sample, value must be 0 or 1.
#define IGN_HIGH_SAMPLE 1 //default value: 1
#define IGN_LOW_SAMPLE 1 //default value: 1

//1 microsecond delay after writing sck pin high or low. Could be required for faster mcu's (but both the Arduino Due and ESP8266 seems to run fine without this delay)
//Change the value to '1' if delay is required.
#define SCK_DELAY 0 //default value: 0

//Note: If you for some reason want to read out single conversions only, SAMPLES can be set to 1 provided that both IGN_HIGH_SAMPLE and IGN_LOW_SAMPLE is set to 0
//if you have some other time consuming (>60μs) interrupt routines that trigger while the sck pin is high, this could unintentionally set the HX711 into "power down" mode
//if required you can change the value to '1' to disable interrupts when writing to the sck pin.
#define SCK_DISABLE_INTERRUPTS 0 //default value: 0

0 comments on commit e390258

Please sign in to comment.