USB Current Meter

…or USB power meter?
…or USB KEY AVR Tiny split core interface?

Call it however you want, this project is a small USB key sized circuit to interface an USB system with a single split core current sensor using an ATtiny85.

These non-invasive sensors are widely available on eBay and similar for a reasonable price (around USD$ 30 for the one I used) and let you measure the current flowing through an alternate voltage line, like house mains. This can be used to get a gross measure of instantaneous power consumption, allowing you to make a graph out of it and plot your power usage profile, or just to check how much power a device is using.

A friend of mine is using this one side-by-side with its photovoltaic inverter to upload his data on, a nice website for photovoltaic plant monitoring.

This also shows a rectifier circuit to acquire data from an alternate voltage source without dual power rails.

Split Core Sensors

The transducer used for the project is a split-core current sensor. This is basically a current transformer, with a splittable ferrite ring for non-intrusive insertion in a live system (but be careful anyway, ok?), simlarly to a current clamp. Of course the output is isolated from the input.

As the sensor is actually a current transformer, it can only work with AC loads, and output the signal as an AC current. To read the sensor from an ADC, the sensor have to be loaded with an high precision resistor to obtain an alternate voltage output.

The sensor I’m using is similar to this 20A Mini CT from Dent Instruments, available both in the 20A and 50A range with a voltage output of 0.333V at the nominal measured current.

Note that the sensor range is nominal, as the 20A version works with currents from 0.25 to 40 Amperes. Also, this sensor has an integrated load resistor, so that the output is already in volts.

This mini CT sensor is fairly well suited for installation in an Italian (European?) home’s electrical system, as the “standard” home contract is 3.3kW at 220V, allowing loads up to 15A. For 110V systems you may want to use a different sensor… just do the math!

Also, keep in mind that you can always do more than one pass through the sensor to get a better accuracy, reducing the range.

Rectifier Circuit

A loaded CT sensor produces an alternate voltage proportional to the input. To measure the signal from a microcontroller there are two possibilities:

  • Bias the signal to make it oscillate in the ADC range, acquire the actual waveform and calculate the RMS value using the samples;
  • Use a rectifier and filter circuit to get the signal to a more suitable range and measure it directly from the ADC;

While the first solution is nice because also allows to measure the actual frequency and waveform distorsion of the signal, it requires some smarter logic in the firmware and is susceptible to error in the biasing circuit (zero calibration) and acquisition period.

On the other side, the rectifier solution does not allow additional measures, but is easier to use, and does not require a bias circuit on the sensor.

This is the actual rectifier circuit, designed using this appliation note from CR Magnetics.

Note that the circuit does NOT use a dual power supply.

The working principle of this circuit is quite easy:

  • the sensor is actually biased at 0V, so that the output oscillates between +Vpeak and -Vpeak, the input load resistor is needeed only for sensor without internal resistor, and the input capaitor can be used for initial filtering.
  • the first OPAMP is the actual rectifier – it’s output is the same as the input for positive signals (as the diodes is reversed) and an inverted replica of the input signal for nevative inputs (as the diode is in forward). Note that this stage has different input impedance for positive and negative signals.
  • the second OPAMP is actually a plain amplifier stage, and has to be tuned to output an average voltage of 1.1V – the actual ADC full-scale – at the desired maximum input current.
  • the final stage is a simple RC filter, tuned to with a sufficiently high time-constant for a 50Hz signal.

One important aspect of this circuit is that not every OPAMP is capable of working with its input positive terminal grounded, so checkout the OPAMP datasheet and chose a suitable one, such as the LT2078.

Gain and Filtering

Tuning calculations are wrote in the schematics, but this is the basic idea behind it:

  • The tuning has to measure input power up to 4kW for a 230V system, so a maximum RMS current of 17.4A is archieved;
  • counting the sensor, that would give us a maximum peak voltage of .410V, and an average voltage of .261V;
  • the amplifier stage has to be tuned high enough to get an accurate post-filter average measurement, but not too high to saturate at peak values; this tuning uses a gain of 4.3, so that the required 4kW input gives out a 1.121 voltage average output.
  • the output filter has to have a time constant much higher than the 50Hz input signal, so an 100kOhm, 3uF RC circuit is used (.3s time constant).

Refer to the schematics for complete calculations.

ATtiny USB Interface

Interface with the host system is handled using the V-USB soft-USB library, implemented on an ATtiny85 microcontroller.

The protocol is two simple control requests:

  • CUSTOM_RQ_SET_MODE: set the acquisition mode to automatic or single-shot
  • CUSTOM_RQ_GET_VALUE: return the measured value, in Watt, normalize for 230V

The actual adc routine exploits the availability of a 20x gain stage in the ATtiny MCU, so that we can get a more precise value for low signals.

That’s the actual routine:

