This project utilizes the ATmega328's internal 1.1V bandgap reference to allow for accurate measurements of external voltages. From these measurements the library is able to measure the external voltage, allowing users to choose what to do in undervoltage/overvoltage/overcurrent cases within their projects. External components are kept to an absolute minimum, requiring only the battery and a shunt resistor (which isn't needed if you don't care about current draw). It is worth noting that as the project stands right now for Arduino boards there is no way to prevent current from the USB programmer from going into the battery and causing problems. As a result, be sure to have the battery disconnected whenever programming. See the github page for some simple circuit guidelines for this library. This library is also capable of monitoring the battery while the Arduino is powered by a boost converter for those who need 5V instead of whatever the battery happens to be at.
For anyone curious about what's happening behind the scenes the battery voltage is calculated by:
where A terms represent the ADC value returned by reading the pin.
The current is found using the equation:
For anyone interested the full derivations are available in the logs of this project.
This project is still ongoing, and awaiting parts for thorough testing.
This project has moved pretty fast overall, not sure how long I expected this project to take. Either way, I have been waiting on some OLED I2C displays to actually test this library properly and they finally arrived (I plugging into the arduino and using the serial monitor interferes with the results). I also tested the library using a boost converter circuit powered from the same battery that's being monitored so basically this is just an all around project update with some actual test footage. So lets talk about the code first, which doesn't change between either of the tests shown in this log:
#include<BatteryMonitor.h>#include<Wire.h>#include<Adafruit_GFX.h>#include<Adafruit_SSD1306.h>#define SCREEN_WIDTH 128 // OLED display width, in pixels#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define batVoltagePin A0 //connect directly to positive terminal of the battery#define batCurrentPin A1 //connect to the other side of a shunt resistor going from the positive battery terminal to the rest of your circuit
BatteryMonitor bat = BatteryMonitor(batVoltagePin, batCurrentPin);
display.println("Battery Monitor Test");
display.print("Vbat = ");
display.print("Ibat = ");
display.print("Vop = ");
I cut out the setup(), but it is important to note that the resistance for these tests was set to 1.42 ohms.... because that's the best I could cobble together from my salvaged parts box. So a better test will come when some proper .05 and .1 ohm resistors arrive from digikey. All this sketch really does is use the library functions getCurrentBatteryVoltage(), getBatteryCurrent(), and getCurrentOperatingVoltage() then print the return values to the display.
note the sketch prints battery input as Vbat, Battery Current as Ibat, and the operating voltage of the Arduino as Vop.
onto the simple battery monitor which was the original goal of this project it works! using the same schematic as is shown in the project image:
and the results of the test are shown in this video:
The voltage of the battery and the operating voltage appear to be reading pretty accurately but the current is somewhat off. I suspect this is due to the sense resistor I'm using, however, I currently don't own a multimeter that can measure resistances that low with any real accuracy. I measured 1.42 ohms by just doing the math after putting it across the power supply set to 1V and reading the current (its a 5w resistor it could take it).
Now onto the good stuff, the library can now officially monitor a battery while being powered by a boost converter. For this the schematic gets a little bit more messy but really its not that bad. I used some generic boost converter module that was laying around so there's really just a stand in for the boost converter in the schematic below:
Its worth noting that the AREF pin of the Arduino should always be connected to the highest voltage in your circuit provided that it's not outside the operating range of the board itself. Either way here's a nice little video of the library operating with the same program as above:
I was pretty sure that a boost converter could be used like this with the library but until now it hadn't been tried, either way all the codes there to allow someone to easily monitor battery voltage for whatever project they're doing. Even if you don't want to use your Arduino as a BMS it might be helpful in some cases to have a good estimate of the battery power remaining. Either...
Chances are this has been worked out before, I don't know, I didn't really look. But here is the process that was used to determine how to calculate the battery voltage and current. (its like circuits 101 all over again).
Vbg = Voltage of internal bandgap reference on the AVR = 1.1V
Aref = ADC value returned by reading Vbg
Vbat = Voltage of battery
Abat = ADC value returned by reading Vbat
Vsense = Voltage of the negative side of the current sense resistor
Asense = ADC value returned by reading the negative side of the current sense resistor
Rsense = the value of the resistor used to sense current
Iread = current read by the micro-controller
First assume the ratio of the 1.1V reference to the battery voltage is equal to the ADC reading of the reference to the ADC reading of the battery voltage. (this is mostly true)
And that's about it for the voltage calculation, onto current. First we find the voltage at the sense resistor using the same assumption as before that the ratio of the voltage is equal to the ratio of the ADC readings:
Using Ohm's law the current can be found by dividing the change in voltage by the resistance:
Now substituting in the above equations and simplifying yields Iread:
That's everything, since everything's now in terms of ADC values its fairly straight forward to simply get the values in software and calculate both the voltage of and current draw from the battery. All the units check out and a few sample calculations I ran seem to show that these equations work well enough (accuracy of the ADC throws current readings off by a few percentage points). If I overlooked something please let me know.
Most of these changes will be applied to the description of the project. Just wanted to give credit to https://hackaday.io/grbn who pointed out that there was a much better way to get the battery voltage using an AVR.