bogde / HX711

An Arduino library to interface the Avia Semiconductor HX711 24-Bit Analog-to-Digital Converter (ADC) for Weight Scales.
MIT License
894 stars 537 forks source link

Seting Up multiple amplifiers for multiple load cells #35

Open rtlop opened 8 years ago

rtlop commented 8 years ago

So the library works great for one amplifier and load cell. But what would I need to change if I wanted to set up to 2 load cell and amplifiers?

compugician commented 6 years ago

At what sample rate?

On Wed, Apr 25, 2018 at 3:15 PM, rs810 notifications@github.com wrote:

@compugician https://github.com/compugician How many can you run with an Arduino Uno?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384402573, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiMqUCNFdcJuJGkMKDWzG7faul8fyks5tsMtZgaJpZM4ICbpk .

rs810 commented 6 years ago

The sample rate can be quite low: once a second.

On Apr 26, 2018, at 5:26 PM, Tal Achituv notifications@github.com wrote:

At what sample rate?

On Wed, Apr 25, 2018 at 3:15 PM, rs810 notifications@github.com wrote:

@compugician https://github.com/compugician How many can you run with an Arduino Uno?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384402573, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiMqUCNFdcJuJGkMKDWzG7faul8fyks5tsMtZgaJpZM4ICbpk .

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

compugician commented 6 years ago

You should be able to run a dozen or so with no additional hardware. And virtually hundreds if you use additional hardware.

The number is smaller if simultaneous sampling.

How far apart can cell 1 sampling be from cell N sampling? (Within a given 1hz sample)

Notice that some code modifications are necessary. On Thu, Apr 26, 2018 at 10:04 PM rs810 notifications@github.com wrote:

The sample rate can be quite low: once a second.

On Apr 26, 2018, at 5:26 PM, Tal Achituv notifications@github.com wrote:

At what sample rate?

On Wed, Apr 25, 2018 at 3:15 PM, rs810 notifications@github.com wrote:

@compugician https://github.com/compugician How many can you run with an Arduino Uno?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384402573, or mute the thread < https://github.com/notifications/unsubscribe-auth/AEYFiMqUCNFdcJuJGkMKDWzG7faul8fyks5tsMtZgaJpZM4ICbpk

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384841609, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiCKR35nedDjctrANVyOsYRsin8QSks5tsnyTgaJpZM4ICbpk .

rs810 commented 6 years ago

The project requires monitoring of five load cells and ideally getting an update on each one once a second. It seems we could offset sampling of each one by 200ms or groups by a larger time interval.

On Apr 26, 2018, at 8:10 PM, Tal Achituv notifications@github.com wrote:

You should be able to run a dozen or so with no additional hardware. And virtually hundreds if you use additional hardware.

The number is smaller if simultaneous sampling.

How far apart can cell 1 sampling be from cell N sampling? (Within a given 1hz sample)

Notice that some code modifications are necessary. On Thu, Apr 26, 2018 at 10:04 PM rs810 notifications@github.com wrote:

The sample rate can be quite low: once a second.

On Apr 26, 2018, at 5:26 PM, Tal Achituv notifications@github.com wrote:

At what sample rate?

On Wed, Apr 25, 2018 at 3:15 PM, rs810 notifications@github.com wrote:

@compugician https://github.com/compugician How many can you run with an Arduino Uno?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384402573, or mute the thread < https://github.com/notifications/unsubscribe-auth/AEYFiMqUCNFdcJuJGkMKDWzG7faul8fyks5tsMtZgaJpZM4ICbpk

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384841609, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiCKR35nedDjctrANVyOsYRsin8QSks5tsnyTgaJpZM4ICbpk .

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

compugician commented 6 years ago

