├── 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 | --------------------------------------------------------------------------------