Contents[Hide]

1. Intro

For a hub motor test stand, I needed a weighing scale which can be read out by a computer. Therefore I developed an interface program for the Arduino to read out the scale. There is no additional electronics needed, just two wires between the internal scale electronics and the Arduino.

Kitchen scale with interface cable
Kitchen scale with interface cable - Kitchen scale with interface cable

Kitchen scale with interface cable - Kitchen scale with interface cable

2. Arduino scale output to the screen

Tare . done
0
0
118
118
118
0

3. Kitchen weighing scale electronics

A digital scale consists of a load-cell, an analog-to-digital converter (ADC), a processor and a LCD display. The scale electronics will be left intact. The electronics of the scale that I used has a dual-slope integrating ADC that has been built with some integrated circuits. This dual slope ADC has a 5V digital PWM output signal that can easily be converted by the Arduino to the weight in grams. The PWM signal is taken from pin PA2, see the image.

Digital kitchen weighing scale electronics
Digital kitchen weighing scale electronics - Digital kitchen weighing scale electronics

Digital kitchen weighing scale electronics - Digital kitchen weighing scale electronics

Kitchen scale load cell
Kitchen scale load cell - Kitchen scale load cell

Kitchen scale load cell - Kitchen scale load cell


Kitchen scale dual slope ADC signal
Kitchen scale dual slope ADC signal - Kitchen scale dual slope ADC signal

Kitchen scale dual slope ADC signal - Kitchen scale dual slope ADC signal

Kitchen scale output PWM signal 5V 20ms
Kitchen scale output PWM signal 5V 20ms - Kitchen scale output PWM signal 5V 20ms

Kitchen scale output PWM signal 5V 20ms - Kitchen scale output PWM signal 5V 20ms


4. Interface hardware

I have not investigated if any scale can be used, because we need a PWM output signal. We use an Arduino with USB connection, such as the Arduino Uno or a Nano. Connect the digital scale PWM signal with the Arduino interrupt pin d3. It is wise to have a 10kΩ resistor in series with the PWM signal.

Scale interface hardware
Scale interface hardware - Scale interface hardware

Scale interface hardware - Scale interface hardware

5. Calibration

The interface must first be calibrated. Take the gain = 1 and offset = 0. Measure different weights and load the values in Excel. Now the conversion value (gain) can be read from the chart formula, see the example. The gain is 0.0378, which has to be filled into the library.

Scale interface calibration with Excel

6. Taring

After switch on, the Arduino automatically determines the offset, this is called taring.

7. Auto zero

Because of electronic drift, scales will fluctuate slightly from zero when nothing is on the tray. In order to correct this, an auto-zero function keeps the scale display at zero if the weight is between about -2 and 2 grams.

A drawback is that no weight can be measured of a few grams, but a kitchen scale is not meant for this too. Since the scale does not know the difference between electronic drift or a real weight of 2 gram, a weight of 2 gram will be displayed as 0 grams. See the links below for common scale accuracy problems. The drift nulling function can be disabled: scale.getWeight(0);

inline void Scale::calcDrift()
{ if(nonzeroed > -3 & nonzeroed < 3)
  { if(gram < -0.5) drift -= 0.2; // correct drift slowly
    if(gram > +0.5) drift += 0.2; 
  }
}

8. Customizing the scale

The Arduino scale interface has the advantage that the software can be customized. This creates interesting possibilities. You can for instance disable the auto zero function, perform automatic statistical analysis or try to improve the scale accuracy.

9. Digital scale accuracy issues

10. Software

For the latest software you can ask me. The scale interface uses the library FreqPeriodCounter, see HERE. For troubleshooting see HERE.

11. Digital kitchen scale calibration

A kitchen scale can easily be calibrated by weighing for example 3 pounds of oranges in a grocery store. Assuming the shop scale is calibrated well, you can calibrate the kitchen scale with the oranges. You need to adjust the value const float gain in scale.cpp. The accuracy then becomes about 0.2%. My Arduino interface follows the scale over the entire range from 0 to 3000 grams with a maximum deviation of about 2 grams.

12. Suitable weighing scales

Not all digital weighing scales may be suitable, it is important that the electronic is not completely sealed. My scale is no longer available, who has recently purchased a suitable scale?

13. Scale interface main program

#include <Streaming.h>
#include <Scale.h>
 
#include <FreqPeriodCounter.h>
 
const byte scalePin = 3;
const byte scaleInterrupt = 1; // is pin 3 too
#define LCDupdate_ms 500 
 
Scale scale(scalePin);
 
void setup() 
{ Serial.begin(9600);
  attachInterrupt(scaleInterrupt, scaleISR, CHANGE);
  Serial << "Push scale tare button ";
  while(!scale.tare()) Serial << ".";
  Serial << " done";
}
 
void loop(void) 
{ static unsigned long lastLCDms;
  if(millis() - lastLCDms > LCDupdate_ms)
  { lastLCDms = millis();
    Serial << endl << _FLOAT(scale.gram, 0); // todo -0 -> 0
  }
}
 
void scaleISR()
{ scale.getWeight(1);
}

14. Scale class header

/* 
Scale interface
Version 11-8-2012
Copyright (C) 2011  Albert van Dalen http://www.avdweb.nl
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses .
*/
 
#ifndef SCALE_H
#define SCALE_H
 
#include <FreqPeriodCounter.h>
 
class Scale : public FreqPeriodCounter
{
public:
  Scale(byte scalePin);
  bool tare(); // inline public member function is not allowed at new Arduino versions
  void getWeight(bool doAutoZero);
  
  float gramAverage, gram, nonzeroed, drift;
  
protected:
  inline void calcDrift();
  inline void calcAverage();
  
  long offset;
  byte scalePin;
};
 
#endif

15. Scale class cpp file

/* 
Scale interface
Version 11-8-2012
Copyright (C) 2011  Albert van Dalen http://www.avdweb.nl
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses .
*/
 
#include "Scale.h"
 
// DEFINITIONS
const float gain = 0.03769; // calibrate with Excel trendline formula with gain=1, offsetet=0
const int filter = 2;
// Compile time calculations
const int maxOffsetsDifference = 1/gain; // maxOffsetsDifference = 1 gram
 
Scale::Scale(byte scalePin):
scalePin (scalePin), gramAverage(0), gram (0), nonzeroed(0), drift(0), offset(0), FreqPeriodCounter(scalePin, micros, 0)
}
 
bool Scale::tare()
{ const int measurements=5;
  offset = 0;
  while(!ready()); 
  delay(3000); 
  long offsets[measurements];
  for(int i=0; i<measurements; i++) 
  { while(!ready());    
    offsets[i] = period;
    offset += period;
  }
  offset /= measurements;
  for(int i=0; i<measurements; i++) if(abs(offsets[i] - offset) > maxOffsetsDifference) return false; // only use equal values
  delay(3000); // todo, avoid negative begin values but way?
  return true;
}
 
void Scale::getWeight(bool doAutoZero)
{ poll();
  nonzeroed = gain * ((long)period - offset);
  gram = nonzeroed - drift;
  calcAverage();
  if(doAutoZero) calcDrift(); // else drift = 0
}
 
void Scale::calcDrift()
{ if(nonzeroed > -3 & nonzeroed < 3)
  { if(gram < -0.5) drift -= 0.2; // correct drift slowly
    if(gram > +0.5) drift += 0.2; 
  }
}
 
inline void Scale::calcAverage()
{ gramAverage = (gramAverage * (filter-1) + gram) / filter;
}

Do you have any comments? Please let me know.
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.