You should be able to do that easily even with the standard library. The hx711 multi library (https://github.com/compugician/hx711-multi) will save you some wires but is not really necessary if you are ok with samples being more than 100ms apart.

On Fri, Apr 27, 2018 at 10:59 AM, rs810 notifications@github.com wrote:

The project requires monitoring of five load cells and ideally getting an update on each one once a second. It seems we could offset sampling of each one by 200ms or groups by a larger time interval.

On Apr 26, 2018, at 8:10 PM, Tal Achituv notifications@github.com wrote:

You should be able to run a dozen or so with no additional hardware. And virtually hundreds if you use additional hardware.

The number is smaller if simultaneous sampling.

How far apart can cell 1 sampling be from cell N sampling? (Within a given 1hz sample)

Notice that some code modifications are necessary. On Thu, Apr 26, 2018 at 10:04 PM rs810 notifications@github.com wrote:

The sample rate can be quite low: once a second.

On Apr 26, 2018, at 5:26 PM, Tal Achituv notifications@github.com wrote:

At what sample rate?

On Wed, Apr 25, 2018 at 3:15 PM, rs810 notifications@github.com wrote:

@compugician https://github.com/compugician How many can you run with an Arduino Uno?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384402573, or mute the thread < https://github.com/notifications/unsubscribe-auth/ AEYFiMqUCNFdcJuJGkMKDWzG7faul8fyks5tsMtZgaJpZM4ICbpk

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384841609, or mute the thread https://github.com/notifications/unsubscribe-auth/ AEYFiCKR35nedDjctrANVyOsYRsin8QSks5tsnyTgaJpZM4ICbpk

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384996465, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiG3ZSpV7Dj0nUu-14BBKUTeNlllbks5tszJJgaJpZM4ICbpk .

rs810 commented 6 years ago

Thank you for taking the time to answer my questions.

On Apr 27, 2018, at 9:13 AM, Tal Achituv notifications@github.com wrote:

You should be able to do that easily even with the standard library. The hx711 multi library (https://github.com/compugician/hx711-multi) will save you some wires but is not really necessary if you are ok with samples being more than 100ms apart.

On Fri, Apr 27, 2018 at 10:59 AM, rs810 notifications@github.com wrote:

The project requires monitoring of five load cells and ideally getting an update on each one once a second. It seems we could offset sampling of each one by 200ms or groups by a larger time interval.

On Apr 26, 2018, at 8:10 PM, Tal Achituv notifications@github.com wrote:

You should be able to run a dozen or so with no additional hardware. And virtually hundreds if you use additional hardware.

The number is smaller if simultaneous sampling.

How far apart can cell 1 sampling be from cell N sampling? (Within a given 1hz sample)

Notice that some code modifications are necessary. On Thu, Apr 26, 2018 at 10:04 PM rs810 notifications@github.com wrote:

The sample rate can be quite low: once a second.

On Apr 26, 2018, at 5:26 PM, Tal Achituv notifications@github.com wrote:

At what sample rate?

On Wed, Apr 25, 2018 at 3:15 PM, rs810 notifications@github.com wrote:

@compugician https://github.com/compugician How many can you run with an Arduino Uno?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384402573, or mute the thread < https://github.com/notifications/unsubscribe-auth/ AEYFiMqUCNFdcJuJGkMKDWzG7faul8fyks5tsMtZgaJpZM4ICbpk

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384841609, or mute the thread https://github.com/notifications/unsubscribe-auth/ AEYFiCKR35nedDjctrANVyOsYRsin8QSks5tsnyTgaJpZM4ICbpk

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-384996465, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiG3ZSpV7Dj0nUu-14BBKUTeNlllbks5tszJJgaJpZM4ICbpk .

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

lad97 commented 6 years ago

I'm doing a similar project as @rs810 using 3 load cells and 3 HX711 boards. It is great to find an active forum discussion on the topic. Pleased with the discussion. Thanks @compugician @lucian0112 @matouchat790te for you input/work specifically!

compugician commented 6 years ago

@lad97 - could you share a bit about what you're building? I would love to hear about what others are working on that needs this capability.

lad97 commented 6 years ago

@compugician Well to be honest, I'm not really using the capability of the multi-library you developed.. I can see a need for faster sampling in a later prototype though. I'm working on a project for an inventory management system that uses load cells to track part counts. Using a 1kg load cell I can get an exact part count for parts weighing only a few grams each. For now I'm using the esp8266 (nodeMCU) board to report the part count of 3 bins to a web dashboard - simple enough demo.

makay68g commented 6 years ago

@technicalpriyanshu - I had the same experience, and here is the solution.

@compugician - I found the problem, why your HX711-multi code works with 3 cells, but not with 4. According to the specification of the HX711 (page 5 of www.mouser.com/ds/2/813/hx711_english-1022875.pdf) the clock high time can take at most 50 microseconds during reading the data. I have an Arduino Nano with 16 MHz clock speed, so I have 800 time ticks to read all HX711's connected to it. It turns out that only 3 cells can be read safely in this amount of time with your code. I was able to speed up the code, so instead of

int i;
...
for (i = 0; i < 24; ++i) {
    digitalWrite(PD_SCK, HIGH);
    if (NULL!=result) {
        for (j = 0; j < COUNT; ++j) {
            bitWrite(result[j], 23-i, digitalRead(DOUT[j]));
        }
    }
    digitalWrite(PD_SCK, LOW);
}

I used

long int i;
...
for (j=0;j<COUNT;++j)
    result[j] = 0;
for (i = 1 << 23; i > 0; i>>=1) {
    digitalWrite(PD_SCK, HIGH);
    for (j = 0; j < COUNT; ++j)
        if (digitalRead(DOUT[j]))
            result[j] |= i;
    digitalWrite(PD_SCK, LOW);
}

[I know, the (NULL!=result) checking is not in this code, but if we are short of CPU time and one does not need the result, than why is he calling the read function anyway? :) ]

This change makes it work for 6 HX711's.

@technicalpriyanshu - If you need only 4 HX711's, then change the above code to what I wrote, and it will work. Moreover, if you never need any other number of HX711's, then unfold the for cycles, and it will run even faster. Or you can buy a faster Arduino (like Due) or even a Raspberry Pi. Or you can go for Assembly... :)

