Introduction: Measure Low, Higher and Negative Voltages With Vivid Unit

About: A hustband, a father, an engineer, a hobbyist of electronics, programing, machining and retro gaming.

As a single-board computer, Vivid Unit comes with 3 ADC channels. ADC stands for Analog-to-Digital Converter, which is a system that converts analog signal to digital signal. Thanks to the ADC channels on Vivid Unit, you can measure voltages and get digital values as result, which can be further processed in your program.

I will introduce how to measure low voltage (up to 5V), higher voltage (above 5V) and negative voltage with Vivid Unit.

Supplies

  • 1 x Vivid Unit
  • Some DuPont wires
  • Breadboard
  • Some resistors (a 47K and a 10K in these examples)
  • Multimeter (optional, for result calibration)
  • Heat shrink tube (optional, to ease the calibration)

Step 1: Measure Low Voltage (up to 5V)

Vivid Unit has 3 ADC channels (A0, A3 and A4) and they are all 10-bit ADCs. You may wonder what resolution can they achieve? Let's take a look at Vivid Unit's schematic. I put the related parts into a picture so we can keep focus.

The ADC part is using 1.8V as the reference voltage, if there is no voltage divider in front of ADC input, then each ADC channel can measure up to 1.8V and the resolution would be 1.8/1024=0.00176V. However it is not the case for Vivid Unit, because it has a voltage divider for each ADC input. The voltage divider consists of a 17.8k resistor and a 10k resistor, which enlarge the voltage measuring range to 5V (1.8x27.8/10=5.004V), at the cost of lowering the resolution (to 5/1024=0.00488V). This resolution is still decent because it is less than 5mV, while a USB power adapter usually has ~50mV ripple voltage.

With that said, if you apply a voltage on Vivid Unit's ADC channel, that voltage should be between 0V and 5V. If the voltage is out of that range, the clamping circuit will actuate to protect the ADC input. But not for long, because the heat will eventually damage the diode and then the protection will be gone. So we should make sure to feed the A0, A3 and A4 a voltage between 0V~5V.

If you just need to measure a voltage no higher than 5V, then you can do it right away. You just need to make sure not to reverse the polarity. On Vivid Unit's PCB you can find a yellow 4-pin header, which breaks out the three ADC channels and the GND. You can connect two female-male DuPont wires to a ADC channel (e.g. A0) and GND for voltage measurement.

You can use the pre-installed software VGPW to monitor the voltage on each ADC channel. As shown in the picture.

Step 2: Measure Higher Voltage

If you want to measure voltage higher than 5V (e.g. to measure a 9V battery), you may add another voltage divider between Vivid Unit's ADC channel and your voltage. The voltage divider will make sure the voltage you feed to the ADC channel is not higher than 5V, again enlarging the range of measurable voltage will reduce the resolution.

General Situation

As shown in Fig.2-1, R1 and R2 are in serial as (R1+R2), which is in parallel with R4 as Rx (shown within the dashed rectangle). R3 and Rx work as a voltage divider. Our mission is to choose R3 and R4, so the system can measure higher voltage.

You can choose R4 first. Since R1 and R2 are already known, we can calculate Rx using the Eq.1 in Fig.2-2.

You can then decide the highest voltage VA0' (VA0 will be 5V then), and calculate R3 using the Eq.2 in Fig.2-2.

If you can not find the required resistor for R3, you may pick one with closest value. In such case you need to recalculate the highest voltage VA0' using the Eq.3 in Fig.2-2.

Simplified Situation

If you increase R4 to infinity (∞), that means to remove R4 from the network, as shown in Fig.2-3. In such case the Rx equals to R1+R2, and the calculation will be simplified, also you will save one resistor.

For example, I have a 47K resistor and I want to use it as R3. I just need to connect it to one of the ADC channel and it will increase the voltage measuring range to:

VA0'=(47+27.8)*5/27.8=13.453V

The actual resolution will be:

13.453/1024=0.01314V

As you can see the resolution is reduced (from ~5mV to ~13mV).

Get Correct Result

Although the system can measure up to 13.453V now, please keep in mind the actual voltage applies on ADC channel is still no higher than 5V, so the voltage read from VGPW is not the real result. Assume you read 3.264V on VGPW, the actual voltage you measured would be:

3.264*13.453/5=8.782V

You can even write a Python program to print the realtime result automatically:

import subprocess
import time

def call_vgp_adc():
  try:
    result = subprocess.check_output(["vgp", "adc", "0", "v"]).decode("utf-8").strip()
    result = float(result)*13.453/5
    print("\rResult: {:.3f}".format(result), end="V", flush=True)
  except subprocess.CalledProcessError as e:
    print("\rError: {}".format(e), end="", flush=True)

