Micro Voltage reading with HX711

Hi friends,
I want to measure micro volts accurately for this I choose HX711 module which is used in Weighing scale.
Reasons behind choosing this one because it has HX710 who has inbuilt PGA and 24bit ADC with very stable response (as per datasheet). I am referring FOLLOWING document to use it in real!

Code I am trying to use is as follows

#define ADC_data  A1
#define ADC_sck   A0

void setup() {
  Serial.begin(250000);
  Serial.println("Starting...");
  // put your setup code here, to run once:
pinMode(ADC_data,INPUT_PULLUP);
pinMode(ADC_sck,OUTPUT);
pinMode(13,OUTPUT);
digitalWrite(ADC_sck,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
long Count=ReadCount();
//digitalWrite(13,LOW);
//Serial.print("Count=");
//Serial.print(Count);
long Count1=Count-1;
long complemnted=0;
/*char CountChar[25];
char CountChar1[25];*/
//Serial.print("\tCount-1=");
//Serial.println(Count1);
//sprintf(CountChar,"%d",Count1);
//Serial.println(CountChar);
/*
for(int i=0;i<24;i++){
  if(CountChar[i]=='0'){
    CountChar1[i]='1';
  }
  else{
    CountChar1[i]='0';
  }
  Serial.println(int2bin(Count1));
}*/

//Serial.print("\tCount inverted=");
//Serial.println(CountChar1);

delay(2000);
}


unsigned long ReadCount(void){
  
   unsigned long Count=0,Count1=0;
 int i;
 //digitalWrite(ADC_data,HIGH);
 //digitalWrite(ADC_sck,HIGH);
 
 //PORTC  |= B0000010;
 PORTC  &= B1111110;
 PORTB  |= B00100000;
 Count=0;
 
 while(digitalRead(ADC_data));
 //digitalWrite(13,HIGH);
 //while(1){
 for (i=0;i<24;i++){
 //digitalWrite(ADC_sck,HIGH);
 PORTC  |= B0000001;
 PORTB  |= B00100000;
  if(digitalRead(ADC_data)==1){
  Count++;
 }
 
 Count=Count<<1;
 

 
delayMicroseconds(25);
// digitalWrite(ADC_sck,LOW);
 PORTC  &= B1111110;
 PORTB  &= B11011111;
 //delayMicroseconds(1);

 delayMicroseconds(25);
 }
 //delay(10);
 //}
//digitalWrite(ADC_sck,HIGH);
PORTC  |= B0000001;
PORTB  |= B00100000;
Count=Count^0x800000;
Count=Count&0xFFFFFF;
//delayMicroseconds(5);
//digitalWrite(ADC_sck,LOW);
PORTC  &= B1111110;
PORTB  &= B11011111;
Serial.print(Count);

 return(Count);
 
}

Now what problem I am facing:-
1] When I connect A+ and A- of module to each other or even to ground I am still getting some value at output and it is still fluctuating! Don’t no why should it change when both input are grounded.
2] How to map the input data with my adc value
Means I was unable to correlate my data with my adc input voltage!
3] I also tried different hx711 libraries but scenario didn’t changed i still get deviation when both ip are grounded and unable to correlate it with the input voltage!
Does anyone have used it or can any one could guide me on my need of measurement of micro volts accurately?

Thanks in advance!

Why don’t you ditch the code with the port manipulation and use something more understandable, such as this… known to work:

  unsigned long count = 0;

  while(digitalRead(pinDAT));  // wait until goes low (when data is ready)

  // then get 24 bits, MSB first
  for(byte i=0;i<24;i++)
  {
    digitalWrite(pinCLK, HIGH);   
    count=count<<1;          // shift left, zero goes into LSB; 1st time thru just shifts all zeros
    digitalWrite(pinCLK, LOW);
    if(digitalRead(pinDAT))       // read a bit; if high, change count LSB to 1
      count++;
  }
  digitalWrite(pinCLK, HIGH);   // channel A w/ 128 gain
  count=count^0x800000;         // convert two's comp (see notes below)
  digitalWrite(pinCLK, LOW);    // leave clock low
  // two's comp min = 0x800000 = -8388608; converted = 0
  // two's comp zero = 0x000000 = 0000000; converted = 2^23 = 8,388,608
  // two's comp max = 0x7FFFFF = +8388607; converted = (2^24)-1 = 16,777,215

The HX711 can only output data at 80 Hz, max, which is glacially slow relative to the microprocessor’s ability to talk with it, so there’s no need for speedy port-based communication.

Grounding the inputs violates the low end of the common mode voltage limitation (see the datasheet); not sure what effect that has on the chip or output. To get zero differential within the common mode range, you could short the inputs and hold them at roughly half of the excitation voltage using a resistor divider.

There will always be some fluctuation in the ADC output due to noise and other factors.

One way to understand and “map” your input vs ADC output is to plot the input and ADC output on a graph. If you do that over the full range of your input, you should get a point “cloud” that approximates a straight line. Fit a straight line through the points…y=mx+b…where x = ADC output and y = input voltage. Then for any ADC output, you can calculate the approximate voltage.

PS: how many microvolts are you trying to measure?

PPS: 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. By applying 25~27 positive clock pulses at the PD_SCK pin, data is shifted out…

Compare that to your code setup:

pinMode(ADC_sck,OUTPUT);
digitalWrite(ADC_sck,HIGH);

…which doesn’t seem to match the datasheet…

firstly thanks for your support!
As I understand this datasheet this adc works between -20 to+20mV so I grounded both of them. But in actual to get maximum vakue I have to increase voltage upto 0.5V (Dont no why so).