BTW: I am using load cells and HX711's in a warehouse automation logistic system. The cells will measure the weight of the commissioned goods. We will have 8 scales on each position, each scale will have 4 load cells, so I will go with two Raspberry Pi's reading 16-16 HX711's (they will have other tasks too, like showing information on a screen, so it is not an overkill :) ).

I hope this helps... :)

stadlor commented 5 years ago

HI

I'm currently trying to run 4 load cells connected to 4 HX711 boards, with preferable full speed (~80Hz). It did not work with HX711-multi as mentioned above. I therefor tried your replacement code @makay68g.

That is, I replaced some code in the readRaw() function, as shown in the code snippet below. However, this code dit not work for me since I'm only getting zero output. Is there anything I'm doing wrong?

void HX711MULTI::readRaw(long *result) {
    long int i,j;
    // wait for all the chips to become ready
    while (!is_ready());

    for (j=0;j<COUNT;++j)
        result[j] = 0;
    for (i = 1 << 23; i > 0; i>>=1) {
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUT[j]))
                result[j] |= i;
        digitalWrite(PD_SCK, LOW);
    ...

Thanks for all the help in this thread!

compugician commented 5 years ago

Could you share some more about your usecase?

On Thu, May 17, 2018 at 9:21 PM, lad97 notifications@github.com wrote:

I'm doing a similar project as @rs810 https://github.com/rs810 using 3 load cells and 3 HX711 boards. It is great to find an active forum discussion on the topic. Pleased with the discussion. Thanks @compugician https://github.com/compugician @lucian0112 https://github.com/lucian0112 @matouchat790te https://github.com/matouchat790te for you input/work specifically!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-389979434, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiPsiXzvuRTEwhyI5F_RYZMJIwFFgks5tzc2pgaJpZM4ICbpk .

compugician commented 5 years ago

Can you share more info? your board, wiring, and any other code running, etc?

On Wed, Sep 19, 2018 at 5:01 PM, stadlor notifications@github.com wrote:

HI

I'm currently trying to run 4 load cells connected to 4 HX711 boards, with preferable full speed (~80Hz). It did not work with HX711-multi as mentioned above. I therefor tried your replacement code @makay68g https://github.com/makay68g.

That is, I replaced some code in the readRaw() function, as shown in the code snippet below. However, this code dit not work for me since I'm only getting zero output. Is there anything I'm doing wrong?