#define div_round(a, b) (((a) + b)/2 / (b))
static uint16_t get_power(void)
        uint32_t value;
        uint16_t offset;
        uint8_t gain;


        offset = 0;
        value  = adc_get(ADC_COIL);

        if (value < AMP_TH) {
                offset = adc_get(ADC_OFFSET_20X);
                value  = adc_get(ADC_COIL_20X);
                gain = 20;
        } else {
                gain = 1;

        if (value < offset)
                value = 0;
                value = div_round((value - offset) * ADC_VREF_mV *
                                  ADC_VREF_BITS * CAL_VOLTAGE *


        return value;

As arithmentics is done in fixed point, constants has to be tuned to prevent overflowing, as division is made as the last operation to not loose granularity.

That’s why the actual constant are defined as scaled in board.h:

#define AMP_TH 45 /* ~ 1024 / 20 */
#define ADC_VREF_mV (1100 / 4)
#define ADC_VREF_BITS (1024 / 4)

Command-line Utility

On the host side, a simple power commmandline utility allows to read from the device.

Without arguments, a single reading is requested and the result is wrote in standard output:

balto@balto-eee:~/usb-current-meter/commandline$ ./power

The utility implements some options to change device mode, reset the device and normalize power reading for different mains voltage.

Just run with the -h flag to see the help text:

balto@balto-eee:~/usb-current-meter/commandline$ ./power -h
Usage: ./power -h
       ./power -R
       ./power [options] divisor
  -h         this help
  -R         reset device
  -b         run in background
  -d delay   delay between updates
  -m         set mode (0=normal, 1=auto sampling)
  -r dbname  rrdtool update mode on dbname db
  -V voltage scale output for real voltage instead of nominal
  divisor    power divisor, correspond to number of turns on the sensor

RRDtool Graphs

One nice feature of the commandline utility is that it can be used directly to interface with rrdtools and load data to an RRD database.

First, the DB has to be created with:



# 5 minutes points, 96 hours data
# 30 minutes points, 25 days data
# 2 hours points, 2 months data
# 24 hours points, 2 years data

rrdtool create $DB \
  DS:power:GAUGE:600:U:U  \
  RRA:AVERAGE:0.5:1:1152  \
  RRA:AVERAGE:0.5:6:720   \
  RRA:AVERAGE:0.5:24:720  \

then, just run the power utility with the -r flag, as in:

balto@balto-eee:~/usb-current-meter/commandline$ ./power -r power.rrd

That’s going to update the DB automatically at about 10Hz.

Once the DB is populated with data, a graph can be generated using normal rrdtool commands, as an example this is the power consumption of my house for 4 weeks.


OPTS="-w 419 -h 200"

$RRDTOOL graph $OUT/power.png $OPTS -l 0 --start -3w \
  DEF:power=$DB:power:AVERAGE \

From the graph you can observe a standby power of about 100W, where the on-off pattern of the last week was just the fridge turning on an off.

Design Files

As always, all the design files for the projects (and something more!) are available from GitHub.


The schematics in PDF version can be downloaded from here.


The PCB is available on BatchPCB!



6 Responses to USB Current Meter

  1. Sung Jun Bae says:

    Dear Fabio Baltieri.
    I am the engineer that is in Korea.
    I discovered a difference in the circuit in your site in the circuit and GitHub project file.
    At that time, between the middle for the R4(Ry) and ground should insert a capacitor?

    • Hello Sung Jun Bae.

      You’re right, I forgot to mention about that capacitor in the post.

      It was meant to be used to tune the feedback circuit to remove the DC offset from the first OPAMP stage… or at least this is what I was told from my friend who helped me with the circuit. In the end I never used it and always short circuited with a 0 Ohm resistor.

      If you have a good scope to test the circuit, feel free to play with it… or just remove it entirely from the circuit!

      Anyway, I updated the schematics and put a note about it.

      Thanks for pointing it out!

  2. wis says:

    It looks like the file “requests.h” referenced in “main.c” (line 15) – is missing on github. Is it somewhere else?

  3. ibnubudir says:

    hi fabio..
    Great article…
    Introduce my name Ibnu Budi R
    I am a high school vocational teacher
    I will try the circuit that you created, but there are parts that I do not find in the market, I replace with LT2078 with LM358, for diode BAT54 no market to sell it, is there any advice for me what is the diode replacement ..?
    oh this month I’m making current sensor with lcd display- 2 sensors measuring electrical currents, using the CT sensor such that you can use in this article, but displayed on the LCD display 2×16, I use ATMega32 microcontroller, sensor 1 is used to measure the phase line and sensor 2 is used for the neutral line, display on the LCD display of measurement results of phase and the second current sensor, the measured ideal is 0 Ampere, if there is a difference in value there is a leak from one of the power lines,
    please give advice to me, email me…

    • Hi Ibnu, thanks for the comment!

      The LM358 is not really a good op-amp for this project, as it has a quite big input offset voltage, so it doesn’t really cope with low voltage signals. I’m really not an analog guy, but I’ve had great results with an OPA2376. You may also consider a chopper op-amp.

      For the rectifier diode, that’s really into the feedback circuit, so any decent signal diode should do the job. In fact the one I used is really just a general purpose Schottky diode (but it doesn’t have to). Do you really have issues getting the BAT54? It is a *really* common part number!

      About the application, have you considered just clamping both wires into the sensor loop? This way the magnetic fields sums up and you get the current difference for free! Signals are going to be *very* low though, unless you have a massive current leak (in which case some other safety device should engage first and disconnect the whole thing).

      Good luck with your project, sounds fun!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: