Arduino Voltmeter using SH1106 OLED display

A voltmeter is an important tool on the workbench of every electronics hobbyist, maker or hardware design engineer. As its name suggests, allows the user to measure the voltage difference between two points.  For today’s tutorial, we will look at how you can build an Arduino based DIY voltmeter, for use in situations where you don’t have the standard meters around.

An analog voltmeter

Measuring a DC voltage, should probably be as easy as connecting the voltage to be measured to an analog pin on the Arduino, but this becomes complicated when voltages are higher than the Arduino’s operational voltage (5V). When applied to an analog pin, Arduino will not only give a false reading but it could also damage the board. To solve this, today’s project uses the principle of voltage divider such that only a fraction of the voltage to be measured is applied to the Arduino. This fraction of voltage that goes in is determined by the ratio of the resistors used, as such, there is usually a limit to the maximum voltage that can be applied. For this tutorial, we will use a combo of a 100k and 10k resistor, with the 10k resistor on the “output side”. Feel free to experiment with other resistor values as well.

To make the voltmeter fully functional, we will add a third part, which is an SH1106 controller-based, 1.3″ OLED display, to show the value of the voltage being measured by the voltmeter.

It is important to note that this voltmeter can only monitor DC voltages within the range of 0-30v due to the values of the voltage divider used. It will require a voltage conversion circuit to be able to measure AC voltages.

Let’s dive in.

Required Component

The following components are required to build this project;

  1. An Arduino UNO board
  2. 1.3″ (132×64) OLED Display
  3. 10k Resistor
  4. 100k Resistor
  5. A breadboard
  6. Jumper wires

These components can be bought from any electronics component store online.

Schematics

The schematics for this project is pretty straightforward. The output of the voltage divider is connected to an analog pin on the Arduino while the OLED display is connected to the I2C bus on the Arduino.

Connect the components as shown in the schematics below:

Schematics

As usual, a pin to pin description of the connection between the Arduino and the OLED display is illustrated below.

OLED – Arduino

VCC - 5v
GND - GND
SDA - A4
SCL - A5

Go over the connections once again to ensure everything is as it should be.

Code

With the schematics complete we can now write the code for the project. The idea behind the code is simple, read the analog value, process it, then determine the Vin using the voltage divider equation and display it on the OLED display.

To reduce the complexity of the code to interact with the OLED, we will use the U8glib library. The library contains functions which make displaying text and images on the display easy.

To do a quick explanation of the code; We start as usual by including the library that will be used for the project, which in this case is, just the U8glib library.

#include "U8glib.h"            // U8glib library for the OLED

Next, we specify the analog pin to which the output of our voltage divider is connected and also create variables to hold different parameters including the Vout, Vin and the values of the resistors, correctly initializing their values.

int analogInput = 0;
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K)
float R2 = 10000.0; // resistance of R2 (10K) 
int value = 0;

Next, we create an instance/object of the U8glib library, which we will use to interact with the display.

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK);  // Display which does not send ACK

With this done, we move to the void setup() function. While you could do without this content, we proceed to declare the analog pin to which our voltage divider is connected as input.

void setup()
{
   pinMode(analogInput, INPUT);
}

Next, we proceed to the void loop() function. This is where the main action takes place. We start the function by reading the pin to which the output of the voltage divider is connected. since the value will be expressed in terms of the ADC, we multiply it by 5 and divide by the resolution of the ADC which is 1024 to obtain the decimal value of the voltage at the output of the voltage divider.

void loop(){
   // read the value at analog input
   value = analogRead(analogInput);
   vout = (value * 5.0) / 1024.0; // see text

We then work our way backward using the Vout and the values of the resistors to determine the value of the input voltage.

vin = vout / (R2/(R1+R2));

To ensure that the value is authentic, we check to ensure that the value is greater than 0.09. If the value is lesser than this, it is rounded up to zero.

   if (vin<0.09) {
   vin=0.0;//statement to quash undesired reading !
}

Next, we refresh the OLED display and call the draw() function, which is used to print the value of the voltage on the OLED.

u8g.firstPage();  
do 
  {
   draw();      
  }
while( u8g.nextPage() );

A small delay of 500ms is then added to stabilize operations. The loop goes on and on updating the value as soon as there is a change.

delay(500);
}

The void draw() function is key to the performance of the project’s objectives. The function starts by setting the font in which the texts will be displayed. Next, it displays the text “voltage” and then sets the cursor some few pixels in front of it to display the determined Vin.

void draw(void) 
{
  u8g.setFont(u8g_font_profont17r);        // select font
  u8g.drawStr(18, 12, "VOLTAGE"); 
  u8g.setPrintPos(33,40);
  u8g.drawRFrame(15, 20, 100, 30, 10);     // draws frame with rounded edges
  u8g.println(vin);                        //Prints the voltage
  u8g.println("V");
}

The complete code for the project is available below and attached under the download section.

#include "U8glib.h"            // U8glib library for the OLED
           

int analogInput = 0;
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K)
float R2 = 10000.0; // resistance of R2 (10K) 
int value = 0;

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK);  // Display which does not send ACK


void setup()
{
   pinMode(analogInput, INPUT);
}
void loop(){
   // read the value at analog input
   value = analogRead(analogInput);
   vout = (value * 5.0) / 1024.0; // see text
   vin = vout / (R2/(R1+R2)); 
   if (vin<0.09) {
   vin=0.0;//statement to quash undesired reading !
} 
  u8g.firstPage();  
  do 
    {
     draw();      
    }
  while( u8g.nextPage() );
delay(500);
}

void draw(void) 
{
  u8g.setFont(u8g_font_profont17r);        // select font
  u8g.drawStr(18, 12, "VOLTAGE"); 
  u8g.setPrintPos(33,40);
  u8g.drawRFrame(15, 20, 100, 30, 10);     // draws frame with rounded edges
  u8g.println(vin);                        //Prints the voltage
  u8g.println("V");
}

Demo

Go over the schematics once again to make sure everything is as it should be, then plug the Arduino to the computer and upload the code. You should see the display come up. At this point, you can now test the voltmeter by connecting the positive (+ve) probe to the positive wire of a battery and the negative probe to the negative wire of the battery.  The voltage of that battery should now be displayed on the OLED.

Demo Photo Credit: Konstantin Dimitrov

As mentioned during the introduction, this voltmeter can only be used to measure DC voltages, as such, one improvement that can be made to it going forward is to add the necessary circuits to give it the ability to measure AC voltages or even take it further and add features that allow it measures current, turning it into a full-blown multimeter.

That’s it for this tutorial guys. Feel free to ask whatever questions you might have about the project via the comment section.

Please follow and like us:
Pin Share



Subscribe
Notify of
guest

3 Comments
Inline Feedbacks
View all comments
Ahti

Hi

Why do voltages jumping up an down?
Like 3,12v ,3,27v and 3,60V?
When i measure with Multimeter I get only one reading.
I can not understand this.
I put this code to Arduino Promini.
Atmega 168 ,5V ,16Mhz.

Best regards Ahti.N

simon

mine jumped up and down as well only when connected to USB. When connected to 9volt pp3 battery the display is a lot more stable.

Jeff

Built this using a Nano and 3D printed an enclosure for it. Running on a 9 volt battery. I added an on/off switch and some banana jacks. Now I’ve got a nice and small portable VDC meter. Thanks!

RELATED PROJECTS

TOP PCB Companies