void HX711MULTI::readRaw(long *result) { long int i,j; // wait for all the chips to become ready while (!is_ready());

for (j=0;j<COUNT;++j) result[j] = 0; for (i = 1 << 23; i > 0; i>>=1) { digitalWrite(PD_SCK, HIGH); for (j = 0; j < COUNT; ++j) bitWrite(result[j], 23-i, digitalRead(DOUT[j])); if (digitalRead(DOUT[j])) result[j] |= i; digitalWrite(PD_SCK, LOW); ...

Thanks for all the help in this thread!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bogde/HX711/issues/35#issuecomment-422836688, or mute the thread https://github.com/notifications/unsubscribe-auth/AEYFiOTQPvEcegzxVYuogQLo3DbPP8Pmks5uclw1gaJpZM4ICbpk .

makay68g commented 5 years ago

@stadlor: The code snippet seems to be right (except for the last '}', but it is there if the code compiles at all... :) ). It must be something wrong in you wiring or in other parts of the code not shown here. I agree with @compugician, we need more information to be able to help.

stadlor commented 5 years ago

Hi and thanks for the fast response @compugician and @makay68g.

Use case: I have attached 4 load cells below a rectangle frame. I need the individual cells data to be able to measure the mass center and do different real time estimations.

Setup: I'm using an Arduino Uno with 4 hx711 boards from sparkfun. The setup works fine for both "HX711.h" and "HX711-multi.h" library, but I get several error values that I would like to remove.

I tried the code mentioned from matouchat790te with "HX711.h". This works fine with no errors but lowers the sampling speed to ~38 Hz.

I then tried the "HX711-multi.h" with the previous code I showed. But this new code only gives me zeros output from the loadcells. My wire setup is like this:

// Pins to the load cell amp
#define CLK 2      // clock pin to the load cell amp
#define DOUT1 3    // data pin to the first lca
#define DOUT2 5    // data pin to the second lca
#define DOUT3 7    // data pin to the third lca
#define DOUT4 9    // data pin to the fourth lca`

Let me know if you need any more information and thanks for the help!

makay68g commented 5 years ago

@stadlor: When you say it worked with "HX711.h" and "HX711-multi.h" with errors, did you mean that you got errors with both header files? Because you should not with "HX711.h", and if you did, then the problem is in your wiring or other parts of the code, as I wrote before.

So, assuming you got errors only with "HX711-multi.h": if you changed only that part I wrote, then it should work. Try the original code with 3 HX711's (all combinations: pins 3-5-7, 3-5-9, 3-7-9 and 5-7-9), and it should work without errors. Try my code with 1-2-3-4 HX711's and tell me the result. Without more information, I cannot help you...

stadlor commented 5 years ago

@makay68g I meant that I get data from the sensors, however with some occasional errors in the data ( huge "noise" spikes that seems to be read errors).

Before it worked flawless with "HX711-multi.h" when using 3 HX711's. However, when using your code I only get zeros from the readRaw() function. (how can I debug this code btw?).

Now I suddenly have some problems using Arduino IDE to upload code. I need to reset the Arduino UNO board just before I hit the upload command (having the exact same problem with 2 new UNO boards as well). I will report back later when I have this problem under control. Thanks again!

makay68g commented 5 years ago

@stadlor: There is not much to debug in this code: it is too short and needs to be run fast. I guess you already connected your Arduino through USB and writing the data to the serial port, that is the only easy way I know to debug it. It seems that your Arduino's have corrupted bootloader. This is the way you reburn it: https://www.arduino.cc/en/Tutorial/ArduinoISP

stadlor commented 5 years ago

Little update.

The problem with uploading to Arduino was my fault.. (I pressed ctrl+shift+u instead of ctrl+u)

Just to be clear, I get valid load cell data for both the original libraries "HX711.h" and "HX711-multi.h". However, when using more than 3 HX711 boards, i occasionally get noise spikes from both libs. So the wiring seems to work fine?

In order to get rid of the noise spikes, I'm trying to use the code that @makay68g suggested 10th of June. However, when using this code the result pointer I get from the read() function, contains only zeros. This is the same for any amount of HX711's I'm trying to use, or which of the four pins I'm trying to use. So I suspect that I have managed to implement the code from @makay68g in a wrong way. I have therefor included the whole edited readRaw() function below (note that I have marked the original and new code).

I have limited experience with "bitwise" programming and pointers, so suspect that have missed some important detail. But I could maybe try to use some Serial.print() commands inside the library code to debug why the Result array ends up containing only zeros?

Thanks again for all the valuable help in this thread!

void HX711MULTI::readRaw(long *result) {
    long int i,j;
    // wait for all the chips to become ready
    while (!is_ready());

    // Start makay68g code
    for (j=0;j<COUNT;++j)
        result[j] = 0;
    for (i = 1 << 23; i > 0; i>>=1) {
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUT[j]))
                result[j] |= i;
        digitalWrite(PD_SCK, LOW);
    }
    // End makay68g code

    /*
    // Start Original working code (but with noise spikes)
    // pulse the clock pin 24 times to read the data
    for (i = 0; i < 24; ++i) {
        digitalWrite(PD_SCK, HIGH);
        if (NULL!=result) {
            for (j = 0; j < COUNT; ++j) {
                bitWrite(result[j], 23-i, digitalRead(DOUT[j]));
            }
        }
        digitalWrite(PD_SCK, LOW);
    }
    // End Original working code.
    */

    // set the channel and the gain factor for the next reading using the clock pin
    for (i = 0; i < GAIN; ++i) {
        digitalWrite(PD_SCK, HIGH);
        digitalWrite(PD_SCK, LOW);
    }

    // Datasheet indicates the value is returned as a two's complement value, so 'stretch' the 24th bit to fit into 32 bits. 
    if (NULL!=result) {
        for (j = 0; j < COUNT; ++j) {
            if ( ( result[j] & 0x00800000 ) ) {
                result[j] |= 0xFF000000;
            } else {
                result[j] &= 0x00FFFFFF; //required in lieu of re-setting the value to zero before shifting bits in.
            }
        } 

    }
}
makay68g commented 5 years ago

I do not see any problems in the code, but let us try something. Add a new variable at the beginning: long int i,j,k; And change my part of the code to the following:

// Start makay68g code
for (j=0;j<COUNT;++j)
    result[j] = 0;
k = 0;
for (i = 1L << 23; i > 0; i>>=1) {
    digitalWrite(PD_SCK, HIGH);
    for (j = 0; j < COUNT; ++j)
        if (digitalRead(DOUT[j]))
            result[j] |= i;
        k |= i;
    digitalWrite(PD_SCK, LOW);
}
Serial.println(k);
// End makay68g code

Notice the changes: in the for cycle i starts from (1L << 23) instead of (1 << 23) just to make sure it's a long integer, and k should be 16777215 at the end. I cannot see any other possible problems. Please, tell me what you get from this code.

stadlor commented 5 years ago

Hi and thanks for the fast response @makay68g

I tried your suggestion. And this is a bit strange. If I set the i to 1L in the for loop, I don't get any serial output from the Arduino at all. It compiles with no errors or warning. But nothing happens in the arduino IDE serial monitor (no timestamps either).

If I remove the L and just set it to 1, as shown in the below code, I get the following results for i, j and k values (It was necessary to add the Serial.begin() to get this debug info out on the monitor):

i = 0 , j = 4 , k = 0

I guess j is correct and reflects the amount of HX711 boards. But k is then not correctly set if it should have been 16777215. Looks like it never gets into the second for loop with the bit shifting commands. I guess this is the reason why the readRaw() function only returns zeros.

    // New makay68g code
    for (j=0;j<COUNT;++j)
        result[j] = 0;
    k = 0;
    for (i = 1 << 23; i > 0; i>>=1) {
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUT[j]))
                result[j] |= i;
                k |= i;
        digitalWrite(PD_SCK, LOW);
    }
    Serial.begin(115200);
    Serial.print("i = ");
    Serial.print(i);
    Serial.print(" , j = ");
    Serial.print(j);
    Serial.print(" , k = ");
    Serial.println(k);
