├── setup.cfg
├── setup.py
├── README.md
├── LICENSE.txt
├── examples
└── scales.py
└── hx711.py
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | description-file = README.md
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import sys
2 | # Remove current dir from sys.path, otherwise setuptools will peek up our
3 | # module instead of system's.
4 | sys.path.pop(0)
5 | from setuptools import setup
6 | sys.path.append("..")
7 | import sdist_upip
8 |
9 |
10 | setup(
11 | cmdclass={'sdist': sdist_upip.sdist},
12 | name='micropython-hx711',
13 | py_modules=['hx711'],
14 | version='1.0.1',
15 | description='Micropython driver for the HX711',
16 | long_description='Micropython driver for the HX711 24-Bit Analog-to-Digital Converter',
17 | keywords=['micropython', 'hx711'],
18 | url='https://github.com/SergeyPiskunov/micropython-hx711',
19 | author='Sergey Piskunov',
20 | author_email='sergey.piskunoff@gmail.com',
21 | maintainer='Sergey Piskunov',
22 | maintainer_email='sergey.piskunoff@gmail.com',
23 | license='MIT',
24 | classifiers=[
25 | 'Development Status :: 4 - Beta',
26 | 'Programming Language :: Python :: Implementation :: MicroPython',
27 | 'License :: OSI Approved :: MIT License',
28 | ],
29 | )
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # micropython-hx711
2 | Micropython driver for the HX711 24-Bit Analog-to-Digital Converter
3 |
4 | Latest version supports:
5 | - retrieving data from the channel 'A' with gain 128 and 64,
6 | the channel 'B' with gain 32 in a raw form and a form
7 | converted from the two's complement.
8 | - sending "power off" sequence to switch device to the power-saving mode.
9 | - sending "power on" sequence with the gain saved before the "power off".
10 | - checking if the device is ready for the data retrieval.
11 |
12 | #### Example for the ESP8266:
13 | D_OUT pin is connected to the GPIO 5
14 | PD_SCK pin is connected to the GPIO 4
15 | Using internal HX711 oscillator, so ESP8266's frequency is set to 160000000
16 |
17 | ```
18 | >>> from machine import freq
19 | >>> freq(160000000)
20 | >>>
21 | >>> from hx711 import HX711
22 | >>>
23 | >>> driver = HX711(d_out=5, pd_sck=4)
24 | >>> driver
25 | HX711 on channel A, gain=128
26 | >>> driver.read()
27 | 74342
28 | >>>
29 | >>> driver.channel=HX711.CHANNEL_A_64
30 | >>> driver.channel
31 | ('A', 64)
32 | >>> driver.read()
33 | 36328
34 | >>>
35 | >>> driver.power_off()
36 | ```
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Sergey Piskunov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/scales.py:
--------------------------------------------------------------------------------
1 | from hx711 import HX711
2 | from utime import sleep_us
3 |
4 |
5 | class Scales(HX711):
6 | def __init__(self, d_out, pd_sck):
7 | super(Scales, self).__init__(d_out, pd_sck)
8 | self.offset = 0
9 |
10 | def reset(self):
11 | self.power_off()
12 | self.power_on()
13 |
14 | def tare(self):
15 | self.offset = self.read()
16 |
17 | def raw_value(self):
18 | return self.read() - self.offset
19 |
20 | def stable_value(self, reads=10, delay_us=500):
21 | values = []
22 | for _ in range(reads):
23 | values.append(self.raw_value())
24 | sleep_us(delay_us)
25 | return self._stabilizer(values)
26 |
27 | @staticmethod
28 | def _stabilizer(values, deviation=10):
29 | weights = []
30 | for prev in values:
31 | weights.append(sum([1 for current in values if abs(prev - current) / (prev / 100) <= deviation]))
32 | return sorted(zip(values, weights), key=lambda x: x[1]).pop()[0]
33 |
34 |
35 | if __name__ == "__main__":
36 | scales = Scales(d_out=5, pd_sck=4)
37 | scales.tare()
38 | val = scales.stable_value()
39 | print(val)
40 | scales.power_off()
41 |
--------------------------------------------------------------------------------
/hx711.py:
--------------------------------------------------------------------------------
1 | from utime import sleep_us, time
2 | from machine import Pin
3 | from micropython import const
4 |
5 |
6 | class HX711Exception(Exception):
7 | pass
8 |
9 |
10 | class InvalidMode(HX711Exception):
11 | pass
12 |
13 |
14 | class DeviceIsNotReady(HX711Exception):
15 | pass
16 |
17 |
18 | class HX711(object):
19 | """
20 | Micropython driver for Avia Semiconductor's HX711
21 | 24-Bit Analog-to-Digital Converter
22 | """
23 | CHANNEL_A_128 = const(1)
24 | CHANNEL_A_64 = const(3)
25 | CHANNEL_B_32 = const(2)
26 |
27 | DATA_BITS = const(24)
28 | MAX_VALUE = const(0x7fffff)
29 | MIN_VALUE = const(0x800000)
30 | READY_TIMEOUT_SEC = const(5)
31 | SLEEP_DELAY_USEC = const(80)
32 |
33 | def __init__(self, d_out: int, pd_sck: int, channel: int = CHANNEL_A_128):
34 | self.d_out_pin = Pin(d_out, Pin.IN)
35 | self.pd_sck_pin = Pin(pd_sck, Pin.OUT, value=0)
36 | self.channel = channel
37 |
38 | def __repr__(self):
39 | return "HX711 on channel %s, gain=%s" % self.channel
40 |
41 | def _convert_from_twos_complement(self, value: int) -> int:
42 | """
43 | Converts a given integer from the two's complement format.
44 | """
45 | if value & (1 << (self.DATA_BITS - 1)):
46 | value -= 1 << self.DATA_BITS
47 | return value
48 |
49 | def _set_channel(self):
50 | """
51 | Input and gain selection is controlled by the
52 | number of the input PD_SCK pulses
53 | 3 pulses for Channel A with gain 64
54 | 2 pulses for Channel B with gain 32
55 | 1 pulse for Channel A with gain 128
56 | """
57 | for i in range(self._channel):
58 | self.pd_sck_pin.value(1)
59 | self.pd_sck_pin.value(0)
60 |
61 | def _wait(self):
62 | """
63 | If the HX711 is not ready within READY_TIMEOUT_SEC
64 | the DeviceIsNotReady exception will be thrown.
65 | """
66 | t0 = time()
67 | while not self.is_ready():
68 | if time() - t0 > self.READY_TIMEOUT_SEC:
69 | raise DeviceIsNotReady()
70 |
71 | @property
72 | def channel(self) -> tuple:
73 | """
74 | Get current input channel in a form
75 | of a tuple (Channel, Gain)
76 | """
77 | if self._channel == self.CHANNEL_A_128:
78 | return 'A', 128
79 | if self._channel == self.CHANNEL_A_64:
80 | return 'A', 64
81 | if self._channel == self.CHANNEL_B_32:
82 | return 'B', 32
83 |
84 | @channel.setter
85 | def channel(self, value):
86 | """
87 | Set input channel
88 | HX711.CHANNEL_A_128 - Channel A with gain 128
89 | HX711.CHANNEL_A_64 - Channel A with gain 64
90 | HX711.CHANNEL_B_32 - Channel B with gain 32
91 | """
92 | if value not in (self.CHANNEL_A_128, self.CHANNEL_A_64, self.CHANNEL_B_32):
93 | raise InvalidMode('Gain should be one of HX711.CHANNEL_A_128, HX711.CHANNEL_A_64, HX711.CHANNEL_B_32')
94 | else:
95 | self._channel = value
96 |
97 | if not self.is_ready():
98 | self._wait()
99 |
100 | for i in range(self.DATA_BITS):
101 | self.pd_sck_pin.value(1)
102 | self.pd_sck_pin.value(0)
103 |
104 | self._set_channel()
105 |
106 | def is_ready(self) -> bool:
107 | """
108 | When output data is not ready for retrieval,
109 | digital output pin DOUT is high.
110 | """
111 | return self.d_out_pin.value() == 0
112 |
113 | def power_off(self):
114 | """
115 | When PD_SCK pin changes from low to high
116 | and stays at high for longer than 60 us ,
117 | HX711 enters power down mode.
118 | """
119 | self.pd_sck_pin.value(0)
120 | self.pd_sck_pin.value(1)
121 | sleep_us(self.SLEEP_DELAY_USEC)
122 |
123 | def power_on(self):
124 | """
125 | When PD_SCK returns to low, HX711 will reset
126 | and enter normal operation mode.
127 | """
128 | self.pd_sck_pin.value(0)
129 | self.channel = self._channel
130 |
131 | def read(self, raw=False):
132 | """
133 | Read current value for current channel with current gain.
134 | if raw is True, the HX711 output will not be converted
135 | from two's complement format.
136 | """
137 | if not self.is_ready():
138 | self._wait()
139 |
140 | raw_data = 0
141 | for i in range(self.DATA_BITS):
142 | self.pd_sck_pin.value(1)
143 | self.pd_sck_pin.value(0)
144 | raw_data = raw_data << 1 | self.d_out_pin.value()
145 | self._set_channel()
146 |
147 | if raw:
148 | return raw_data
149 | else:
150 | return self._convert_from_twos_complement(raw_data)
151 |
--------------------------------------------------------------------------------