A two-channel voltmeter with a thermometer, built as a shield for the Arduino Uno. It measures two DC voltages up to 40 V and the temperature, and shows everything on a small OLED display.
How it works
The device uses the Arduino’s 10-bit analog-to-digital converter. Each measurement reads 16 samples. Their sum is divided by 4, which gives 12-bit resolution through software oversampling. Five such measurements are then averaged and shown on the display roughly every 300 ms. The actual cycle time is shown on the last line of the display.
Schematic
Input channels
The measured voltage is applied to the CH1+ and CH1− terminals. The input has a five-resistor voltage divider (100 kΩ over 10 kΩ + 1 kΩ + 100 Ω + 10 Ω) with a 10:1 ratio. With the 4.096 V reference this gives a measuring range of up to 40 V.
The divider output goes to a filter capacitor (1 µF) and 1N5819 Schottky protection diodes to VCC and ground, and then to the Arduino’s A1 pin. The second channel is identical and connects to pin A2.
Warning
The input is rated for DC voltages up to 40 V only. A higher voltage can damage the Arduino despite the protection diodes.
Voltage reference
The reference is a TL431, set to 4.096 V with the R16 trimmer. It connects to the Arduino’s AREF pin through jumper JP1.
Thermometer
Temperature is measured with a 47 kΩ NTC thermistor (B = 3435). The thermistor and a 47 kΩ resistor in series form a voltage divider whose output depends on the temperature. The divider output connects to pin A0, and the sketch calculates the thermistor resistance from the measured voltage and the temperature from that resistance using the B-parameter equation.
Display
The SSD1306 OLED display (0.96", 128×64) connects to +5 V and ground, and its SDA and SCL signal lines go to the matching Arduino pins (I²C).
Arduino sketch
The sketch uses the U8g2 library to drive the display.
// *********************************************************
// Program: two chanel voltmeter with thermometer
// Date: 01/09/2018
// Version: 1.0
// Author: Elvis Baketa
// Description:
// *********************************************************
#include<Arduino.h>#include<Wire.h>#include<U8g2lib.h>// WHITE OLED LCD 0.96" 128X64 I2C
U8G2_SSD1306_128X64_NONAME_F_HW_I2Cu8g2(U8G2_R0,/* reset=*/U8X8_PIN_NONE);unsignedlongstartTime;unsignedlongfinishTime;intupdateDisplay=0;intsamples=16;floatresolution=4096.0;floatvoltageReference=4.096;floatseriesResistor=47000.00;intanalogValueCH0[16];intanalogValueCH1[16];intanalogValueCH2[16];unsignedintaverageAnalogValueCH0;unsignedintaverageAnalogValueCH1;unsignedintaverageAnalogValueCH2;floatvoltageCH0=0.000;floatvoltageCH1=0.000;floatvoltageCH2=0.000;floataverageVoltageCH1=0.000;floataverageVoltageCH2=0.000;floatresistance=0.000;floattemperature=0.000;floataverageTemperature=0.000;voidsetup(){// put your setup code here, to run once:
analogReference(EXTERNAL);u8g2.begin();}voidloop(){// put your main code here, to run repeatedly:
updateDisplay++;// read chanel one
for(inti=0;i<samples;i++){analogValueCH0[i]=analogRead(A0);delay(1);}for(intl=0;l<samples;l++){averageAnalogValueCH0+=analogValueCH0[l];}averageAnalogValueCH0/=4;voltageCH0=averageAnalogValueCH0*(voltageReference/resolution);averageAnalogValueCH0=0;// convert volts to resistance
resistance=voltageReference/voltageCH0-1;resistance=1/resistance;resistance=seriesResistor*resistance;// convert resistance to temperature in Kelvin
temperature=log(resistance/seriesResistor);temperature=temperature*(1/float(3435));temperature=temperature+(1/(25+273.15));temperature=1/temperature;// convert Kelvin to Celsius
// T(°C) = T(°K) - 273.15
temperature=temperature-273.15;averageTemperature+=temperature;// read chanel two
for(intj=0;j<samples;j++){analogValueCH1[j]=analogRead(A1);delay(1);}for(intm=0;m<samples;m++){averageAnalogValueCH1+=analogValueCH1[m];}averageAnalogValueCH1/=4;voltageCH1=averageAnalogValueCH1*(voltageReference/resolution);voltageCH1*=10;averageVoltageCH1+=voltageCH1;averageAnalogValueCH1=0;// read chanel three
for(intk=0;k<samples;k++){analogValueCH2[k]=analogRead(A2);delay(1);}for(intn=0;n<samples;n++){averageAnalogValueCH2+=analogValueCH2[n];}averageAnalogValueCH2/=4;voltageCH2=averageAnalogValueCH2*(voltageReference/resolution);voltageCH2*=10;averageVoltageCH2+=voltageCH2;averageAnalogValueCH2=0;if(updateDisplay>4){// display data
u8g2.clearBuffer();u8g2.setFont(u8g2_font_profont22_tf);averageTemperature/=updateDisplay;u8g2.setCursor(0,16);u8g2.print("T ");u8g2.print(averageTemperature);u8g2.print(char(176));u8g2.print("C");averageVoltageCH1/=updateDisplay;u8g2.setCursor(0,32);u8g2.print("CH1 ");u8g2.print(averageVoltageCH1);u8g2.print("V");averageVoltageCH2/=updateDisplay;u8g2.setCursor(0,48);u8g2.print("CH2 ");u8g2.print(averageVoltageCH2);u8g2.print("V");u8g2.setCursor(0,64);finishTime=millis()-startTime;u8g2.print(finishTime);u8g2.print(" ms");u8g2.sendBuffer();averageTemperature=0.000;averageVoltageCH1=0.000;averageVoltageCH2=0.000;updateDisplay=0;startTime=millis();}}