makay68g commented 5 years ago

OK, then try to start i from 8388608 which is (1 << 23). Then it should work. If it does not, then try this in your setup function (after Serial.begin() :) ): Serial.println(1<<23); Serial.println(1L<<23); Serial.println(8388608); It should all output the same number: 8388608. If it does not, then this is the problem. And I have no idea, how to solve it, since it is simple math, it should work.

stadlor commented 5 years ago

Hi again.

Both Serial.println(1L<<23); and Serial.println(8388608); works and outputs 8388608. However Serial.println(1<<23) outputs 0.

When trying to start the for loop from 8388608, I get the same problem as using 1L<<23, i.e. no output from Arduino monitor. Maybe I need to construct the for loop in a different way?

This is strange. I'm btw. using Windows 10 with an Arduino Uno and Arduino IDE 1.8.7. Thanks again for all the help!

makay68g commented 5 years ago

Hmm. Try to print out the following after the for cycle: Serial.println(sizeof(i)); It should be 4. Also try this there: i = 1L<<23;Serial.println(i); I am getting interested in this problem... :) . However I use Linux, and I had no problem with the original code...

stadlor commented 5 years ago

Hi again

Yes Serial.println(sizeof(i)); becomes 4. And i = 1L<<23;Serial.println(i); becomes 8388608.

I will try to see if I can find any solution. Now I at least understand the purpose of the operators :)

makay68g commented 5 years ago

OK then, two more tests: i = 1L<<23;Serial.println(i);i >>= 1;Serial.println(i); and i = 1;Serial.println(i);i >>= 1;Serial.println(i); The first should be: 8388608, 4194304, and the second: 1, 0. My guess is, that the Arduino went into an infinite cycle, because some computation does not work, we check that now. And that is why you did not receive anything.

makay68g commented 5 years ago

Or, you can try i=i>>1 or i/=2 or i=i/2 instead of i>>=1 in the for cycle.

stadlor commented 5 years ago

They work fine, that is i = 1L<<23;Serial.println(i);i >>= 1;Serial.println(i); becomes 8388608 and 4194304 i = 1;Serial.println(i);i >>= 1;Serial.println(i); becomes 1 and 0

The different approaches for next mask did also not make any difference. (i=i>>1 or i/=2 or i=i/2)

The "bitmask" loop ( for (long int i = 1L<<23; i > 0; i>>=1) { ... } ) works fine if I make it as a new separate arduino sketch. There seems to be something strange going on when I use it in the library. If running the following code in the readRaw() function:

    Serial.begin(19200);
    // Start makay68g code
    for (j=0;j<COUNT;++j)
        result[j] = 0;
    for (i = 1L << 23; i > 0; i>>=1) {
        Serial.println(i);
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUT[j]))
                result[j] |= i;
        digitalWrite(PD_SCK, LOW);
    }
    // End makay68g code */

I get the following output:

8388608
4194304
2097152
1048576
524288
262144
131072
65536
32768
0⸮
0@
0 
0
0
0
0
⸮
64
32
16
8
4
2
1
0
0
0
...

Beside outputting strange values between 32768 and 64, the loop never ends and goes into a long endless loop outputting zeros. Should I maybe not be calling the Serial.begin() in this part of the code? Why does this loop suddenly not work/stop in this context/library?

makay68g commented 5 years ago

OK, I have two suggestion. First: check your program for local variables, and try to eliminate as much as possible. If compilation says that you use too much memory and instability may occur, then this might be a the reason for this behaviour. You can check if this is the real problem: if you run a simple program like this, then this should work.

void setup() {
  Serial.begin(115200);
}

void loop() {
  long int i;
  for (i = 1L << 23; i > 0; i>>=1)
    Serial.println(i);
  delay(1000000);
}

If this program does not work, then replace your Arduino with a different one, this might be some hardware problem.

stadlor commented 5 years ago

I have almost no local variables. I'm basically running the example code from the library. I'm only sending the data I collect from the HX711 boards through the serial port. But I have switched of this function also.

The simple code in your last reply works fine when I use it in a separate and minimal Arduino sketch.

I'm starting to think that there are some errors in the Arduino IDE framework? Or could it be something with the result pointer or the last part of the function?

makay68g commented 5 years ago

There might be too many local variables in the library itself, although I do not know what happens if someone runs out of memory on an Arduino... :) . To make sure, I did not use the library, I just used my code as it is in a separate function. You might want to try that too...

I do not think, the Arduno IDE has anything to do with this problem. Since the simple code runs just fine, the compiler must be OK. The problem must be in the running of the code.

stadlor commented 5 years ago

Ok. Maybe that is a best way of incorporating this functionality. It is not a large library to implement.

stadlor commented 5 years ago

