HX711 Load Cell Issue

Started by callen, December 20, 2016, 05:04:01 PM

callen

Hi,

I have an  Adafruit Feather M0 RFM69HCW Packet Radio - 433MHz and am trying to read an HX711 load cell and am having issues.  I think the issue may have been covered partially in the following post but i don't recall seeing a resolutions: https://lowpowerlab.com/forum/general-topics/gateway-sensor-reading-issue/msg12954/#msg12954

Below is the code I'm running:
//****************************************************
//************ INCLUDE ALL LIBRARIES HERE ************
//****************************************************
// General
#include <SPI.h>                          
#include <Wire.h>                         
            
// OLED
#include <Adafruit_SSD1306.h>         
#include <Adafruit_GFX.h>     

// 433 Radio
#include <RFM69.h>                       
#include <RFM69registers.h>               
#include <RFM69_ATC.h>    

// Thrust Cell
#include "HX711.h"

//****************************************************
//**** DEFINE KEY SETTINGS AND CALIBRATIONS HERE *****
//****************************************************

// Radio
int Transmit_Interval = 500; // how often, in milli seconds, the radio transmits data to controller
int Radio_Power = 31; // power output ranges from 0 (5dBm) to 31 (20dBm)
#define ENCRYPTKEY     "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!

// Thrust Cells 
#define M1_Thrust_calibration_factor -7050.0 //This value is obtained using the Calibration sketch

//****************************************************
//**************** MAP ALL PINS HERE *****************
//****************************************************

// for Feather M0 
#define RFM69_CS      8
#define RFM69_IRQ     3
#define RFM69_IRQN    3  // Pin 3 is IRQ 3!
#define RFM69_RST     4

// Thrust Cell Data Pins
#define M1_DOUT  6 // 
#define CLK  24  //  Pin 24 seems to work on Feather board its the SCK pin, also work for both cells

//***************************************************
// ************ RADIO SETTINGS HERE *****************
//***************************************************
#define NETWORKID    100  //the same on all nodes that talk to each other
#define NODE1        1  
#define NODE2        2

#define NODEID       NODE2 // Swap these two for other Feather
#define RECEIVER     NODE1 // Swap these two for other Feather

// Feather board frequency
#define FREQUENCY     RF69_433MHZ
#define IS_RFM69HCW    true // set to 'true' if you are using an RFM69HCW module

#define SERIAL_BAUD   115200  // CHECK, DELETE?  VARIALBE ISN'T REFERENCED ANYWHERE

//****************************************************
//******* Define Variables and Constants HERE ********
//****************************************************

// Variables for thrust
float M1_Thrust;

// Variables for Radio
char DatatoSend[20];  // String were all the varaibles to be sent will be stored
char DataRecieved[20];  // DO I NEED THIS? String were all the recieved varaibles will be stored
long lastmillis = 0;  // check if this can be integer,this counts how oftern telemtry data should be sent
int16_t packetnum = 0;  // packet counter, we increment per xmission.  Is this for packets sent

//****************************************************
//************* CREATE INSTANCES HERE ****************
//****************************************************

Adafruit_SSD1306 oled = Adafruit_SSD1306();  // OLED

RFM69 radio = RFM69(RFM69_CS, RFM69_IRQ, IS_RFM69HCW, RFM69_IRQN); // Radio  -- This does not effect the load cell

HX711 scale1(M1_DOUT, CLK); // Thrust Cell Motor 1

//****************************************************
//********* RUN SETUP CODE HERE - RUNS ONCE **********
//****************************************************

//  LOAD CELL NOT WORKING ARE RELATED TO THE SETUPCODE OF THE RFM RADIO UNIT.  I commented out the looping code of the radio unit and the scale doesn't work in this sketch however it does if you disable the radio setup code.

void setup() {
  Serial.begin(9600);  //Start the serial connection with the computer to view the result open the serial monitor 

  // Initialize OLED display
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)

  // OLED text display settings
  oled.setTextSize(2);
  oled.setTextColor(WHITE); 
  oled.setCursor(0,0);
  
  // Hard Reset the RFM module
  pinMode(RFM69_RST, OUTPUT); // commented this out and load cell still worked.
  digitalWrite(RFM69_RST, HIGH); delay(100); // commented this out and load cell still worked.
  digitalWrite(RFM69_RST, LOW);  delay(100); // commented this out and load cell still worked.

   // Initialize radio
  radio.initialize(FREQUENCY,NODEID,NETWORKID);  // turning this on stops the load cells from working
  if (IS_RFM69HCW) radio.setHighPower();  // Only for RFM69HCW & HW!
  radio.setPowerLevel(Radio_Power); // power output ranges from 0 (5dBm) to 31 (20dBm)
  radio.encrypt(ENCRYPTKEY);

  // Thrust Cell Calibration Set and Zero
  scale1.set_scale(M1_Thrust_calibration_factor); 
  scale1.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0
}