PPS: from the datasheet:
Quote

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…

Compare that to your code setup:
Code: [Select]

pinMode(ADC_sck,OUTPUT);
digitalWrite(ADC_sck,HIGH);

…which doesn’t seem to match the datasheet…

As you mention PD_SCK should be input but I think that is input for HX711 not for Microcontroller, I was also confused in it so I checked arduino’s available library Q2-HXL11 here is his cpp file

#include <Arduino.h>
#include "Q2HX711.h"

Q2HX711::Q2HX711(byte output_pin, byte clock_pin) {
  CLOCK_PIN  = clock_pin;
  OUT_PIN  = output_pin;
  GAIN = 1;
  pinsConfigured = false;
}

Q2HX711::~Q2HX711() {
}

bool Q2HX711::readyToSend() {
  if (!pinsConfigured) {
    // We need to set the pin mode once, but not in the constructor
    pinMode(CLOCK_PIN, OUTPUT);
    pinMode(OUT_PIN, INPUT);
    pinsConfigured = true;
  }
  return digitalRead(OUT_PIN) == LOW;
}

void Q2HX711::setGain(byte gain) {
  switch (gain) {
    case 128:
      GAIN = 1;
      break;
    case 64:
      GAIN = 3;
      break;
    case 32:
      GAIN = 2;
      break;
  }

  digitalWrite(CLOCK_PIN, LOW);
  read();
}

long Q2HX711::read() {
   while (!readyToSend());

  byte data[3];

  for (byte j = 3; j--;) {
      data[j] = shiftIn(OUT_PIN,CLOCK_PIN, MSBFIRST);
  }

  // set gain
  for (int i = 0; i < GAIN; i++) {
    digitalWrite(CLOCK_PIN, HIGH);
    digitalWrite(CLOCK_PIN, LOW);
  }

  data[2] ^= 0x80;
  return ((uint32_t) data[2] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[0];
}

In this

pinMode(CLOCK_PIN, OUTPUT);
pinMode(OUT_PIN, INPUT);

says its a output pin thats why I am making it output!

PS: how many microvolts are you trying to measure?

I atleast want 22bit resolution even if we consider it for vcc 5 v still it should measure 1.19uV and I don’t think its for 5V input as its having 128 gain.(and it reaches to max value on output in just 0.6V) So it should pusses more resolution than this.
but I at least need 1uV measurement .

I also tried to measure 20mv with following way mention in this video on Youtube and got 5uV step means on 1mV change I was getting 200 steps and not understanding why I am not able to get full resolution.

yatin:
As I understand this datasheet this adc works between -20 to+20mV so I grounded both of them.

This is apparently in response to my comment that grounding the inputs takes them outside the common mode voltage limit. Please google common mode voltage so you understand the concept, and then read the datasheet again, paying attention to the common mode voltage limit. (The input range -20 to +20 mV (differential voltage) has nothing to do with common mode voltage.)

yatin:
As you mention PD_SCK should be input but I think that is input for HX711 not for Microcontroller

You missed the important part of the bold text that I quoted from the datasheet. What state is PD_SCK supposed to be in while the ADC is thinking? What state does your "setup" code leave it in?

yatin:
I want at least want 22bit resolution

Good luck with getting 22 bits noise free.

grounding the inputs takes them outside the common mode voltage limit. Please google common mode voltage so you understand the concept, and then read the datasheet again, paying attention to the common mode voltage limit. (The input range -20 to +20 mV (differential voltage) has nothing to do with common mode voltage.)

Thanks a lot for pointing out my mistake, and improving my knowledge.
Yes I got the point and corrected the error!

You missed the important part of the bold text that I quoted from the datasheet. What state is PD_SCK supposed to be in while the ADC is thinking? What state does your “setup” code leave it in?

Sorry I interpreted your statement wrongly!

PORTC  &= B1111110;

this line of my code was for making it low only but you were right as it is in port manipulation its hard to understand.

#define ADC_data  A1
#define ADC_sck   A0

void setup() {
  Serial.begin(250000);
  Serial.println("Starting...");
  // put your setup code here, to run once:
pinMode(ADC_data,INPUT_PULLUP);
pinMode(ADC_sck,OUTPUT);
pinMode(13,OUTPUT);
digitalWrite(ADC_sck,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
long Count=ReadCount();
delay(2000);
}


unsigned long ReadCount(void){
  
   unsigned long Count=0,Count1=0;
 int i;
 
 digitalWrite(ADC_sck,LOW);
 Count=0;
 
 while(digitalRead(ADC_data));
 
 for (i=0;i<24;i++){
 digitalWrite(ADC_sck,HIGH);
  if(digitalRead(ADC_data)==1){
  Count++;
 }
 else{
  Count1++;
 }
 Count=Count<<1; 
delayMicroseconds(1);
 digitalWrite(ADC_sck,LOW);

delayMicroseconds(1);
 }

digitalWrite(ADC_sck,HIGH);
Count=Count^0x800000;
delayMicroseconds(1);
digitalWrite(ADC_sck,LOW);

Serial.print(Count);
Serial.print("\t");
Serial.println(Count,2);
 return(Count); 
}

this one is regular code and now I am getting 24 bit resolution! Thanks alot .

You're welcome.

But your setup() still writes sck HIGH.

Also, there's no need for Count1.

And "i" doesn't need to be an int...can be a byte...and it can be local to the "for" loop.

No need for the uS delays, either.

Yatin, can you give us a pic of your circuit? I trying the same thing here, but it's not working.