Hi again. Looks like it is the result[j] |= i; in the loop that corrupts the i value. If I remove this line, the output from Serial.print is not corrupted.

    for (i = 1L << 23; i > 0L; i>>=1) {     
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUTS[j]))
                //result[j] |= i;
        digitalWrite(PD_SCK, LOW);
    }
stadlor commented 5 years ago

You were right. After moving the whole library into a single sketch, the for loop works fine like you have explained.

My only problem is that I still get the spikes, i.e. sudden noisy values.

makay68g commented 5 years ago

Your last code does something very differently, if you comment out that line as you did: the digitalWrite(PD_SCK, LOW); is in the if block in that code. Your code should look like:

for (i = 1L << 23; i > 0L; i>>=1) {     
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUTS[j])) {
                //result[j] |= i;
                        }
        digitalWrite(PD_SCK, LOW);
    }

The i value cannot possibly be corrupted unless you give the wrong type of result variable. Could you post your complete code?

stadlor commented 5 years ago

Hi

Now I can't actually reproduce it. Currently I get this output from the following code.

    Serial.begin(115200);
    // Start makay68g code
    for (j=0;j<COUNT;++j)
        result[j] = 0;
    for (i = 1L << 23; i > 0; i>>=1L) {
        digitalWrite(PD_SCK, HIGH);
        for (j = 0; j < COUNT; ++j)
            if (digitalRead(DOUTS[j])) {
                \\result[j] |= i;
            }
        digitalWrite(PD_SCK, LOW);
        Serial.println(i);
    }
8388608
4194304
2097152
1048576
524288
262144
131072
65536
32768
16384

So it actually stops "inside" the for loop. If I uncomment the result[j] |= i;, line I get the following output (same output as I reported some days ago.)

8388608
4194304
2097152
1048576
524288
262144
131072
65536
0⸮
0@
0 
0
0
0
0
0
128
64
32
16
8
4
2
1
0
0
0
.... (many zeros)

Anyway, the for loop works fine now that I have moved the whole library into one Arduino IDE sketch. However, I still get the noisy spikes errors, like the below in column 3. Notice how the value first goes up, before it goes down to a large negative number. This is the raw output from the read function. Any idea how I could debug such errors? It happens randomly like every 2 seconds, on different boards/channels.

...
71024   90248   97640   104531
71115   90183   2109356 104625
71025   90146   -8388607    104676
70943   90204   97708   104862
71037   90089   97686   104888
71119   90214   97709   104893
...
makay68g commented 5 years ago

Without the complete code I cannot help you more. All I can say is that it worked for me.

stadlor commented 5 years ago

Sure. I can post my whole Arduino sketch that have all included below. Note that I have commented out the tare functionality. (How is this best done, should I maybe just include a file?).

#include <TimerOne.h>

// Pins to the load cell amp
#define CLK 2      // clock pin to the load cell amp
#define DOUT1 3    // data pin to the first lca
#define DOUT2 4    // data pin to the second lca
#define DOUT3 5    // data pin to the third lca
#define DOUT4 6    // data pin to the fourth lca

#define TARE_TIMEOUT_SECONDS 4

byte DOUTS[4] = {DOUT1, DOUT2, DOUT3, DOUT4};
byte GAIN;

#define CHANNEL_COUNT sizeof(DOUTS)/sizeof(byte)
long int results[CHANNEL_COUNT];
long int OFFSETS[CHANNEL_COUNT];

uint32_t logTime;

void setup() {
  Serial.begin(115200/2);
  //Serial.flush();
  //pinMode(11,OUTPUT);
  pinMode(CLK, OUTPUT);
  for (int i=0; i<CHANNEL_COUNT; i++) {
    pinMode(DOUTS[i], INPUT);
  }
  set_gain(128);

  read();
  //for (int i=0; i<CHANNEL_COUNT; ++i) {
  //  OFFSETS[i] = results[i];
  //}

  Timer1.initialize(1000000/80);
  Timer1.attachInterrupt(sendRawData);
}

void sendRawData() {
//  uint32_t nowTime = micros();
//  Serial.print(1000000.f/(nowTime-logTime),2);
//  Serial.print(" Hz, ");
//  logTime = nowTime;

  read();
  Serial.print("Data\t");
  for (int i=0; i<CHANNEL_COUNT; ++i) {;
    //Serial.print( -results[i]/22050.f,6);
    Serial.print( -results[i]);
    Serial.print( (i!=CHANNEL_COUNT-1)?"\t":"\n");
  }  
  Serial.flush();
  delay(10);
}

void loop() {
}

// ### Lib methods below

bool is_ready() { 
  bool result = true;
  for (int i = 0; i<CHANNEL_COUNT; ++i) {
    if (digitalRead(DOUTS[i]) == HIGH) {
      result = false;
    }
  }
  return result;
}

void set_gain(byte gain) {
  switch (gain) {
    case 128:   // channel A, gain factor 128
      GAIN = 1;
      break;
    case 64:    // channel A, gain factor 64
      GAIN = 3;
      break;
    case 32:    // channel B, gain factor 32
      GAIN = 2;
      break;
  }

  digitalWrite(CLK, LOW);
  read(); //a read is needed to get gain setting to come into effect.
}

