From 76830802129035d0d4a00b2d57ed587d9830c5c2 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Tue, 16 Nov 2021 17:39:29 +0100 Subject: [PATCH] Develop (#12) * fix #11 shiftIn() timing of clock pulses (breaking change) * update readme * improved readability --- HX711.cpp | 44 ++++++++-- HX711.h | 7 +- README.md | 82 +++++++++++-------- examples/HX_delta_scale/HX_delta_scale.ino | 13 ++- .../HX_grocery_scale/HX_grocery_scale.ino | 6 +- .../HX_kitchen_scale/HX_kitchen_scale.ino | 9 +- examples/HX_performance/HX_performance.ino | 17 +++- examples/HX_performance2/HX_performance2.ino | 11 ++- examples/HX_plotter/HX_plotter.ino | 11 ++- examples/HX_read_median/HX_read_median.ino | 10 ++- .../HX_read_median_average.ino | 5 ++ examples/HX_set_mode/HX_set_mode.ino | 5 ++ keywords.txt | 2 + library.json | 2 +- library.properties | 2 +- test/unit_test_001.cpp | 1 + 16 files changed, 165 insertions(+), 62 deletions(-) diff --git a/HX711.cpp b/HX711.cpp index 7706599..149bf1b 100644 --- a/HX711.cpp +++ b/HX711.cpp @@ -1,7 +1,7 @@ // // FILE: HX711.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.2.3 +// VERSION: 0.3.0 // PURPOSE: Library for Loadcells for UNO // URL: https://github.com/RobTillaart/HX711 // @@ -12,6 +12,9 @@ // 0.2.1 2020-12-28 add arduino-ci + unit test // 0.2.2 2021-05-10 add read_median(), fix typo, add mode operandi // 0.2.3 2021-05-26 add running_average() mode +// 0.3.0 2021-11-14 fix #11 shiftIn timing +// update build-CI, readme.md, badges + #include "HX711.h" @@ -28,7 +31,7 @@ HX711::~HX711() {} void HX711::begin(uint8_t dataPin, uint8_t clockPin) { - _dataPin = dataPin; + _dataPin = dataPin; _clockPin = clockPin; pinMode(_dataPin, INPUT); @@ -55,6 +58,11 @@ bool HX711::is_ready() } +// from datasheet page 4 +// When output data is not ready for retrieval, +// digital output pin DOUT is high. Serial clock +// input PD_SCK should be low. When DOUT goes +// to low, it indicates data is ready for retrieval. float HX711::read() { // this waiting takes most time... @@ -69,9 +77,12 @@ float HX711::read() noInterrupts(); // Pulse the clock pin 24 times to read the data. - v.data[2] = shiftIn(_dataPin, _clockPin, MSBFIRST); - v.data[1] = shiftIn(_dataPin, _clockPin, MSBFIRST); - v.data[0] = shiftIn(_dataPin, _clockPin, MSBFIRST); + // v.data[2] = shiftIn(_dataPin, _clockPin, MSBFIRST); + // v.data[1] = shiftIn(_dataPin, _clockPin, MSBFIRST); + // v.data[0] = shiftIn(_dataPin, _clockPin, MSBFIRST); + v.data[2] = _shiftIn(); + v.data[1] = _shiftIn(); + v.data[0] = _shiftIn(); // TABLE 3 page 4 datasheet // only default verified, so other values not supported yet @@ -271,4 +282,27 @@ void HX711::power_up() digitalWrite(_clockPin, LOW); } + +// MSB_FIRST optimized shiftIn +// see datasheet page 5 for timing +uint8_t HX711::_shiftIn() +{ + uint8_t value = 0; + uint8_t mask = 0x80; + while(mask > 0) + { + digitalWrite(_clockPin, HIGH); + delayMicroseconds(1); // T2 >= 0.2 us + if (digitalRead(_dataPin) == HIGH) + { + value |= mask; + } + digitalWrite(_clockPin, LOW); + delayMicroseconds(1); // keep duty cycle ~50% + mask >>= 1; + } + return value; +} + + // -- END OF FILE -- diff --git a/HX711.h b/HX711.h index aca3c00..a23287c 100644 --- a/HX711.h +++ b/HX711.h @@ -2,7 +2,7 @@ // // FILE: HX711.h // AUTHOR: Rob Tillaart -// VERSION: 0.2.3 +// VERSION: 0.3.0 // PURPOSE: Library for Loadcells for UNO // URL: https://github.com/RobTillaart/HX711 // @@ -15,7 +15,7 @@ #include "Arduino.h" -#define HX711_LIB_VERSION (F("0.2.3")) +#define HX711_LIB_VERSION (F("0.3.0")) const uint8_t HX711_AVERAGE_MODE = 0x00; @@ -39,7 +39,7 @@ class HX711 void reset(); - // checks if loadcell is ready to read. + // checks if load cell is ready to read. bool is_ready(); // wait until ready, @@ -142,6 +142,7 @@ class HX711 uint8_t _mode = 0; void _insertSort(float * array, uint8_t size); + uint8_t _shiftIn(); }; // -- END OF FILE -- diff --git a/README.md b/README.md index 3157f15..5eaed84 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ # HX711 -Arduino library for HX711 24 bit ADC used for load cells and scales. +Arduino library for HX711 24 bit ADC used for load cells and scales. ## Description @@ -21,6 +21,21 @@ The 23 bits mantissa of the IEE754 float matches the 24 bit ADC very well. Furthermore it gave a smaller footprint. +### Breaking change 0.3.0 + +In issue #11 it became clear that the timing of the default **shiftIn()** function that +reads the value of the internal ADC was too fast on some processor boards for the HX711. +This resulted in missing the first = sign bit and value read could be a factor two +higher than should. If one calibrated the sensor this would be compensated with the +factor that is derived in the calibration process. + +In 0.3.0 a dedicated **shiftIn()** function is added into this library that uses hard +coded delays to keep the timing of the clock within datasheet parameters. +This should guarantee that the sign bit is read correctly on all platforms. +Drawback is that reading the HX711 takes an ~50 extra microseconds. +How much this affects performance is to be investigated. + + ## Main flow First action is to call **begin(dataPin, clockPin)** to make connection to the **HX711**. @@ -44,11 +59,11 @@ Steps to take for calibration #### Base -- **HX711()** constructor +- **HX711()** constructor. - **~HX711()** - **void begin(uint8_t dataPin, uint8_t clockPin)** sets a fixed gain 128 for now. -- **void reset()** -- **bool is_ready()** checks if load-cell is ready to read. +- **void reset()** set internal state to start condition. +- **bool is_ready()** checks if load cell is ready to read. - **void wait_ready(uint32_t ms = 0)** wait until ready, check every ms. - **bool wait_ready_retry(uint8_t retries = 3, uint32_t ms = 0)** wait max retries. - **bool wait_ready_timeout(uint32_t timeout = 1000, uint32_t ms = 0)** wait max timeout. @@ -66,7 +81,8 @@ The weight alpha can be set to any value between 0 and 1, times >= 1. #### Gain read datasheet - see also Connections HX711 below -- **void set_gain(uint8_t gain = 128)** values: 128 (default), 64 32 - only 128 tested & verified + +- **void set_gain(uint8_t gain = 128)** values: 128 (default), 64 32 - only 128 tested & verified. - **uint8_t get_gain()** returns set gain. @@ -78,10 +94,10 @@ In median and medavg mode only 3..15 samples are allowed. - **void set_median_mode()** - **void set_medavg_mode()** - **void set_runavg_mode()** default alpha = 0.5. -- **uint8_t get_mode()** +- **uint8_t get_mode()** -#### GET VALUES +#### Get values get values corrected for offset and scale @@ -93,7 +109,7 @@ get values corrected for offset and scale - **long get_offset()** idem. -#### TARE & CALIBRATION +#### Tare & calibration Steps to take for calibration 1. clear the scale @@ -109,7 +125,7 @@ Steps to take for calibration - **void calibrate_scale(uint16_t weight, uint8_t times = 10)** idem. -#### POWER MANAGEMENT +#### Power management - **void power_down()** idem. - **void power_up()** idem. @@ -130,13 +146,13 @@ For weight conversion functions see https://github.com/RobTillaart/weight ## Notes -### Scale values for loadcells +### Scale values for load cells -These scale values worked pretty well with a set of load-cells, -Use calibrate to find your values. +These scale values worked pretty well with a set of load cells I have, +Use calibrate to find your favourite values. -- 5 KG loadcell scale.set_scale(420.52); -- 20 KG loadcell scale.set_scale(127.15); +- 5 KG load cell scale.set_scale(420.52); +- 20 KG load cell scale.set_scale(127.15); ### Connections HX711 @@ -147,29 +163,30 @@ Use calibrate to find your values. ### Connections -| HX711 Pin | Color | -|:----:|:----:| -| E+ | red | -| E- | black | -| A- | white | -| A+ | green | -| B- | not connected | -| B+ | not connected | +| HX711 Pin | Colour | +|:---------:|:--------------:| +| E+ | red | +| E- | black | +| A- | white | +| A+ | green | +| B- | not connected | +| B+ | not connected | -| HX711 Pin | Color | -|:----:|:----:| -| E+ | red | -| E- | black | -| A- | blue | -| A+ | white | -| B- | not connected | -| B+ | not connected | +| HX711 Pin | Colour | +|:---------:|:--------------:| +| E+ | red | +| E- | black | +| A- | blue | +| A+ | white | +| B- | not connected | +| B+ | not connected | ### Temperature -Load-cells do have a temperature related error. (check datasheet) + +Load cells do have a temperature related error. (check datasheet) This can be reduced by doing the calibration and take the tare at the temperature one also uses for the measurements. @@ -187,7 +204,8 @@ See examples - update documentation - add examples -- test different load-cells +- test different load cells +- optimize the build-in **ShiftIn()** function to improve performance again. #### the adding scale diff --git a/examples/HX_delta_scale/HX_delta_scale.ino b/examples/HX_delta_scale/HX_delta_scale.ino index 2468b84..487484e 100644 --- a/examples/HX_delta_scale/HX_delta_scale.ino +++ b/examples/HX_delta_scale/HX_delta_scale.ino @@ -9,6 +9,7 @@ // 0.1.0 2020-06-16 initial version // + // to be tested #include "HX711.h" @@ -20,6 +21,7 @@ uint8_t clockPin = 7; float w1, w2, previous = 0; + void setup() { Serial.begin(115200); @@ -33,16 +35,17 @@ void setup() Serial.print("UNITS: "); Serial.println(scale.get_units(10)); - // loadcell factor 20 KG + // load cell factor 20 KG // scale.set_scale(127.15); - // loadcell factor 5 KG - scale.set_scale(420.0983); + // load cell factor 5 KG + scale.set_scale(420.0983); // TODO you need to calibrate this yourself. scale.tare(); Serial.print("UNITS: "); Serial.println(scale.get_units(10)); } + void loop() { // read until stable @@ -71,4 +74,6 @@ void loop() delay(100); } -// END OF FILE + +// -- END OF FILE -- + diff --git a/examples/HX_grocery_scale/HX_grocery_scale.ino b/examples/HX_grocery_scale/HX_grocery_scale.ino index 049d27c..6c9bdbe 100644 --- a/examples/HX_grocery_scale/HX_grocery_scale.ino +++ b/examples/HX_grocery_scale/HX_grocery_scale.ino @@ -9,6 +9,7 @@ // 0.1.0 2020-06-16 initial version // + #include "HX711.h" HX711 scale; @@ -54,6 +55,7 @@ void setup() scale.set_unit_price(0.031415); // we only have one price } + void loop() { Serial.print("UNITS: "); @@ -63,4 +65,6 @@ void loop() delay(250); } -// END OF FILE \ No newline at end of file + +// -- END OF FILE -- + diff --git a/examples/HX_kitchen_scale/HX_kitchen_scale.ino b/examples/HX_kitchen_scale/HX_kitchen_scale.ino index 1a92347..ea36eea 100644 --- a/examples/HX_kitchen_scale/HX_kitchen_scale.ino +++ b/examples/HX_kitchen_scale/HX_kitchen_scale.ino @@ -9,6 +9,7 @@ // 0.1.0 2020-06-16 initial version // + #include "HX711.h" HX711 scale; @@ -48,11 +49,13 @@ void setup() Serial.println(scale.get_units(10)); Serial.println("\nScale is calibrated, press a key to continue"); + // Serial.println(scale.get_scale()); + // Serial.println(scale.get_offset()); while(!Serial.available()); while(Serial.available()) Serial.read(); - } + void loop() { Serial.print("UNITS: "); @@ -60,4 +63,6 @@ void loop() delay(250); } -// END OF FILE + +// -- END OF FILE -- + diff --git a/examples/HX_performance/HX_performance.ino b/examples/HX_performance/HX_performance.ino index 580d69d..340eb2c 100644 --- a/examples/HX_performance/HX_performance.ino +++ b/examples/HX_performance/HX_performance.ino @@ -9,6 +9,7 @@ // 0.1.0 2020-06-15 initial version // + #include "HX711.h" HX711 scale; @@ -19,6 +20,7 @@ uint8_t clockPin = 7; uint32_t start, stop; volatile float f; + void setup() { Serial.begin(115200); @@ -34,11 +36,11 @@ void setup() measure(10); // TODO find a nice solution for this calibration.. - // loadcell factor 20 KG + // load cell factor 20 KG // scale.set_scale(127.15); - // loadcell factor 5 KG - scale.set_scale(420.0983); + // load cell factor 5 KG + scale.set_scale(420.0983); // TODO you need to calibrate this yourself. // reset the scale to zero = 0 scale.tare(); @@ -54,6 +56,11 @@ void setup() delay(1000); measure(10); +/* + * PERFORMANCE + * 100x get_units(1) = 9404352 (UNO) + * VAL: 0.05 + */ Serial.println("\nPERFORMANCE"); start = micros(); f = 0; @@ -75,9 +82,9 @@ void setup() } Serial.print(" VAL:"); Serial.println(f * 0.01, 4); - } + void loop() { // continuous scale 4x per second @@ -86,6 +93,7 @@ void loop() delay(250); } + void measure(uint8_t cnt) { Serial.print(" RAW: "); @@ -100,3 +108,4 @@ void measure(uint8_t cnt) // -- END OF FILE -- + diff --git a/examples/HX_performance2/HX_performance2.ino b/examples/HX_performance2/HX_performance2.ino index 553bdd8..bbd11bb 100644 --- a/examples/HX_performance2/HX_performance2.ino +++ b/examples/HX_performance2/HX_performance2.ino @@ -9,6 +9,7 @@ // 0.1.0 2020-06-15 initial version // + #include "HX711.h" HX711 scale; @@ -19,6 +20,7 @@ uint8_t clockPin = 7; uint32_t start, stop; volatile float f; + void setup() { Serial.begin(115200); @@ -30,21 +32,23 @@ void setup() scale.begin(dataPin, clockPin); // TODO find a nice solution for this calibration.. - // loadcell factor 20 KG + // load cell factor 20 KG // scale.set_scale(127.15); - // loadcell factor 5 KG - scale.set_scale(420.0983); + // load cell factor 5 KG + scale.set_scale(420.0983); // TODO you need to calibrate this yourself. // reset the scale to zero = 0 scale.tare(); measure(); } + void loop() { } + void measure() { Serial.println("Counting get_units() calls for 1 minute..."); @@ -66,3 +70,4 @@ void measure() // -- END OF FILE -- + diff --git a/examples/HX_plotter/HX_plotter.ino b/examples/HX_plotter/HX_plotter.ino index 6f1fec6..5da9366 100644 --- a/examples/HX_plotter/HX_plotter.ino +++ b/examples/HX_plotter/HX_plotter.ino @@ -9,6 +9,7 @@ // 0.1.0 2020-06-15 initial version // + #include "HX711.h" HX711 scale; @@ -19,6 +20,7 @@ uint8_t clockPin = 7; uint32_t start, stop; volatile float f; + void setup() { Serial.begin(115200); @@ -30,14 +32,15 @@ void setup() scale.begin(dataPin, clockPin); // TODO find a nice solution for this calibration.. - // loadcell factor 20 KG + // load cell factor 20 KG // scale.set_scale(127.15); - // loadcell factor 5 KG - scale.set_scale(420.0983); + // load cell factor 5 KG + scale.set_scale(420.0983); // TODO you need to calibrate this yourself. // reset the scale to zero = 0 scale.tare(); } + void loop() { // continuous scale 4x per second @@ -46,4 +49,6 @@ void loop() delay(250); } + // -- END OF FILE -- + diff --git a/examples/HX_read_median/HX_read_median.ino b/examples/HX_read_median/HX_read_median.ino index 74914f0..35e0068 100644 --- a/examples/HX_read_median/HX_read_median.ino +++ b/examples/HX_read_median/HX_read_median.ino @@ -9,6 +9,7 @@ // 0.1.0 2021-05-10 initial version // + #include "HX711.h" HX711 scale; @@ -19,6 +20,7 @@ uint8_t clockPin = 7; uint32_t start, stop; volatile float f; + void setup() { Serial.begin(115200); @@ -30,10 +32,10 @@ void setup() scale.begin(dataPin, clockPin); // TODO find a nice solution for this calibration.. - // loadcell factor 20 KG - scale.set_scale(127.15); + // load cell factor 20 KG + scale.set_scale(127.15); // TODO you need to calibrate this yourself. - // loadcell factor 5 KG + // load cell factor 5 KG // scale.set_scale(420.0983); // reset the scale to zero = 0 scale.tare(); @@ -52,6 +54,7 @@ void setup() Serial.println(f, 2); } + void loop() { // continuous scale once per second @@ -62,3 +65,4 @@ void loop() // -- END OF FILE -- + diff --git a/examples/HX_read_median_average/HX_read_median_average.ino b/examples/HX_read_median_average/HX_read_median_average.ino index 027460b..6c5b807 100644 --- a/examples/HX_read_median_average/HX_read_median_average.ino +++ b/examples/HX_read_median_average/HX_read_median_average.ino @@ -9,6 +9,7 @@ // 0.1.0 2021-05-13 initial version // + #include "HX711.h" HX711 scale; @@ -19,6 +20,7 @@ uint8_t clockPin = 7; uint32_t start, stop; volatile float f; + void setup() { Serial.begin(115200); @@ -52,6 +54,7 @@ void setup() Serial.println(f, 2); } + void loop() { // continuous scale once per second @@ -60,4 +63,6 @@ void loop() delay(1000); } + // -- END OF FILE -- + diff --git a/examples/HX_set_mode/HX_set_mode.ino b/examples/HX_set_mode/HX_set_mode.ino index 194f5f6..a894c00 100644 --- a/examples/HX_set_mode/HX_set_mode.ino +++ b/examples/HX_set_mode/HX_set_mode.ino @@ -9,6 +9,7 @@ // 0.1.0 2021-05-13 initial version // + #include "HX711.h" HX711 scale; @@ -19,6 +20,7 @@ uint8_t clockPin = 7; uint32_t start, stop; volatile float f; + void setup() { Serial.begin(115200); @@ -91,8 +93,11 @@ void setup() Serial.println("\ndone..."); } + void loop() { } + // -- END OF FILE -- + diff --git a/keywords.txt b/keywords.txt index 110a133..cc82a08 100644 --- a/keywords.txt +++ b/keywords.txt @@ -3,6 +3,7 @@ # Data types (KEYWORD1) HX711 KEYWORD1 + # Methods and Functions (KEYWORD2) begin KEYWORD2 reset KEYWORD2 @@ -50,6 +51,7 @@ get_price KEYWORD2 set_unit_price KEYWORD2 get_unit_price KEYWORD2 + # Instances (KEYWORD2) diff --git a/library.json b/library.json index 4373a3a..a28e935 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/HX711" }, - "version": "0.2.3", + "version": "0.3.0", "license": "MIT", "frameworks": "arduino", "platforms": "*" diff --git a/library.properties b/library.properties index fec8830..5212b35 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HX711 -version=0.2.3 +version=0.3.0 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for HX711 loadcell amplifier diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index 3d52d9b..e9f327d 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -53,6 +53,7 @@ unittest(test_constructor) assertEqual(0, scale.last_read()); } + unittest(test_gain) { HX711 scale;