Switch branches/tags
Nothing to show
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
CustomBoardAndEnclosure update categorisation Sep 18, 2018
assets [MilliVoltmeterDIY] add easyeda source Jul 7, 2018
MilliVoltmeterDIY.fzz [MilliVoltmeterDIY] EasyEDA PCB design Jan 21, 2018
MilliVoltmeterDIY.ino [MilliVoltmeterDIY/CustomBoardAndEnclosure] more notes May 26, 2018
ltc2400_adc.h [MilliVoltmeterDIY] refactor code to classes Jan 16, 2018
saved_settings.cpp [MilliVoltmeterDIY] refactor code to classes Jan 16, 2018
saved_settings.h [MilliVoltmeterDIY] refactor code to classes Jan 16, 2018


#372 MilliVoltmeterDIY

An ATmega328-based millivolt meter based on a design by Scullcom Hobby Electronics. Uses an LTC2400 ADC and LT1019 voltage reference.

See CustomBoardAndEnclosure for details of the custom PCB and enclosure I made for the project.


▶️ return to the LEAP Catalog


This project is based on the excellent build tutorial by Scullcom Hobby Electronics #44 - Millivolt Meter MK2


A few changes I've made:

  • LT1019 2.5V voltage reference instead of the ADR4540BRZ
  • direct LCD control instead of I2C (because it is what I had available)
  • some of the buttons moved to analog pins (digital mode) since the LCD uses a few too many pins
  • adjust the controls to a three-button command set.
  • discarded the op-amp buffer, as I found it skewed the reading at the top and bottom of the range
  • altered the calibration method, so the only fixed value in the code is the reference voltage.

Button Functions

I used normally-open pushbuttons on the breadboard, but for the final build I have some normally-closed pushbuttons. The #define BUTTON_LOGIC_ACTIVE_STATE is used to select between HIGH or LOW button logic. Internal pull-ups are enabled so there are no additional external components required other than the push-buttons themselves.

All the necessary functions are implemented with a three-button command set:

  • button 1: calibrate
  • button 2: change the number of digits (precision)
  • button 3: change the second-line function between 3 modes:
    • bar graph
    • hold value
    • raw ADC output

Buffering the Input Voltage

The input signal is tapped from a voltage-divider to provide around 10x attenuation, and therefore support a wider voltage range.

The values used in the voltage-divider are not critical. They just need to be in a suitable proportion to scale back the intended input voltage range to a maximum limit of the reference voltage, and large enough to provide a high-impedence input to the voltage under test.

In my design, I'm using 100kΩ and 1MΩ which support a full-range of around 27.5V

Ideally the reading should be buffered to further reduce coupling with the circuit-under-test, as in the original Scullcom project. I tested buffering with an LMC6482 op-amp, but although it is "rail-to-rail" I found it performed quite poorly at the top and bottom of the range e.g. 0V input still producted a 40mV output on the buffer. I decided to discard the buffer, and just rely on a stiff voltage divider. Note that the Scullcom project used a AD8628ARZ, so perhaps that performs better as a buffer (I will have to get some to try).

I also planned to add a 1N4733 5.1V zener diode to provide some over-voltage input protection (across the lower half of the voltage-divider). However the leakage current introduced a minor non-linearity in the readings. So again, I discarded this idea in favour of the most accurate reading possible.

Using the LTC2400

10kΩ pull-ups are added on the CS and SCK pins to ensure the chip does not go into internal oscillator mode on startup.

The LTC2400 provides a 24-bit measurement with respect to the reference voltage (Vref = x00FFFFFF). This ias received in a 32-bit serial stream:

  • 4 high bits provide status
  • 4 low bits are "sub LSB" and can be discarded without affecting accuracy
  • the 24 bits in between are the actual reading

The status bits help decode the reading correctly:

  • SIG indicates if reading is positive or negative
  • EXR indicates if the reading exceeds the reference range (above or below)

Voltage Reference and Calibration

I'm using an LT1019 2.5V reference (because it is what I had available). This means that the LTC2400 ADC output is all calculated with respect to the 2.5V standard.

I have adapted the code so that the unit performs an automatic calibration with respect to the reference voltage. The only hardcoded value is the reference voltage. How this works:

  • the reference voltage is exposed on a "calibration" test point
  • the +ve input is connected to the "calibration" test point
  • press the "calibration" botton
  • the calibration adjustment factor is calculated to ensure an accurate reading of the reference voltage
  • the calibration adjustment factor is also stored in EEPROM as the default on startup

As a result - as long as the reference voltage is accurate(!) - this approach is agnostic with regards to any input attenutation set in the input voltage divider.


MilliVoltmeterDIY.ino is my version of the code, based on the original Millivolt_Meter_MK2_ver33.ino.

Libraries used:

Breadboard Construction

I initially built this on a breadboard and controlled with an Arduino Uno to verify and refine the circuit.




Credits and References