bool tare(byte times) {
  //TODO: change this implementation to use a smarter read strategy. 
  //    right now samples are read 'times' times, but only the last is used (the multiple samples)
  //    are just being used to verify the spread is < tolerance.
  //    
  //    This should be done by creating a smarter multiple-reads function which returns a struct with values and metadata (number of good samples, standard deviation, etc.) 
  int i,j;

  long values[CHANNEL_COUNT];
  long minValues[CHANNEL_COUNT];
  long maxValues[CHANNEL_COUNT];

  for (i=0; i<CHANNEL_COUNT; ++i) {
    minValues[i]=0x7FFFFFFF;
    maxValues[i]=0x80000000;
  }

  for (i=0; i<times; ++i) {
    readRaw();
    for (j=0; j<CHANNEL_COUNT; ++j) {
      if (values[j]<minValues[j]) {
        minValues[j]=values[j];
      } 
      if (values[j]>maxValues[j]) {
        maxValues[j]=values[j];
      } 
    }   
  }

  //set the offsets
  for (i=0; i<CHANNEL_COUNT; ++i) {
    OFFSETS[i] = values[i];
    Serial.println(OFFSETS[i]);
    Serial.println(CHANNEL_COUNT);
    delay(100);
  }
  return true;
}

void read() {
  readRaw();
  /*
  for (int j = 0; j < CHANNEL_COUNT; ++j) {
//      Serial.print(results[j]);
//      Serial.print(" - ");
//      Serial.print(OFFSETS[j]);
      results[j] -= OFFSETS[j]; 
//      Serial.print(" = ");
//      Serial.println(results[j]);
  } */
}

void readRaw() {
  long int i;
  int j;

  // wait for all the chips to become ready
  while (!is_ready());

  // Start makay68g code
  for (j=0;j<CHANNEL_COUNT;++j)
    results[j] = 0;
  for (i = 1L << 23; i > 0L; i>>=1) {
    digitalWrite(CLK, HIGH);
    //PORTD |= (1<<2); // quick port
    for (j = 0; j < CHANNEL_COUNT; ++j)
      if (digitalRead(DOUTS[j])) {
        results[j] |= i;
      }
    digitalWrite(CLK, LOW);
    //PORTD &= ~(1<<2);
  }

  /*
  // Start Original working code (but with noise spikes)
  // pulse the clock pin 24 times to read the data
  for (i = 0; i < 24; ++i) {
    //digitalWrite(CLK, HIGH);
    PORTD |= (1<<2);
    for (j = 0; j < CHANNEL_COUNT; ++j) {
      bitWrite(results[j], 23-i, digitalRead(DOUTS[j]));
      //bitWrite(results[j], 23-i, (PIND & (1<<DOUTS[j]))>0?0:1);
    }
    //digitalWrite(CLK, LOW);
    PORTD &= ~(1<<2);
  }*/
  // End Original working code.

  // set the channel and the gain factor for the next reading using the clock pin
  for (i = 0; i < GAIN; ++i) {
    digitalWrite(CLK, HIGH);
    digitalWrite(CLK, LOW);
  }

  // Datasheet indicates the value is returned as a two's complement value, so 'stretch' the 24th bit to fit into 32 bits. 
  for (j = 0; j < CHANNEL_COUNT; ++j) {
    if ( ( results[j] & 0x00800000 ) ) {
      results[j] |= 0xFF000000;
    } else {
      results[j] &= 0x00FFFFFF; //required in lieu of re-setting the value to zero before shifting bits in.
    }
  } 
}
makay68g commented 5 years ago

OK, one thing I see as a possible problem. You use a timer interrupt to read and send the results through the serial port. It is well possible, that the interrupt cuts in while you are reading the values from the HX711's. Try the following: comment out Timer1 completely in the setup function and put your sendRawData function in the loop.

There is no point in doing everything in an interrupt. According to the specification the HX711 board can handle a 10 Hz reading and only by forcing pin 15 high can you achive 80 Hz. Doing everything in the loop function will just read the HX711's as fast as it is possible, since the readRaw function will wait for the data to be ready from the HX711's.

stadlor commented 5 years ago

Hi

I added the timer to try to get a stable sampling frequency of 80 Hz. However, if I remove the timer and put call the for sendRawData() in the loop, and remove the call for Serial.flush(); and the delay(10); in the end of sendRawData() function, it actually seems to work better now.. ! :)

I still get some few noise spikes, but much less often. Could be that it is still sensible on speed.

Is there anyway of ensuring a stable 80Hz sampling frequency, while not disturbing this setup?

makay68g commented 5 years ago

If you already setup your HX711's to give you an 80 Hz reading, then that you will have with this setup: no need to time it in the Arduino code, the HX711's will do that for you.

The Serial.print might be too slow for the 80 Hz refresh rate (I tried my code with the 10 Hz data rate: the original problem was in the reading of the actual data, and not with the data rate). So I assume now, that it is a speed problem and try to suggest some methods to avoid this problem.