if __name__ == "__main__":
  while True:
    call_vgp_adc()
    time.sleep(1)

Every second this program calls the CLI version of VGP application to read the voltage on A0 (command is "vgp adc 0 v"), and calculates the actual voltage you measured.

You can also find the Python source code in attached vh.py file.

Attachments

Step 3: Measure Negative Voltage

Some times you may want to measure a negative voltage, or just want to avoid the damage caused by unintentional polarity reversing. You might immediately think of operational amplifier or inverting amplifier, but I am going to introduce a simplier way: just use two resistors.

You can not feed a negative VA0' directly to the ADC channel on Vivid Unit, so you can not connect the "-" polarity of VA0' to the GND of Vivid Unit. Instead you should connect the "-" polarity of VA0' to a reference point, which has a positive voltage (relates to Vivid Unit's GND), and its voltage is lower than the voltage that ADC channel can measure (5V). As shown in Fig.3-1, this way you "raised" the reference of VA0' to a point, by properly selecting R3 and R4 you can make sure the applied negative VA0' will eventually feed a positive voltage to A0.

As shown in Fig.3-2, you can calculate the range of allowed VA0' with given R3 and R4 values. If we want to measure positive and negative voltages with the same system, the Vref should be lower than 5V. The smaller Vref you have, the higher positive voltage you can measure, but at the same time the range for negative voltage will be reduced accordingly. In Vivid Unit's 40-pin GPIO header, there is 3.3V pin, which can be directly used as Vref.

For example, I choose 47K as R3 and 10K as R4. I calculate the range of allowed VA0' like this:

5*(1+47/(17.8+10)+47/10)-3.3*(47+10)/10 >= VA0' >= -3.3*(47+10)/10

18.14V >= VA0' >= -18.81V

With this configuration the system can safely measure ±18V without worrying about the polarity. The voltage resolution now becomes:

(18.14+18.81)/1024=0.03608V

Get Correct Result

Again you need to calculate the correct result from the VGP output. You can use Eq.2 in FIg.3-2 for this calculation.

If you read 1.354V on VGPW, the actual voltage you measured would be:

1.354*(1+47/(17.8+10)+47/10)-3.3*(47+10)/10=-8.803V

If you read 3.722V on VGPW, the actual voltage you measured would be:

3.722*(1+47/(17.8+10)+47/10)-3.3*(47+10)/10=8.698V

You can also write a Python program to print the realtime result automatically:

import subprocess
import time

def call_vgp_adc():
  try:
    va0 = subprocess.check_output(["vgp", "adc", "0", "v"]).decode("utf-8").strip()
    va0 = float(va0)
    result = va0*(1+47/(17.8+10)+47/10)-3.3*(1+47/10)
    print("\rResult: {:.3f}".format(result), end="V", flush=True)
  except subprocess.CalledProcessError as e:
    print("\rError: {}".format(e), end="", flush=True)

if __name__ == "__main__":
  while True:
    call_vgp_adc()
    time.sleep(1)

You can also find the Python source code in attached vh.py file.

Attachments

Step 4: Calibration

Every measurement has error (the amount of inaccuracy). When measuring voltage with ADC, the error may come from the reference voltage, the ADC itself, the accuracy of resistors in voltage divider, the resistor of cable/contact point etc.

The ADC on Vivid Unit has decent accurancy and in the majority of cases you may not need to calibrate the result. For example, when monitoring the voltage of a battery you would not mind the result is 0.05V higher than the actual voltage.

However sometimes you do want better accurancy. For example you are using the ADC to measure the output voltage of a precise sensor, and the result of further calculations heavily relies on the accurancy of this voltage. In such case you should do the calibration, and it is not difficult: you just need an accurate volmeter (multimeter will also do).

The idea is to use a voltmeter you trust, to measure the voltage you are measuring with Vivid Unit, so you can see the actual error of the value you get. You can then compensate the value in your program so the final output will be very close to the result from your favorite voltmeter.

In order to do the calibration, you will need to connect the voltmeter and Vivid Unit together to the voltage you want to measure. You can do it manually, but I found it is less reliable to use hands here: it is rather hard to hold the wires with fingers while trying to do the measurement, also human's body resistor may affect the result too.

So I did some modifications on my multimeter probes with DuPont wire and heat shrink tube, as shown in attached picture. I just need to plug in the DuPont wire from breadboard and I can measure the voltage easily.

In the last attached photo, I show the result after the calibration, which is very close to the value on my multimeter.