[SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
cpr
Posts: 11
Joined: Thu Mar 03, 2016 4:56 pm
Location: LDK, OWL @ .de

[SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

Post by cpr » Sat Nov 19, 2016 7:53 pm

Hello everybody,

I am trying to read from this popular HX711 breakout board with an Adafruit Huzzah ESP8266 and a stock esp8266-20161110-v1.8.6.bin

This is the component for a digital scale, sparkfun has some pictures.

This chip has a non-standard protocol, the datasheet describes:
Serial Interface
Pin PD_SCK and DOUT are used for data retrieval, input selection, gain selection and power down controls.
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. By applying 25~27 positive clock pulses at the PD_SCK pin, data is shifted out from the DOUT output pin. Each PD_SCK pulse shifts out one bit, starting with the MSB bit first, until all 24 bits are shifted out. The 25th pulse at PD_SCK input will pull DOUT pin back to high (Fig.2).
My load cell and the HX711 board do work fine
- with an Arduino UNO and 5V
- with an Arduino UNO and 3.3V
both times with the popular library.

There is a RPi.GPIO-based implementation available.

Here is MY problem with MY code:

All I get back is "1" from the data pin.

The code (I just print out the values from the data pin, not doing any bit operations (or struct) yet) is as following:

Code: Select all

# -*- coding: utf-8 -*-
"""
An implementation of the HX711 board reading load cell(s).
"""

import time
import ustruct as struct # pylint: disable=import-error
from machine import Pin # pylint: disable=import-error

class HX711:
    """ Reading from a HX711 board by s simple serial protocol.
    """

    def __init__(self, pd_sck=4, dout=5, gain=128):

        self.gain = gain #unused, todo: 128 = 3 times sck high->low

        self.dataPin = Pin(dout, Pin.IN)
        self.pdsckPin = Pin(pd_sck, Pin.OUT, value=0)
        self.pdsckPin.low()

        time.sleep(1)
        self.powerDown()
        self.powerUp()

        self.read()

    def isready(self):
        """When output data is not ready for retrieval,
        digital output pin DOUT is high.
        """
        print("<waiting> dataPin: {}, sckPin: {}".format(self.dataPin.value(), self.pdsckPin.value()))
        return self.dataPin.value() == 0

    def read(self):
        """Reading from the board.
        """

        self.powerUp()

        while not self.isready():
            pass
        print("<waiting finished> dataPin: {}, sckPin: {}".format(self.dataPin.value(), self.pdsckPin.value()))

        for i in range(24):
            self.pdsckPin.high()
            time.sleep_us(2)
            print("<{}> dataPin: {}, sckPin: {}".format(i, self.dataPin.value(), self.pdsckPin.value()))
            self.pdsckPin.low()
            #print(i, self.dataPin.value(), self.pdsckPin.value())
            time.sleep_us(2)

        for i in range(3):
            #print(i)
            self.pdsckPin.high()
            time.sleep_us(2)
            print(i, self.dataPin.value(), self.pdsckPin.value())
            self.pdsckPin.low()
            time.sleep_us(2)

        self.powerDown()
        time.sleep(2)

    def powerDown(self):
        """Power the HX711 down as per datasheet: Setting high longer than 60 microseconds.
        """
        self.pdsckPin.low()
        self.pdsckPin.high()
        time.sleep_us(80)

    def powerUp(self):
        """Power the HX711 up.
        """
        self.pdsckPin.low()
And this is the typical result:

Code: Select all

 dataPin: 1, sckPin: 0
<waiting> dataPin: 1, sckPin: 0
<waiting> dataPin: 1, sckPin: 0
<waiting> dataPin: 1, sckPin: 0
<waiting> dataPin: 1, sckPin: 0
<waiting finished> dataPin: 0, sckPin: 0
<0> dataPin: 1, sckPin: 1
<1> dataPin: 1, sckPin: 1
<2> dataPin: 1, sckPin: 1
<3> dataPin: 1, sckPin: 1
<4> dataPin: 1, sckPin: 1
<5> dataPin: 1, sckPin: 1
<6> dataPin: 1, sckPin: 1
<7> dataPin: 1, sckPin: 1
<8> dataPin: 1, sckPin: 1
<9> dataPin: 1, sckPin: 1
<10> dataPin: 1, sckPin: 1
<11> dataPin: 1, sckPin: 1
<12> dataPin: 1, sckPin: 1
<13> dataPin: 1, sckPin: 1
<14> dataPin: 1, sckPin: 1
<15> dataPin: 1, sckPin: 1
<16> dataPin: 1, sckPin: 1
<17> dataPin: 1, sckPin: 1
<18> dataPin: 1, sckPin: 1
<19> dataPin: 1, sckPin: 1
<20> dataPin: 1, sckPin: 1
<21> dataPin: 1, sckPin: 1
<22> dataPin: 1, sckPin: 1
<23> dataPin: 1, sckPin: 1
0 1 1
1 1 1
2 1 1
I have two pictures of my setup, too.

Has anybody a digital scale working? That board is seemingly ubiquitous and the very same hardware works with my Arduino. So it _must_ be my code -- maybe someone spots a problem?

Asks with best regards,
Chris
Attachments
IMG_20161119_205531.jpg
IMG_20161119_205531.jpg (65.99 KiB) Viewed 40822 times
IMG_20161119_205554.jpg
IMG_20161119_205554.jpg (64.44 KiB) Viewed 40822 times
Last edited by cpr on Thu Nov 24, 2016 12:12 am, edited 1 time in total.

cpr
Posts: 11
Joined: Thu Mar 03, 2016 4:56 pm
Location: LDK, OWL @ .de

Re: Having problems with HX711 load cell sensor

Post by cpr » Wed Nov 23, 2016 6:30 pm

Ahhhh, the code is too slow!!!

*heureka*

Now this was just plain stupid:

Code: Select all

        for i in range(24):
            self.pdsckPin.high()
            time.sleep_us(2)
            print("<{}> dataPin: {}, sckPin: {}".format(i, self.dataPin.value(), self.pdsckPin.value()))
            self.pdsckPin.low()
            #print(i, self.dataPin.value(), self.pdsckPin.value())
            time.sleep_us(2)

Why? Because of
When PD_SCK pin changes from low to high
and stays at high for longer than 60µs, HX711
enters power down mode
This is faster, but still too slow:

Code: Select all

        for i in range(24):
            now = time.ticks_us()
            self.pdsckPin.value(1)
            print(time.ticks_diff(time.ticks_us(), now))
            my = my << self.dataPin.value()
            self.pdsckPin.value(0)
Result:
231
152
196
196
196
152
152
156
152
152
152
152
196
196
196
152
152
152
152
152
152
152
197
196

So the question is: It seems that the docs at http://docs.micropython.org/en/latest/e ... ython.html are not valid for the ESP8266 as neither import stm nor @micropython.native do work (on a stock 1.8.6).

What posibilities do I have on the ESP8266 port to toggle a pin?

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Having problems with HX711 load cell sensor

Post by Roberthh » Wed Nov 23, 2016 8:17 pm

What posibilities do I have on the ESP8266 port to toggle a pin?
I just gave it a try, using an oscilloscope. The following loop at a frequency of 160MHz will have a pulse high period of 10 or 30 us. Set the device to 160 MHz by:

Code: Select all

import machine
machine.freq(160000000)

Code: Select all

    my = 0
    for i in range(24):
        pdsckPin.value(1)
        pdsckPin.value(0)
        my = (my << 1) | dataPin.value()
Since the data is to be read after the falling edge, you have to use that sequence. I do not know why the width of the positive pulse varies.

cpr
Posts: 11
Joined: Thu Mar 03, 2016 4:56 pm
Location: LDK, OWL @ .de

Re: Having problems with HX711 load cell sensor

Post by cpr » Thu Nov 24, 2016 12:12 am

Hi Robert,

thank YOU!

I had to get up in the middle of the night and try the frequency change and indeed I now get:
- with a 0.5kg weight
- without a weight

Code: Select all

>>> f = HX711()
<waiting finished> dataPin: 0, sckPin: 0
bitbanged:  15240832
us:  , 228, 202, 216, 215, 201, 198, 212, 216, 194, 216, 212, 194, 216, 216, 194, 194, 212, 216, 194, 216, 212, 194, 215, 212
data:  111010001000111010000000
>>> f.read()
<waiting finished> dataPin: 0, sckPin: 0
bitbanged:  15982611
us:  , 236, 216, 189, 190, 212, 209, 190, 212, 212, 190, 212, 212, 186, 190, 208, 208, 190, 212, 208, 190, 212, 208, 190, 190
data:  111100111110000000010011
I then upgraded my toolchain *g* because that's what I do at night and put the code in ~/micropython/esp8266/modules/ but that did not make much difference:
- it still fails with 80MHz
- but returns values with 160MHz

I will continue the other day with the calibration, and maybe able to use the offsets gathered with the Arduino.



There is the clear tendency that the first iteration takes slightly longer than the rest.
I could not make this go away, despite
- toggling the pins a couple of times before entering the for-loop
- calling utime.ticks_ms() before entering the for-loop
Maybe something to do with scoping inside the loop?


So this code now works in that it gives me a sequence of 0 and 1 from the HX711 load cell amplifier:

Code: Select all

# -*- coding: utf-8 -*-
"""
An implementation of the HX711 board reading load cell(s).
"""

import utime
#import ustruct as struct # pylint: disable=import-error
from machine import Pin # pylint: disable=import-error
from machine import freq
freq(160000000)

class HX711:
    """ Reading from a HX711 board by s simple serial protocol.
    """

    def __init__(self, pd_sck=4, dout=5, gain=128):

        self.gain = gain #unused, todo: 128 = 3 times sck high->low

        self.dataPin = Pin(dout, Pin.IN)
        self.pdsckPin = Pin(pd_sck, Pin.OUT, value=0)
        self.pdsckPin.low()

        utime.sleep(1)
        self.powerDown()
        self.powerUp()

        self.now = 0
        self.read()

    def isready(self):
        """When output data is not ready for retrieval,
        digital output pin DOUT is high.
        """
        #print("<waiting> dataPin: {}, sckPin: {}".format(self.dataPin.value(), self.pdsckPin.value()))
        return self.dataPin.value() == 0

    def read(self):
        """Reading from the board.
        """

        self.powerUp()

        while not self.isready():
            pass
        print("<waiting finished> dataPin: {}, sckPin: {}".format(self.dataPin.value(), self.pdsckPin.value()))

        my = 0
        myus = ""
        mydata = ""
        now = utime.ticks_us()

        #now = time.ticks_us()
        for i in range(24):
            data = ""
            now = utime.ticks_us()
            self.pdsckPin.value(1)
            self.pdsckPin.value(0)
            data = self.dataPin.value()
            myus += ", " + str(utime.ticks_diff(utime.ticks_us(), now))
            mydata += str(data)
            my = ( my << 1) | data

        print("bitbanged: ", my)
        print("us: ", myus)
        print("data: ", mydata)

        for i in range(3):
            self.pdsckPin.high()
            utime.sleep_us(2)
            self.pdsckPin.low()

        self.powerDown()

    def powerDown(self):
        """Power the HX711 down as per datasheet: Setting high longer than 60 microseconds.
        """
        self.pdsckPin.low()
        self.pdsckPin.high()
        utime.sleep_us(80)

    def powerUp(self):
        self.pdsckPin.low()



User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: [SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

Post by Roberthh » Thu Nov 24, 2016 6:47 am

toggling the pins a couple of times before entering the for-loop
I tried to disable interrupts just for the pulse duration and enable it again then.

Code: Select all

            isr = machine.disable_irq()
            self.pdsckPin.value(1)
            self.pdsckPin.value(0)
            machine.enable_irq(isr)
That works fine and results in a 20 us pulse at 80 MHz, and a 10 us pulse at 160 MHz.
P.S.:
in the loop, you do not need the first

Code: Select all

data = ""
because data is reassigned later anyhow. And all that stuff to determine the timing makes the loop slower.

cpr
Posts: 11
Joined: Thu Mar 03, 2016 4:56 pm
Location: LDK, OWL @ .de

Re: [SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

Post by cpr » Thu Nov 24, 2016 7:02 am

Ah, disabling interrupts is what I'll do, too -- I am still new to all this.

That data = "" was more for debugging, because for a few moments I wasn't sure if repeated calls to .value() might mess up with the HX711 shifting out bits :)
All these print statements must go away anyways.

Thanks for the hints, I was mentally stuck when that inline assembler turned out not to work.


What I want to experiment with is:
- Placing a smartphone with a custom app on top of a ESP8266 device
- vibrate it (have that working already, with Ionic 2 framework and Cordova
- sense that vibration with e.g. an ADXL345
- and if some mirse-code like sequence matches
- (both already connect to the same MQTT broker)
- then "credit" the user logged into the app with the weight difference

Sounds daft? Well, think shared "KaffeeKanne"... :)
Not the most convincing usecase,
BUT all kinds of " authentication by being in proximity" are fascinating IoT concepts.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: [SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

Post by Roberthh » Sun Dec 11, 2016 1:52 pm

The recently introduced support of native and viper code emitters can be used to speed up the code a litte bit more. In the sample code,
the duration of the positive pulse decreases form 24ms to 14 ms, and the time between pulses from 240us to 108 us

Code: Select all

@micropython.native
def toggle():
    import machine

    pd_sck=4
    dout=5
    dataPin = machine.Pin(dout, machine.Pin.IN)
    pdsckPin = machine.Pin(pd_sck, machine.Pin.OUT, value=0)

    my = 0
    for i in range(24):
        isr = machine.disable_irq()
        pdsckPin.value(1)
        pdsckPin.value(0)
        machine.enable_irq(isr)
        my = (my << 1) | dataPin.value()
I do not try viper (yet), allowing direct access to the registers. And all of that is WIP anyhow.

sexbee
Posts: 1
Joined: Wed Aug 09, 2017 5:20 am

Re: [SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

Post by sexbee » Fri Aug 11, 2017 6:16 am

#write your program:
# -*- coding: utf-8 -*-
"""
An implementation of the HX711 board reading load cell(s).
"""

import utime
#import ustruct as struct # pylint: disable=import-error
from machine import Pin # pylint: disable=import-error
from machine import freq
freq(160000000)

class HX711:
""" Reading from a HX711 board by s simple serial protocol.
"""

def __init__(self, pd_sck, dout, gain):

self.gain = gain #unused, todo: 128 = 3 times sck high->low

self.dataPin = Pin(dout, Pin.IN)
self.pdsckPin = Pin(pd_sck, Pin.OUT, value=0)
self.pdsckPin.value(0)

utime.sleep(1)
self.powerDown()
self.powerUp()

self.now = 0
self.read()

def isready(self):
"""When output data is not ready for retrieval,
digital output pin DOUT is high.
"""
#print("<waiting> dataPin: {}, sckPin: {}".format(self.dataPin.value(), self.pdsckPin.value()))
return self.dataPin.value() == 0

def read(self):
"""Reading from the board.
"""

self.powerUp()

while not self.isready():
pass
print("<waiting finished> dataPin: {}, sckPin: {}".format(self.dataPin.value(), self.pdsckPin.value()))

my = 0
myus = ""
mydata = ""
now = utime.ticks_us()

#now = time.ticks_us()
for i in range(24):
#data = ""
now = utime.ticks_us()
self.pdsckPin.value(1)
self.pdsckPin.value(0)
data = self.dataPin.value()
myus += ", " + str(utime.ticks_diff(utime.ticks_us(), now))
mydata += str(data)
my = ( my << 1) | data

print("bitbanged: ", my)
print("us: ", myus)
print("data: ", mydata)

for i in range(3):
self.pdsckPin.value(1)
utime.sleep_us(2)
self.pdsckPin.value(0)

self.powerDown()

def powerDown(self):
"""Power the HX711 down as per datasheet: Setting high longer than 60 microseconds.
"""
self.pdsckPin.value(0)
self.pdsckPin.value(1)
utime.sleep_us(80)

def powerUp(self):
self.pdsckPin.value(0)

NilsNoreyson
Posts: 1
Joined: Fri Nov 17, 2017 10:44 pm

Re: [SOLVED/WORKEDAROUND] Having problems with HX711 load cell sensor

Post by NilsNoreyson » Fri Nov 17, 2017 11:05 pm

Hi,
thanks for your work for getting the HX711 running with the esp8266. I got the data of my load cell quiet fast with your example.
The HX711 breakout board I'm am using does not have a pull-down on the data line. This seems to be necessary. Due to this I was at first not able to read out the values correctly. GPIO15 has a build in pull-down resistor. When having the data line on this pin it was working very well after pulling the pin low.
By setting dout = 15 and changing the line:
self.dataPin = Pin(dout, Pin.IN) :arrow: self.dataPin = Pin(dout, Pin.IN,Pin.PULL_UP)
I got the correct values.

https://docs.micropython.org/en/latest/ ... /pins.html

Thanks!

delarge
Posts: 3
Joined: Mon Dec 18, 2017 4:04 pm

Re: [SOLVED/WORKEDAROUND] Having profolblems with HX711 load cell sensor

Post by delarge » Thu Dec 28, 2017 12:22 am

Hello everybody,

I'm starting with all this related with ESP8266+Micropython and I'm trying to make the HX711 work. I'm using NodeMCU v2 and the code(https://pastebin.com/43Ji11AL) is based on the info in this thread (thanks for that).

I'm having the following error when I try the HX711().

>>> HX711()
<waiting finished> dataPin: 0, sckPin: 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 14, in __init__
File "<stdin>", line 32, in read
NameError: local variable referenced before assignment

Seems a easy-solution error but I can't find it. Sorry about that. I would appreciate any hint for make HX711 work.

PS: I don't think that the problem is in my set-up. Anyway this is it: https://goo.gl/uh97MU

Thanks in advance.
Regards.

Post Reply