One small change in the Serial communication part might speed it up a little:

  Serial.print("Data");
  for (int i=0; i<CHANNEL_COUNT; ++i) {
    //Serial.print( -results[i]/22050.f,6);
    Serial.print("\t");
    Serial.print( -results[i]);
  }  
  Serial.print("\n");

Also putting everything together in a string using sprintf and sending it with one Serial.println command might also be faster. Also sending the results in hexadecimal format might be faster. And try to avoid all data processing in the Arduino code, like '-results[i]` or the last for cycle in the readRaw function: do it on the PC.

You might also try to avoid calling one function from the others, that will also decrease the overhead: put the command block of sendRawData in the loop function, remove the read function and replace it with readRaw everywhere.

Is this a 4-scale setup, or one scale with 4 cells? If the later one, then (after calibration) you do not need to send the data for all cells through the Serial, only it's combined result, this might also help.

And if all else fails: a 16 MHz Arduino is just too slow for some setups, you should try a faster one... :)

stadlor commented 5 years ago

Thanks for the suggestions! I will try them out. Btw, what is a fast and good Arduino for this? I have ordered the Arduino Due.

makay68g commented 5 years ago

I used my code on a 16 MHz Arduino, and it worked for me for 4 HX711's and I calculated that it should work for 6 too. But I tried it for 10 Hz data rate only. So the problem must be in the time of the processing between the data readings, that is what needs to be cut down.

Since you do not have many spikes now, any faster Arduino should do it. I used a Raspberry Pi, because it had other duties too and I needed it's power to do that,

matouchat790te commented 5 years ago

Hello, the data sheet tell to wait the falling edge of DOUT/READY to read the value. If you spend too much time in sprintf at 115200bds to print about 40 char you'll lose 3.4 ms . May be sometime one of the HX711 overun and you start to read the previous value and an end-of-conversion occurs and you finish the read with the new value or logical 1 as it seams to be detailled in data sheet. Remember the HX7111 is free running : may be when you enter the interrupt timer , the falling edge of DOUT is already past for 12 ms, so you only have 1/ 80Hz ==> 12.5 ms - 12ms = 500us to read before the next conversion . And your result will be corrupted as you tell us. May be use an interrupt on falling edge of DOUT, only read asap the datas, just rise a flag signaling new datas are awailable and exit out of the interrupt .

stadlor commented 5 years ago

Thanks for the feedback! There are several things I could try out here.

I have also seen in the HX711 datasheet that it's possible to use an external clock (pin 14), and in this way ensure that the boards are synchronized. Could it be problematic that they have different internal clocks?

matouchat790te commented 5 years ago

it would be a solution to wire each DOUT to an interrupt pin of your arduino, write an interrupt routine per HX711, don't forget to declare variables seen by main program as ''volatile'' , https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/volatile/ use macro ATOMIC to be sure to exhange data beween low level ISR and main loop not corrupted by interrputs when your loop read the values . put every sprintf in the main loop. And it would work better . what kind of arduino you use ?

stadlor commented 5 years ago

Ok. Using internal interrupt pin seems like a good idea. I'm currently using an Arduino Uno. But I have ordered a Due.

Btw, if I let the HX711's "control" the outputted sampling frequency (just let the loop() control itself), I get a output frequency of 85-87 Hz. Does this point to a problem, or is the internal clock of Hx711 just not precise in this way?

If you already setup your HX711's to give you an 80 Hz reading, then that you will have with this setup: no need to time it in the Arduino code, the HX711's will do that for you.

matouchat790te commented 5 years ago

4 externals interrupts could be difficult with the uno. It can handle only 2 real external int able to detect falling edge, and .. 3 banks of interrupts working on ''pin change''. You have 4 sensors : it could be possible with pins 2,3 , D8D13 ( PCINT0_vect) , A0-A5 ( PCINT1_vect) or D0-D7 ( PCINT2_vect) . Or use a MEGA2560 with 6 external interrupts.

matouchat790te commented 5 years ago

a MEGA 2560 PRO could be a nice and small solution

makay68g commented 5 years ago

@matouchat790te: I do not think that using interrupts would help. The main problem in reading the data is that the 16MHz Arduino is not fast enough to read the HX711's output even if it reads them as fast as it is possible. If you introduce another overhead (the calling of the interrupt), the situation will become even worse. Moreover, for this setup you would also need a different CLK pin on the Arduino for each HX711, write it separately, which makes the program take even more time. And finally: if in the middle of reading one HX711 another HX711's interrupt comes in, then the first one will have wrong reading for sure as you will miss the 50 microsecond time window to read one bit.

External clock source might be a solution, I have never tried it.

Reading the HX711's in parallel in the loop function is not a perfect solution: the first couple of readings might have problems, but after that the HX711's will be synchronised (at least this is what happened in my case) and you will have stable readings. As I said before, the problem might be in the 80 Hz frequency, you do not have much time to communicate the results to the PC. The 85-87 Hz output might come from the not perfect synchronization of the HX711's and that you do force them to output their data as soon as they are all ready to do that.