//****************************************************
//******* RUN Main CODE HERE - RUNS REPEATEDLY *******
//****************************************************
void loop() {
  //  ************ Thrust  *********
  M1_Thrust = scale1.get_units();
/*
  //  *** Send Telemetry Data - START ***********  This code all works but i commented out to try and trouble shoot RFM 
  if (millis() - lastmillis > Transmit_Interval){ //Send data every transmit interval in miliseconds
    sprintf(DatatoSend, "%d, %d", M1_Thrust, M1_Thrust);  // this encodes the data into a char format for sending via radio  Should be updated to include all variables
    itoa(packetnum++, DatatoSend+13, 0);
    radio.send(RECEIVER, DatatoSend, strlen(DatatoSend)); //target node Id, message as string or byte array, message length
    lastmillis = millis(); // Update lasmillis 
  }  
  //  *** Send Telemetry Data - END **************

  //  *** Recieve Throttle data -- START *********
  if (radio.receiveDone()) {
    if (radio.ACKRequested()) {  // Send acknolwedgment, if this isn't recieved by controller it will try to resend until recieved
      radio.sendACK();
    }  
  }
  radio.receiveDone(); //put radio in RX mode
  Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU   
  //  *** Recieve Throttle data -- END *******
*/

  //  ************ Print to OLED and Serial Monitor - Start *********
  // Debug display and print
  oled.setCursor(0,0);  
  oled.print("Thr1="); oled.print(M1_Thrust,1);
  oled.display();
  oled.clearDisplay();

  // Print all data to Serial
  Serial.print("Thrust1= "); Serial.println(M1_Thrust);
  //  ************ Print to OLED and Serial Monitor - End *********

}  // END OF VOID LOOP


I've tried all sorts of pin combinations and can't get it to work together.  I think the issue is the RFM module and the HX711 are both using the same SPI data feed.  Any help would be greatly appreciated.

Charles

TomWS

At quick glance, it appears as if the HX711 library uses a bit banging protocol to communicate with the load cell and needs to use a dedicated GPIO for its clock, not one shared with SPI or I2C (TWI).  Wire a spare GPIO pin to the HX711 amplifier and change the code to match.

Tom

callen

Tom- Thanks for the reply.  I think i found the problem.  I didn't need to set the pinmode on the SPI pins they just worked but then when i used the radio there was an issue. The other pins didn't work but i hadn't set the pinmode for CLK to output.  I'll see if this solves the problem. 

Charles

TomWS

Quote from: callen on December 21, 2016, 09:20:29 AM
Tom- Thanks for the reply.  I think i found the problem.  I didn't need to set the pinmode on the SPI pins they just worked but then when i used the radio there was an issue. The other pins didn't work but i hadn't set the pinmode for CLK to output.  I'll see if this solves the problem. 

Charles
I doubt very much that this will solve the problem.  The HX711 has a totally different communication protocol than the SPI devices and the SPI clock will interfere with the data retrieval from the HX711. 

Tom

perky

#4
Quote from: TomWS on December 21, 2016, 09:28:51 AM
I doubt very much that this will solve the problem.  The HX711 has a totally different communication protocol than the SPI devices and the SPI clock will interfere with the data retrieval from the HX711. 

Tom

Well, that device has DOUT which is not tri-statable, so you might need a series resistor on its DOUT output to prevent it from over-driving MISO. This device also requires 25-27 clocks per aquisition transfer, the number if these clocks selects the gain and channel. It appears you should apply those clocks first, then wait for DOUT to go low (without a clock), then transfer 24 bits. If you're using a common SPI clock the device might get into an unknown state because it is being clocked, but if there's 60us with the clock high it would enter power-down and (presumably) reset that logic.

