Upload files to "libraries/HX711"

This commit is contained in:
2026-01-14 14:25:15 -05:00
parent dd68f6ee79
commit c2a0e716d9
4 changed files with 957 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
# Change Log HX711
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.6.3] - 2025-09-16
- fix #70, HX711 rate pin code
- fix #70, add a doReset parameter to begin() to improve start up time.
- update readme.md
- add details about start up time (related to RATE).
- add **isReady()** check in calibration
- add reference to ADAfruit breakout with RATE
- minor edits
## [0.6.2] - 2025-09-06
- fix #68, add bogde to the license, to give credit for the API
- implement experimental rate support.
- update keywords.txt
- update readme.md
- update the GitHub actions
- minor edits
## [0.6.1] - 2025-06-19
- fix #65, is_ready() => set dataPin to INPUT_PULLUP
- minor edits
## [0.6.0] - 2025-04-10
- fix #60, change parameter **void calibrate_scale(float weight, uint8_t times = 10)**
- update readme.md
----
## [0.5.2] - 2024-11-18
- fix #56, update readme.md
- add parameter default for **fastProcessor**
- add **last_time_read()** to replace **last_read()** in future.
- minor edits
## [0.5.1] - 2024-11-08
- fix #54, calibration sketch should output int32_t for offset.
- update examples
- update readme.md
- minor edits
## [0.5.0] - 2024-06-17
- fix #50, bug in constructor (thanks Mathieu!)
- refactor constructor
----
## [0.4.0] - 2024-03-02
- add fastProcessor option in **begin()** (Thanks to palmerr23)
- updated license
- updated GitHub/actions to v4
----
## [0.3.9] - 2023-11-04
- update readme.md
- minor edits
## [0.3.8] - 2023-08-26
- fix #41 #40 add example **HX_loadcell_array.ino**
- test support array of loadcells.
- update readme.md
- add issue-count badge
- add PlatformIO badge
- minor edits
## [0.3.7] - 2023-06-27
- add example to measure noise level
- moved code to .cpp
- reorder .cpp to match .h
- removed **callibrate_scale()** (typo ll)
- add scale == 0 in **set_scale(scale)**
- changed return type to **bool set_scale(scale)**
- add example is_ready
- add example pulse-length decoder (Morse)
- update readme.md
## [0.3.6] - 2023-03-11
- update readme.md to reference HX711_MP
## [0.3.5] - 2023-03-10
- update readme.md
- update GitHub actions
- update license 2023
- add MulitMap example
- minor edits
## [0.3.4] - 2022-11-11
- simplified changelog
- add RP2040 to build-CI
- refactored **set_gain()** to return bool to confirm valid parameter.
- add forced flag for set_gain to force a dummy read call. Default false.
- add constants for **set_gain()**
- improved unit test for **set_gain()**
- add unit test for constants.
- add delayMicroseconds(64) to power_down to enforce long enough HIGH signal.
- add power_down() power_up() cycle in **reset()**
- updated readme.md
- updated keywords.txt
## [0.3.3] - 2022-03-16
- add HX711_RAW_MODE
- update documentation
## [0.3.2] - 2022-03-16
- add example HX_set_persistent.ino. (won't work for m4)
- add CHANGELOG.md
- minor edits
## [0.3.1] - 2021-12-19
- update library.json
- license
- minor edits
## [0.3.0] - 2021-11-14
- update build-CI
- readme.md incl. badges
- fix #11 shiftIn timing
----
## [0.2.3] - 2021-05-26
- add running_average() mode
## [0.2.2] - 2021-05-10
- add read_median()
- add mode operandi
- fix typo
## [0.2.1] - 2020-12-28
- add arduino-ci
- unit test
## [0.2.0] - 2020-06-15
- add price functions
- some refactor
----
## [0.1.1] - 2019-09-09
- change long to float (reduce footprint)
## [0.1.0] - 2019-09-04
- initial version

512
libraries/HX711/HX711.cpp Normal file
View File

@@ -0,0 +1,512 @@
//
// FILE: HX711.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.6.3
// PURPOSE: Library for load cells for UNO
// URL: https://github.com/RobTillaart/HX711_MP
// URL: https://github.com/RobTillaart/HX711
#include "HX711.h"
HX711::HX711()
{
_offset = 0;
_scale = 1;
_gain = HX711_CHANNEL_A_GAIN_128;
_lastTimeRead = 0;
_mode = HX711_AVERAGE_MODE;
_fastProcessor = false;
_price = 0;
}
HX711::~HX711()
{
}
void HX711::begin(uint8_t dataPin, uint8_t clockPin, bool fastProcessor, bool doReset)
{
_dataPin = dataPin;
_clockPin = clockPin;
_fastProcessor = fastProcessor;
pinMode(_dataPin, INPUT_PULLUP);
pinMode(_clockPin, OUTPUT);
digitalWrite(_clockPin, LOW);
if (doReset)
{
reset();
}
}
void HX711::reset()
{
power_down();
power_up();
_offset = 0;
_scale = 1;
_gain = HX711_CHANNEL_A_GAIN_128;
_lastTimeRead = 0;
_mode = HX711_AVERAGE_MODE;
_price = 0;
}
bool HX711::is_ready()
{
return digitalRead(_dataPin) == LOW;
}
void HX711::wait_ready(uint32_t ms)
{
while (!is_ready())
{
delay(ms);
}
}
bool HX711::wait_ready_retry(uint8_t retries, uint32_t ms)
{
while (retries--)
{
if (is_ready()) return true;
delay(ms);
}
return false;
}
bool HX711::wait_ready_timeout(uint32_t timeout, uint32_t ms)
{
uint32_t start = millis();
while (millis() - start < timeout)
{
if (is_ready()) return true;
delay(ms);
}
return false;
}
///////////////////////////////////////////////////////////////
//
// READ
//
// 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.
// Blocking period can be long up to 400 ms in first read() call.
float HX711::read()
{
// this BLOCKING wait takes most time...
while (digitalRead(_dataPin) == HIGH)
{
yield();
}
union
{
int32_t value = 0;
uint8_t data[4];
} v;
// blocking part ...
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();
v.data[1] = _shiftIn();
v.data[0] = _shiftIn();
// TABLE 3 page 4 datasheet
//
// CLOCK CHANNEL GAIN m
// ------------------------------------
// 25 A 128 1 // default
// 26 B 32 2
// 27 A 64 3
//
// only default 128 verified,
// selection goes through the set_gain(gain)
//
uint8_t m = 1;
if (_gain == HX711_CHANNEL_A_GAIN_128) m = 1;
else if (_gain == HX711_CHANNEL_A_GAIN_64) m = 3;
else if (_gain == HX711_CHANNEL_B_GAIN_32) m = 2;
while (m > 0)
{
// delayMicroSeconds(1) is needed for fast processors
// T2 >= 0.2 us
digitalWrite(_clockPin, HIGH);
if (_fastProcessor) delayMicroseconds(1);
digitalWrite(_clockPin, LOW);
// keep duty cycle ~50%
if (_fastProcessor) delayMicroseconds(1);
m--;
}
interrupts();
// yield();
// SIGN extend
if (v.data[2] & 0x80) v.data[3] = 0xFF;
_lastTimeRead = millis();
return 1.0 * v.value;
}
float HX711::read_average(uint8_t times)
{
if (times < 1) times = 1;
float sum = 0;
for (uint8_t i = 0; i < times; i++)
{
sum += read();
yield();
}
return sum / times;
}
float HX711::read_median(uint8_t times)
{
if (times > 15) times = 15;
if (times < 3) times = 3;
float samples[15];
for (uint8_t i = 0; i < times; i++)
{
samples[i] = read();
yield();
}
_insertSort(samples, times);
if (times & 0x01) return samples[times/2];
return (samples[times/2] + samples[times/2 + 1]) / 2;
}
float HX711::read_medavg(uint8_t times)
{
if (times > 15) times = 15;
if (times < 3) times = 3;
float samples[15];
for (uint8_t i = 0; i < times; i++)
{
samples[i] = read();
yield();
}
_insertSort(samples, times);
float sum = 0;
// iterate over 1/4 to 3/4 of the array
uint8_t count = 0;
uint8_t first = (times + 2) / 4;
uint8_t last = times - first - 1;
for (uint8_t i = first; i <= last; i++) // !! include last one too
{
sum += samples[i];
count++;
}
return sum / count;
}
float HX711::read_runavg(uint8_t times, float alpha)
{
if (times < 1) times = 1;
if (alpha < 0) alpha = 0;
if (alpha > 1) alpha = 1;
float val = read();
for (uint8_t i = 1; i < times; i++)
{
val += alpha * (read() - val);
yield();
}
return val;
}
///////////////////////////////////////////////////////
//
// MODE
//
void HX711::set_raw_mode()
{
_mode = HX711_RAW_MODE;
}
void HX711::set_average_mode()
{
_mode = HX711_AVERAGE_MODE;
}
void HX711::set_median_mode()
{
_mode = HX711_MEDIAN_MODE;
}
void HX711::set_medavg_mode()
{
_mode = HX711_MEDAVG_MODE;
}
// set_run_avg will use a default alpha of 0.5.
void HX711::set_runavg_mode()
{
_mode = HX711_RUNAVG_MODE;
}
uint8_t HX711::get_mode()
{
return _mode;
}
float HX711::get_value(uint8_t times)
{
float raw;
switch(_mode)
{
case HX711_RAW_MODE:
raw = read();
break;
case HX711_RUNAVG_MODE:
raw = read_runavg(times);
break;
case HX711_MEDAVG_MODE:
raw = read_medavg(times);
break;
case HX711_MEDIAN_MODE:
raw = read_median(times);
break;
case HX711_AVERAGE_MODE:
default:
raw = read_average(times);
break;
}
return raw - _offset;
}
float HX711::get_units(uint8_t times)
{
float units = get_value(times) * _scale;
return units;
}
///////////////////////////////////////////////////////////////
//
// GAIN
//
// note: if parameter gain == 0xFF40 some compilers
// will map that to 0x40 == HX711_CHANNEL_A_GAIN_64;
// solution: use uint32_t or larger parameters everywhere.
// note that changing gain/channel may take up to 400 ms (page 3)
bool HX711::set_gain(uint8_t gain, bool forced)
{
if ( (not forced) && (_gain == gain)) return true;
switch(gain)
{
case HX711_CHANNEL_B_GAIN_32:
case HX711_CHANNEL_A_GAIN_64:
case HX711_CHANNEL_A_GAIN_128:
_gain = gain;
read(); // next user read() is from right channel / gain
return true;
}
return false; // unchanged, but incorrect value.
}
uint8_t HX711::get_gain()
{
return _gain;
}
///////////////////////////////////////////////////////
//
// TARE
//
void HX711::tare(uint8_t times)
{
_offset = read_average(times);
}
float HX711::get_tare()
{
return -_offset * _scale;
}
bool HX711::tare_set()
{
return _offset != 0;
}
///////////////////////////////////////////////////////////////
//
// CALIBRATION (tare see above)
//
bool HX711::set_scale(float scale)
{
if (scale == 0) return false;
_scale = 1.0 / scale;
return true;
}
float HX711::get_scale()
{
return 1.0 / _scale;
}
void HX711::set_offset(int32_t offset)
{
_offset = offset;
}
int32_t HX711::get_offset()
{
return _offset;
}
// assumes tare() has been set.
void HX711::calibrate_scale(float weight, uint8_t times)
{
_scale = weight / (read_average(times) - _offset);
}
///////////////////////////////////////////////////////////////
//
// POWER MANAGEMENT
//
void HX711::power_down()
{
// at least 60 us HIGH
digitalWrite(_clockPin, HIGH);
delayMicroseconds(64);
}
void HX711::power_up()
{
digitalWrite(_clockPin, LOW);
}
///////////////////////////////////////////////////////////////
//
// RATE PIN - works only if rate pin is exposed.
//
void HX711::set_rate_pin(uint8_t pin)
{
_ratePin = pin;
pinMode(_ratePin, OUTPUT);
set_rate_10SPS();
}
void HX711::set_rate_10SPS()
{
_rate = 10;
digitalWrite(_ratePin, LOW);
}
void HX711::set_rate_80SPS()
{
_rate = 80;
digitalWrite(_ratePin, HIGH);
}
uint8_t HX711::get_rate()
{
return _rate;
}
///////////////////////////////////////////////////////////////
//
// MISC
//
uint32_t HX711::last_time_read()
{
return _lastTimeRead;
}
///////////////////////////////////////////////////////////////
//
// PRIVATE
//
void HX711::_insertSort(float * array, uint8_t size)
{
uint8_t t, z;
float temp;
for (t = 1; t < size; t++)
{
z = t;
temp = array[z];
while( (z > 0) && (temp < array[z - 1] ))
{
array[z] = array[z - 1];
z--;
}
array[z] = temp;
yield();
}
}
// MSB_FIRST optimized shiftIn
// see datasheet page 5 for timing
uint8_t HX711::_shiftIn()
{
// local variables are faster.
uint8_t clk = _clockPin;
uint8_t data = _dataPin;
uint8_t value = 0;
uint8_t mask = 0x80;
while (mask > 0)
{
digitalWrite(clk, HIGH);
// T2 >= 0.2 us
if(_fastProcessor) delayMicroseconds(1);
if (digitalRead(data) == HIGH)
{
value |= mask;
}
digitalWrite(clk, LOW);
// keep duty cycle ~50%
if(_fastProcessor) delayMicroseconds(1);
mask >>= 1;
}
return value;
}
// -- END OF FILE --

215
libraries/HX711/HX711.h Normal file
View File

@@ -0,0 +1,215 @@
#pragma once
//
// FILE: HX711.h
// AUTHOR: Rob Tillaart
// VERSION: 0.6.3
// PURPOSE: Library for load cells for Arduino
// URL: https://github.com/RobTillaart/HX711_MP
// URL: https://github.com/RobTillaart/HX711
//
// NOTES
// Superset of interface of HX711 class of Bogde
// uses float instead of long as float has 23 bits mantissa
// which almost perfectly matches the 24 bit ADC.
#include "Arduino.h"
#define HX711_LIB_VERSION (F("0.6.3"))
const uint8_t HX711_AVERAGE_MODE = 0x00;
// in median mode only between 3 and 15 samples are allowed.
const uint8_t HX711_MEDIAN_MODE = 0x01;
// medavg = average of the middle "half" of sorted elements
// in medavg mode only between 3 and 15 samples are allowed.
const uint8_t HX711_MEDAVG_MODE = 0x02;
// runavg = running average
const uint8_t HX711_RUNAVG_MODE = 0x03;
// causes read() to be called only once!
const uint8_t HX711_RAW_MODE = 0x04;
// supported values for set_gain()
const uint8_t HX711_CHANNEL_A_GAIN_128 = 128; // default
const uint8_t HX711_CHANNEL_A_GAIN_64 = 64;
const uint8_t HX711_CHANNEL_B_GAIN_32 = 32;
class HX711
{
public:
HX711();
~HX711();
// fixed gain 128 for now
void begin(uint8_t dataPin, uint8_t clockPin,
bool fastProcessor = false,
bool doReset = true);
void reset();
// checks if load cell is ready to read.
// use this to prevent blocking reads, esp at startup, 1st read.
bool is_ready();
// wait until ready,
// check every ms
void wait_ready(uint32_t ms = 0);
// max # retries
bool wait_ready_retry(uint8_t retries = 3, uint32_t ms = 0);
// max timeout
bool wait_ready_timeout(uint32_t timeout = 1000, uint32_t ms = 0);
///////////////////////////////////////////////////////////////
//
// READ
//
// raw read, is blocking until device is ready to read().
// this blocking period can be long up to 400 ms in first read() call.
float read();
// get average of multiple raw reads
// times = 1 or more
float read_average(uint8_t times = 10);
// get median of multiple raw reads
// times = 3..15 - odd numbers preferred
float read_median(uint8_t times = 7);
// get average of "middle half" of multiple raw reads.
// times = 3..15 - odd numbers preferred
float read_medavg(uint8_t times = 7);
// get running average over times measurements.
// the weight alpha can be set to any value between 0 and 1
// times = 1 or more.
float read_runavg(uint8_t times = 7, float alpha = 0.5);
///////////////////////////////////////////////////////////////
//
// MODE
//
// get set mode for get_value() and indirect get_units().
// in median and medavg mode only 3..15 samples are allowed.
void set_raw_mode();
void set_average_mode();
void set_median_mode();
void set_medavg_mode();
// set_run_avg will use a default alpha of 0.5.
void set_runavg_mode();
uint8_t get_mode();
// corrected for offset.
// in HX711_RAW_MODE the parameter times will be ignored.
float get_value(uint8_t times = 1);
// converted to proper units, corrected for scale.
// in HX711_RAW_MODE the parameter times will be ignored.
float get_units(uint8_t times = 1);
///////////////////////////////////////////////////////////////
//
// GAIN
//
// CORE "CONSTANTS" -> read datasheet
// CHANNEL GAIN notes
// -------------------------------------
// A 128 default, tested
// A 64
// B 32
// returns true ==> parameter gain is valid
// returns false ==> parameter gain is invalid ==> no change.
// note that changing gain/channel takes up to 400 ms (page 3)
// if forced == true, the gain will be forced set
// even it is already the right value
bool set_gain(uint8_t gain = HX711_CHANNEL_A_GAIN_128, bool forced = false);
uint8_t get_gain();
///////////////////////////////////////////////////////////////
//
// TARE
// call tare to calibrate zero
void tare(uint8_t times = 10);
float get_tare();
bool tare_set();
///////////////////////////////////////////////////////////////
//
// CALIBRATION
//
// SCALE > 0
// returns false if scale == 0;
bool set_scale(float scale = 1.0);
float get_scale();
// OFFSET > 0
void set_offset(int32_t offset = 0);
int32_t get_offset();
// clear the scale
// call tare() to set the zero offset
// put a known weight on the scale
// call calibrate_scale(weight)
// scale is calculated.
void calibrate_scale(float weight, uint8_t times = 10);
///////////////////////////////////////////////////////////////
//
// POWER MANAGEMENT
//
void power_down();
void power_up();
///////////////////////////////////////////////////////////////
//
// EXPERIMENTAL
// RATE PIN - works only if rate pin is exposed.
//
void set_rate_pin(uint8_t pin);
void set_rate_10SPS();
void set_rate_80SPS();
uint8_t get_rate();
// TIME OF LAST READ
uint32_t last_time_read();
// obsolete in the future (0.7.0)
[[deprecated("Use last_time_read() instead.")]]
uint32_t last_read() { return last_time_read(); };
// PRICING
float get_price(uint8_t times = 1) { return get_units(times) * _price; };
void set_unit_price(float price = 1.0) { _price = price; };
float get_unit_price() { return _price; };
private:
uint8_t _dataPin;
uint8_t _clockPin;
int32_t _offset;
float _scale;
uint8_t _gain;
uint32_t _lastTimeRead;
uint8_t _mode;
bool _fastProcessor;
uint8_t _ratePin = 255;
uint8_t _rate = 10;
float _price;
void _insertSort(float * array, uint8_t size);
uint8_t _shiftIn();
};
// -- END OF FILE --

View File

@@ -0,0 +1,80 @@
# Syntax Colouring Map For HX711
# Data types (KEYWORD1)
HX711 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
reset KEYWORD2
is_ready KEYWORD2
wait_ready KEYWORD2
wait_ready_retry KEYWORD2
wait_ready_timeout KEYWORD2
read KEYWORD2
read_average KEYWORD2
read_median KEYWORD2
read_medavg KEYWORD2
read_runavg KEYWORD2
get_value KEYWORD2
get_units KEYWORD2
set_raw_mode KEYWORD2
set_average_mode KEYWORD2
set_median_mode KEYWORD2
set_medavg_mode KEYWORD2
set_runavg_mode KEYWORD2
get_mode KEYWORD2
tare KEYWORD2
get_tare KEYWORD2
tare_set KEYWORD2
set_gain KEYWORD2
get_gain KEYWORD2
# set_chanA_gain128 KEYWORD2
# set_chanA_gain64 KEYWORD2
# set_chanB_gain32 KEYWORD2
set_scale KEYWORD2
get_scale KEYWORD2
set_offset KEYWORD2
get_offset KEYWORD2
calibrate_scale KEYWORD2
power_down KEYWORD2
power_up KEYWORD2
set_rate_pin KEYWORD2
set_rate_10SPS KEYWORD2
set_rate_80SPS KEYWORD2
get_rate KEYWORD2
last_read KEYWORD2
get_price KEYWORD2
set_unit_price KEYWORD2
get_unit_price KEYWORD2
# Instances (KEYWORD2)
# Constants (LITERAL1)
HX711_LIB_VERSION LITERAL1
HX711_RAW_MODE LITERAL1
HX711_AVERAGE_MODE LITERAL1
HX711_MEDIAN_MODE LITERAL1
HX711_MEDAVG_MODE LITERAL1
HX711_RUNAVG_MODE LITERAL1
HX711_CHANNEL_A_GAIN_128 LITERAL1
HX711_CHANNEL_A_GAIN_64 LITERAL1
HX711_CHANNEL_B_GAIN_32 LITERAL1