Introduction: Mini OLED Panel Meter
This is an arduino programmable OLED panel meter that uses the INA226 power monitor chip to sense the voltage, and current which is then shown on the SSD1306 OLED display. Usually other small panel meters which are the ones on amazon/ebay that are dirt cheap are very inaccurate, and some of them come with this potentiometer that can vary the voltage and current, but this is only accurate within a small range of values, and usually messes up the volt/current reading. To avoid this frustration I built my own panel meter that can display both voltage, and current accurately, be very tiny, be easy to use, measure watts, and change units of any measurement. All this is achieved in this Instructable.
Supplies
ALL COMPONENTS PURCHASED FROM LCSC
Chips
ATMEGA328p
LM317 (3.3v regulator)
INA226
Passives
3 x 10kΩ, 330Ω, 200Ω, 82Ω (0402 resistors)
1uF(1206), 4 x 0.1uF, 2 x 20pF (0402 ceramic capacitors)
Red LED (0805)
5mΩ 2W Resistor (2512)
Other
FTDI Programmer (purchased on amazon)
SSD1306 OLED display (purchased on amazon)
Step 1: How It Works
Background On Current and voltage measurement
Measuring Voltage is quite easy where all you have to do is connect the voltage you want to measure to an ADC (analog to digital converter) for a microcontroller to then read, and display the values for you. An ADC pretty much samples the analog voltage at certain points in time, and stores those values as bits. The higher the bit resolution, which is the amount of samples the ADC takes of the analog voltage, the better the accuracy. Measuring current can be done in many different ways, but I'll only focus on the one this project uses which is using a current shunt. A current shunt is just a resistor connected in series with the load you are measuring, and according to Ohms Law, the current running through this resistor will create a voltage drop across the resistor equal to I times R. The current through the shunt will be the same as the the current running through the load as it is connected in series with the load. If the value of the shunt is known then the current through the load will be equal to voltage drop across the shunt/resistance of shunt. Shunts can be connected in the high or low side where high side is when the current shunt is connected to the positive side of the load, while low side is connected to the ground side of the load. I chose high side sensing for this project.
About The Components
This project uses the INA226 power monitoring IC to measure the voltage, and current. It achieves this by measuring the voltage across the shunt resistor, and calculates the current running through the load as the voltage is simply measured by the ADC of the INA226. The heart of this project is the ATMEGA328p, since it reads the values from the INA226 through I2C, and displays these values to the OLED display through again, I2C. The current shunt is a 5mΩ resistor with 1% tolerance rated to be 2W which creates a voltage drop that the INA226 measures. The SSD1306 is a typical display that is available everywhere that is commonly used in arduino project where you simply power it up, and feed it information through the I2C line.
Step 2: Schematic
The ATMEGA328p is pretty much the same as an Arduino mini, and to program an Arduino mini you would need a FTDI programmer in order to convert the USB to serial communication. In order to program the ATMEGA328p, the FTDI programmer needs to connect to the ATMEGA by using pins DTR, RX, TX, CTS, POWER, and GROUND. Not only do you have to program the ATMEGA, but since the chip is blank it needs to be bootloaded, and to bootload the chip you need to connect an Arduino uno to the chip with pins 15, 16, 17, and 29. Programming, and bootloading the chip will be explained in the steps below. The two 10k resistors are on pins 28, and 27 of the ATMEGA as those are the I2C pins (SDA and SCL). These two pins need a pull-up resistor to function correctly where the display, and INA226 use I2C communication which is why they have pins labelled SDA, and SCL (serial data and serial clock). VBUS of the INA226 is the point (with respect to ground) that you measure the voltage with, IN+ goes to the positive side of the shunt, and IN- goes to the load side of the shunt, the alert pin is used to alert the user of fault conditions.
Step 3: The PCB
This board measures 27mm x 28mm, and it takes a 5v-40v input which passes through the LM317 regulator which powers the entire board with 3.3v. The shunt resistor is on the bottom of the board, and can be connected to the load through the exposed contacts on the board. The board contains no holes as I wanted to save space, and reduce contact resistance, which was done to make sure the INA226 was giving accurate readings. To program the board, there is a female header for the FTDI programmer, and to bootload the board there are exposed contacts on the back of the board. The OLED display goes on the back of the board where the board must be bootloaded first before placing the display on it, since they are both located on the back.
Step 4: Code
#include <SPI.h> // library for I2C communication
#include <Wire.h> // library for I2C communication
#include <Adafruit_GFX.h> // library for grpahics (not needed)
#include <Adafruit_SSD1306.h> // library for OLED display
#include <math.h> // library for math stuff
#include <INA226_WE.h> // library for INA226 by wollewald
#define SCREEN_WIDTH 128 // setting OLED screen size
#define SCREEN_HEIGHT 64
#define OLED_RESET 4
#define I2C_ADDRESS 0x40 // address for OLED board, you may need to change if using differnt OLED display
Adafruit_SSD1306 display(OLED_RESET);
float shuntVoltage_mV = 0.000; // setting variables to simplify commands
float busVoltage_V = 0.000;
float current_A = 0.000;
float loadVoltage_V = 0.000;
float x;
float y;
float z;
INA226_WE ina226 = INA226_WE(0x40); // address for INA226, this may be different for you
void setup() {
Wire.begin(); // initializing libraries
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Serial.begin(9600);
ina226.init();
ina226.setResistorRange(0.005,10.0); //sets resistor to 0.005Ω (calibration required) and max current to be 10A
ina226.waitUntilConversionCompleted();
ina226.setConversionTime(CONV_TIME_140); // sets conversion time, this is the fastest
ina226.setAverage(AVERAGE_256); // sets average, the higher the more accurate, but it will be slow
pinMode(2,OUTPUT);
}
void loop() {
ina226.setCorrectionFactor(1); // you can use this to set resistor deviations, but I chose not to, so it's 1
ina226.readAndClearFlags();
shuntVoltage_mV = ina226.getShuntVoltage_mV(); // setting variables to make easier commands
busVoltage_V = ina226.getBusVoltage_V();
current_A = ina226.getCurrent_mA()/1000;
if (current_A <=0) { // this if else statment is used to prevent the display from showing negative current values
x = 0.000;
}
else{
x = current_A;
}
if (busVoltage_V >= 10){ //these if else statments are to align the cursors for the voltage and current if one of
z = 18; // them passes 10 as this would make the display look even
}
else {
z = 30;
}
if ( current_A >= 10){
y = 18;
}
else {
y = 30;
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(z,0); // sets where the display starts writing
display.print(busVoltage_V,3); // prints and sets loadvoltage to be measured to the third decimal
display.setCursor(110,0);
display.print("V ");
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(y,18);
display.print(x,3);
display.setCursor(110,18);
display.print("A ");
display.display(); // command to display info
Serial.println(shuntVoltage_mV,5); // use this line to check serial monitor to calibrate sensor
}
Step 5: Bootloading and Programming PCB
Burning Bootloader
To program the board you need to bootload it first. To do this you need another ATMEGA328p that is already bootloaded, which is an Arduino uno or similar. On the back of the board there are 6 exposed contacts which connect to the Arduino pins:
D10 → 29
D11 → 15
D12 → 16
D13 → 17
+3.3v → +3.3v
GND → GND
Then open the Arduino IDE, and open an example sketch called "ArduinoISP", and upload the code. After this, go to tools, and select "Programmer" then "Arduino as ISP". Lastly, go to tools and select "Burn Bootloader" where if it's bootloaded, the board will quickly blink 3 times while bootloading, and you will get a message in the command window telling you it has been bootloaded.
Programming
After bootloading, the board is now ready to be programmed. First, get the FTDI programmer, and connect to the female header shown in the picture above, or you can follow the pinout of the female header, and connect an FTDI board to it through jumper wires. Make sure to set the FTDI programmer to 3.3v. When everything is connected, simply upload the code in step 4.
Calibration
Keep in mind that you may have to tinker with the resistance value for the "setResistorRange" function since resistors aren't perfect. In order to calibrate the sensor you must run the code, and turn on the serial monitor where it would first read 0 or near 0, then you must connect a load, and pass a known current through it. Passing this known current will give you a reading on the serial monitor. Divide this number by 1000 (since it's in mV), then divide it by the known current (in amps), and this should give you the real resistance value. Plug the real resistance value into the "setResistorRange" function to calibrate the board. In step 4 I set the value to 5mΩ, but this of course needs changing if you use a 1% tolerance resistor as you most likely wouldn't need to calibrate it if you use a 0.1% tolerance resistor.
Step 6: Using It
General Use
Wiring the board is very easy, simply follow the diagram above, and keep in in mind you must connect grounds together if you are using two separate supplies. This board can only handle around 5A of current measurement before it starts to get warm, but it can theoretically measure up to 16A as the max sense voltage can only be 80mV. However, the resistor heating up will raise its resistance, and cause inaccuracies. Voltage reading may be inaccurate due to the voltage drop of the measurement wires, to avoid this make sure to use thick wires. The meter can only measure a max of 36v, though, I believe it's possible to redesign the board, add a voltage divider to limit the output voltage, and change the code to get a higher voltage mesurment value. Keep in mind you dont have to use it as a panel meter where you can use it to display anything you want.
More Info on Code and INA226
Here is the Github link to find out more about the library, and its functions.
Here is a thorough explanation of the INA226, and the library I used where there are 4-5 other libraries for the INA226, which if you're interested, then give them a try.
Here is the datasheet of the INA226.
If you would like to try these boards yourself here is a link to get them at PCBway.