So, by disabling SPI and driving SCK high for > 60us, then providing the required number of pulses (1 to 3) manually on SCK, then polling DOUT until it goes low (via the MISO pin) and bit-banging 24 bits on SCK while sampling DOUT via the MISO pin for data, then re-enabling SPI for other devices it should be possible I think to use just the SPI pins. But you are going to need a series resistor between DOUT and MISO so that MISO can be over-driven by the SPI devices when they're selected.

Mark.

Edit: I say bit-banging 24 bits, there's nothing to stop you using the SPI engine for that if you want. In fact that may be better.

callen

Tom - You're right it didn't solve the problem.  Mark - I think you solution is over my head.  My end goal is to have two HX711 boards sensing two load cells.  I figured getting one to work is a good place to start then move to add the 2nd one. 

I have a spare Bluetooth feather board.  I think i'll try adding the two HX711 boards to that and adding it as a slave via I2C to the main arduino to transfer the data.  May be a faster way to achieve my goal. 

Charles

TomWS

Quote from: perky on December 21, 2016, 10:40:32 AM
Edit: I say bit-banging 24 bits, there's nothing to stop you using the SPI engine for that if you want. In fact that may be better.
If you were to write your own library, maybe, but this device has a single Data Line which is bidirectional similar to I2C but different.  Putting this on a standard serial line is a mistake, especially when the existing library does do bit-banging.  Further, it uses information on the data line to handle multiple HX711s on the same signal pins (which is what OP wants to do).

Tom

perky

#7
Quote from: TomWS on December 21, 2016, 05:54:33 PM
If you were to write your own library, maybe, but this device has a single Data Line which is bidirectional similar to I2C but different.  Putting this on a standard serial line is a mistake, especially when the existing library does do bit-banging.  Further, it uses information on the data line to handle multiple HX711s on the same signal pins (which is what OP wants to do).

Tom

It has a uni-directional output that's permanently enabled, it's programmed for gain and channel with dummy clocks. Unless I'm looking at the wrong datasheet, it's a simple device with no ability to share (can you point me to the datasheet you're using if I'm wrong?). I agree the best solution if not pin bound is to use dedicted pins with a bit-banging driver though.

