Hi all.
I’ve been using Particle photons and spark cores for a while. Recently I’ve had one of the most annoying problems I have ever come across.
One of my apps uses a library for the HX711 IC, which is a adc converter for a simple load cell. Sparkfun sells breakout boards of these. They also provide a simple library. With some simple changes like adding #include “application.h” in the library, I was able to get it working perfectly for about oh… months! I’ve never had trouble with this library.
Only two days ago I started working on my software again and came across a solid white LED on the photon everytime I’d upload or reset. In fact resetting did nothing but go straight back to a white LED. I couldn’t get past DFU mode in the reset-mode button toggle, but I could get it into safe mode and flash an unrelated program and get it back to breathing cyan. With the Photon acting so weird I figured it was a hardware problem on my PCB… but I’ve recently narrowed it down to this library!
I’ve literally gone through three Photons (1 unopened) and two of my PCBs trying to get my load cell working again.
If I write everything I’ve tried I’d go on forever, but I attached the library files and a simple sketch program that DID work. You will see if you try to upload it that it compiles file, no errors or warnings, and will flash but right after resetting will go immediately into a solid white led. Nor is it recognized by the USB serial port to my PC.
If you take out the declaration of the HX711 scale() object (and comment out the scale. functions) in the test program it works of course. The HX711 scale(DOUT, CLK); line seems to be the direct cause of the white light on all the time.
Let me say also that connecting the HX711 hardware doesn’t change anything. This code messed up even the brand new opened photon as soon as I registered it. With or without the breakout board attached.
What gives? If anyone could check out the program that be awesome. Try uploading it to a photon. I am totally at a loss here. Did Particle change something in a very recent update??
THANKS!
HX711.cpp
#include "HX711.h"
void bitWrite(uint8_t &x, unsigned int n, bool b) {
if (n <= 7 && n >= 0) {
if (b) {
x |= (1u << n);
} else {
x &= ~(1u << n);
}
}
}
HX711::HX711(byte dout, byte pd_sck, byte gain) {
PD_SCK = pd_sck;
DOUT = dout;
pinMode(PD_SCK, OUTPUT);
pinMode(DOUT, INPUT);
set_gain(gain);
}
HX711::~HX711() {
}
bool HX711::is_ready() {
return digitalRead(DOUT) == LOW;
}
void HX711::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(PD_SCK, LOW);
read();
}
byte HX711::get_gain() {
return GAIN;
}
long HX711::read() {
// wait for the chip to become ready
while (!is_ready()) Spark.process();
byte data[3];
// pulse the clock pin 24 times to read the data
for (byte j = 3; j--;) {
for (char i = 8; i--;) {
digitalWrite(PD_SCK, HIGH);
bitWrite(data[j], i, digitalRead(DOUT));
digitalWrite(PD_SCK, LOW);
}
}
// set the channel and the gain factor for the next reading using the clock pin
for (int i = 0; i < GAIN; i++) {
digitalWrite(PD_SCK, HIGH);
digitalWrite(PD_SCK, LOW);
}
data[2] ^= 0x80;
return ((uint32_t) data[2] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[0];
}
long HX711::read_average(byte times) {
long sum = 0;
for (byte i = 0; i < times; i++) {
sum += read();
}
return sum / times;
}
double HX711::get_value(byte times) {
return read_average(times) - OFFSET;
}
float HX711::get_units(byte times) {
return get_value(times) / SCALE;
}
void HX711::tare(byte times) {
double sum = read_average(times);
set_offset(sum);
}
void HX711::set_scale(float scale) {
SCALE = scale;
}
void HX711::set_offset(long offset) {
OFFSET = offset;
}
void HX711::power_down() {
digitalWrite(PD_SCK, LOW);
digitalWrite(PD_SCK, HIGH);
}
void HX711::power_up() {
digitalWrite(PD_SCK, LOW);
}
HX711.h
#ifndef HX711_h
#define HX711_h
#ifdef ARDUINO
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#else
#include "application.h"
//#include "spark_wiring.h"
//#include "spark_wiring_usbserial.h"
#endif
class HX711
{
private:
byte PD_SCK; // Power Down and Serial Clock Input Pin
byte DOUT; // Serial Data Output Pin
byte GAIN; // amplification factor
long OFFSET; // used for tare weight
float SCALE; // used to return weight in grams, kg, ounces, whatever
public:
// define clock and data pin, channel, and gain factor
// channel selection is made by passing the appropriate gain: 128 or 64 for channel A, 32 for channel B
// gain: 128 or 64 for channel A; channel B works with 32 gain factor only
HX711(byte dout, byte pd_sck, byte gain = 128);
virtual ~HX711();
// check if HX711 is ready
// from the datasheet: 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.
bool is_ready();
// set the gain factor; takes effect only after a call to read()
// channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain
// depending on the parameter, the channel is also set to either A or B
void set_gain(byte gain = 128);
byte get_gain();
// waits for the chip to be ready and returns a reading
long read();
// returns an average reading; times = how many times to read
long read_average(byte times = 10);
// returns (read_average() - OFFSET), that is the current value without the tare weight; times = how many readings to do
double get_value(byte times = 1);
// returns get_value() divided by SCALE, that is the raw value divided by a value obtained via calibration
// times = how many readings to do
float get_units(byte times = 1);
// set the OFFSET value for tare weight; times = how many times to read the tare value
void tare(byte times = 10);
// set the SCALE value; this value is used to convert the raw data to "human readable" data (measure units)
void set_scale(float scale = 1.f);
// set OFFSET, the value that's subtracted from the actual reading (tare weight)
void set_offset(long offset = 0);
// puts the chip into power down mode
void power_down();
// wakes up the chip after power down mode
void power_up();
};
#endif /* HX711_h */
TEST PROGRAM
/*Example using the SparkFun HX711 breakout board with a scale
By: Nathan Seidle
SparkFun Electronics
Date: November 19th, 2014
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
This is the calibration sketch. Use it to determine the calibration_factor that the main example uses. It also
outputs the zero_factor useful for projects that have a permanent mass on the scale in between power cycles.
Setup your scale and start the sketch WITHOUT a weight on the scale
Once readings are displayed place the weight on the scale
Press +/- or a/z to adjust the calibration_factor until the output readings match the known weight
Use this calibration_factor on the example sketch
This example assumes pounds (lbs). If you prefer kilograms, change the Serial.print(" lbs"); line to kg. The
calibration factor will be significantly different but it will be linearly related to lbs (1 lbs = 0.453592 kg).
Your calibration factor may be very positive or very negative. It all depends on the setup of your scale system
and the direction the sensors deflect from zero state
This example code uses bogde's excellent library: https://github.com/bogde/HX711
bogde's library is released under a GNU GENERAL PUBLIC LICENSE
Arduino pin 2 -> HX711 CLK
3 -> DOUT
5V -> VCC
GND -> GND
Most any pin on the Arduino Uno will be compatible with DOUT/CLK.
The HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.
*/
#include "HX711.h"
#define DOUT D6
#define CLK D7
HX711 scale(DOUT, CLK);
int calibration_factor = 878; //-7050 worked for my 440lb max scale setup
void setup() {
Serial.begin(9600);
Serial.println("HX711 calibration sketch");
Serial.println("Remove all weight from scale");
Serial.println("After readings begin, place known weight on scale");
Serial.println("Press + or a to increase calibration factor");
Serial.println("Press - or z to decrease calibration factor");
scale.set_scale();
scale.tare(); //Reset the scale to 0
long zero_factor = scale.read_average(); //Get a baseline reading
Serial.print("Zero factor: "); //This can be used to remove the need to tare the scale. Useful in permanent scale projects.
Serial.println(zero_factor);
}
void loop() {
scale.set_scale(calibration_factor); //Adjust to this calibration factor
Serial.print("Reading: ");
Serial.print(scale.get_units(), 1);
Serial.print(" lbs"); //Change this to kg and re-adjust the calibration factor if you follow SI units like a sane person
Serial.print(" calibration_factor: ");
Serial.print(calibration_factor);
Serial.println();
if(Serial.available())
{
char temp = Serial.read();
if(temp == '+' || temp == 'a')
calibration_factor += 10;
else if(temp == '-' || temp == 'z')
calibration_factor -= 10;
}
}