Arduino Two-Channel Voltmeter with Thermometer

· #arduino #voltmeter #thermometer #oled

Contents

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.

Two-channel voltmeter with thermometer on an Arduino Uno, connected to two 9 V batteries

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

Schematic of the two-channel voltmeter with thermometer

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.

two_channel_voltmeter.ino Download

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// *********************************************************
// 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_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long startTime;
unsigned long finishTime;

int updateDisplay = 0;
int samples = 16;
float resolution = 4096.0;
float voltageReference = 4.096;
float seriesResistor = 47000.00;

int analogValueCH0[16];
int analogValueCH1[16];
int analogValueCH2[16];
unsigned int averageAnalogValueCH0;
unsigned int averageAnalogValueCH1;
unsigned int averageAnalogValueCH2;
float voltageCH0 = 0.000;
float voltageCH1 = 0.000;
float voltageCH2 = 0.000;
float averageVoltageCH1 = 0.000;
float averageVoltageCH2 = 0.000;

float resistance = 0.000;
float temperature = 0.000;
float averageTemperature = 0.000;

void setup() {
  // put your setup code here, to run once:
  analogReference(EXTERNAL);
  u8g2.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  updateDisplay++;

  // read chanel one
  for(int i = 0; i < samples; i++) {
    analogValueCH0[i] = analogRead(A0);
    delay(1);
  }
  for(int l = 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(int j = 0; j < samples; j++) {
    analogValueCH1[j] = analogRead(A1);
    delay(1);
  }
  for(int m = 0; m < samples; m++) {
    averageAnalogValueCH1 += analogValueCH1[m];
  }
  averageAnalogValueCH1 /= 4;
  voltageCH1 = averageAnalogValueCH1 * (voltageReference / resolution);
  voltageCH1 *= 10;
  averageVoltageCH1 += voltageCH1;
  averageAnalogValueCH1 = 0;

  // read chanel three
  for(int k = 0; k < samples; k++) {
    analogValueCH2[k] = analogRead(A2);
    delay(1);
  }
  for(int n = 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();
  }
}