@calllen: OK, you want two HX711s. That complicates things. If you want to do that the cleanest solution is to have a dedicated clock and data pin for each interface and bit bang (it's the cleanest solution to have dedicated pins for one of them as well). However, if you are pin constrained, I still think it could be done using one more dedicated DOUT input pin using a common SPI clock and MISO for the other one. The key point is you can reset the logic in each HX711 with a 60us high on the common clock. It isn't programmed by the serial interface, so clocks out of normal sequence seen by a HX711 won't cause any problems to it as it will get powered down and then reset before it is actually read for real.

Edit: If you're concerned about power the decicated pins approach is really you're only option, you'll need to keep any unused HX711 in power down mode. It is by far the cleanest anyway.

Mark.

callen

Thanks for all the replies.  What I'm still confused about is that if I run just one HX711 using two pins say GPIO 11 (DOUT) and GPIO 10 (CLK), board data sheet here: https://learn.adafruit.com/adafruit-feather-m0-radio-with-lora-radio-module/pinouts) everything works.  However it stops working when I include the radio code, which is commented out below.

//****************************************************
//************ INCLUDE ALL LIBRARIES HERE ************
//****************************************************
// General
#include <SPI.h>                          
#include <Wire.h>                         
           
// 433 Radio
#include <RFM69.h>                       
#include <RFM69registers.h>               
#include <RFM69_ATC.h>    

// Thrust Cell
#include "HX711.h"

//****************************************************
//**** DEFINE KEY SETTINGS AND CALIBRATIONS HERE *****
//****************************************************
// Radio
int Transmit_Interval = 500; // how often, in milli seconds, the radio transmits data to controller
int Radio_Power = 31; // power output ranges from 0 (5dBm) to 31 (20dBm)
#define ENCRYPTKEY     "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!

// Thrust Cells 
#define M1_Thrust_calibration_factor -7050.0 //This value is obtained using the Calibration sketch

//****************************************************
//**************** MAP ALL PINS HERE *****************
//****************************************************
// for Feather M0 
#define RFM69_CS      8
#define RFM69_IRQ     3
#define RFM69_IRQN    3  // Pin 3 is IRQ 3!
#define RFM69_RST     4

// Thrust Cell Data Pins
#define M1_DOUT  11 // 
#define CLK  10  //  

//***************************************************
// ************ RADIO SETTINGS HERE *****************
//***************************************************
#define NETWORKID    100  //the same on all nodes that talk to each other
#define NODE1        1  
#define NODE2        2

#define NODEID       NODE2 // Swap these two for other Feather
#define RECEIVER     NODE1 // Swap these two for other Feather

// Feather board frequency
#define FREQUENCY     RF69_433MHZ
#define IS_RFM69HCW    true // set to 'true' if you are using an RFM69HCW module

#define SERIAL_BAUD   115200  // CHECK, DELETE?  VARIALBE ISN'T REFERENCED ANYWHERE

//****************************************************
//******* Define Variables and Constants HERE ********
//****************************************************

// Variables for thrust
float M1_Thrust;

// Variables for Radio
char DatatoSend[20];  // String were all the varaibles to be sent will be stored
char DataRecieved[20];  // DO I NEED THIS? String were all the recieved varaibles will be stored
long lastmillis = 0;  // check if this can be integer,this counts how oftern telemtry data should be sent
int16_t packetnum = 0;  // packet counter, we increment per xmission.  Is this for packets sent

//****************************************************
//************* CREATE INSTANCES HERE ****************
//****************************************************

RFM69 radio = RFM69(RFM69_CS, RFM69_IRQ, IS_RFM69HCW, RFM69_IRQN); // Radio  -- This does not effect the load cell

HX711 scale1(M1_DOUT, CLK); // Thrust Cell Motor 1

//****************************************************
//********* RUN SETUP CODE HERE - RUNS ONCE **********
//****************************************************

void setup() {
  Serial.begin(9600);  //Start the serial connection with the computer to view the result open the serial monitor 

  // Hard Reset the RFM module
  pinMode(RFM69_RST, OUTPUT); // commented this out and load cell still worked.
  digitalWrite(RFM69_RST, HIGH); delay(100); // commented this out and load cell still worked.
  digitalWrite(RFM69_RST, LOW);  delay(100); // commented this out and load cell still worked.

   // Initialize radio
  radio.initialize(FREQUENCY,NODEID,NETWORKID);  // turning this on stops the load cells from working
  if (IS_RFM69HCW) radio.setHighPower();  // Only for RFM69HCW & HW!
  radio.setPowerLevel(Radio_Power); // power output ranges from 0 (5dBm) to 31 (20dBm)
  radio.encrypt(ENCRYPTKEY);

  // Thrust Cell - Pin Mode, Calibration Set and Zero
  pinMode(CLK, OUTPUT);
  pinMode(M1_DOUT, INPUT);
  
  scale1.set_scale(M1_Thrust_calibration_factor); 
  scale1.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0
}

//****************************************************
//******* RUN Main CODE HERE - RUNS REPEATEDLY *******
//****************************************************
void loop() {
  //  ************ Thrust  *********
  M1_Thrust = scale1.get_units();
/* //   HX711 WORKS IF THIS IS COMMENTED OUT.  ONCE I ADD THIS CODE IT STOPS WORKING.
  //  *** Send Telemetry Data - START ***********  This code all works but i commented out to try and trouble shoot RFM 
  if (millis() - lastmillis > Transmit_Interval){ //Send data every transmit interval in miliseconds
    sprintf(DatatoSend, "%d, %d", M1_Thrust, M1_Thrust);  // this encodes the data into a char format for sending via radio  Should be updated to include all variables
    itoa(packetnum++, DatatoSend+13, 0);
    radio.send(RECEIVER, DatatoSend, strlen(DatatoSend)); //target node Id, message as string or byte array, message length
    lastmillis = millis(); // Update lasmillis 
  }  
  //  *** Send Telemetry Data - END **************

  //  *** Recieve Throttle data -- START *********
  if (radio.receiveDone()) {
    if (radio.ACKRequested()) {  // Send acknolwedgment, if this isn't recieved by controller it will try to resend until recieved
      radio.sendACK();
    }  
  }
  radio.receiveDone(); //put radio in RX mode
  Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU   
  //  *** Recieve Throttle data -- END *******
*/

  // Print all data to Serial
  Serial.print("Thrust1= "); Serial.println(M1_Thrust);
}  // END OF VOID LOOP


I've also tried all sorts of other pin combos.  Additionally I've removed everything else, OLED, all other sensors, etc.

Charles