All helpers! I admire Your patience. Going for a master degree in electric/electronis measurement technic one year of class was on the schedule. "To measure is to know" and old experienced guy expressed it.
True, but knowing what one is measuring is a bit of science too.
What's the theoritical background/experience of OP?
It's actually kind difficult for me to experiment and test things because the Arduino is on a PCB already. It wozld be nice to just to power the thing from my lab psu and then Serial.print the voltages, but as soon as I attach the serial adapter, it powers the Arduino up to 3.3v or something. I do however have a very complex and complicated piece of code working that wakes the Arduino up when a button is pressed and wirelessly sends a packet containing the voltage to another Arduino and then goes back to sleep.
So at the moment I have no way to read multiple measurements without the Arduino going to sleep between each of these, I mean unless I were to spend a few more days on trying to modify the code without breaking everything.
I have no background in electronics or anything the like, I just do this for fun and have been for a few years.
Did You test Your theories on a breadboard before going for a PCB of Your own?
What other Arduino projects did You manage before this one?
I had everything on a breadboard before it put it on a PCB yes.
I wouldn't know where to begin. I've done lots of random Arduino/ESP/Pi projects.
How can I measure the internal voltage of the ATmega328p? Is it exposed to any of the pins?
felic:
Oh are you saying I don't need delay at all? I can just read the voltage 10 times and then use the last result?
Rather than wasting nine reads, why not average them?
After a bunch of trial and error, I figured out that "const long InternalReferenceVoltage = 1091L;" yields the most accurate results for me. With that I consistently get the same readings as my voltmeter down to a 100th of a volt.
Here's some useful information for future readers:
- Adding delays of any kind didn't make any difference whatsoever.
- The first voltage reading is always too low.
- The second voltage reading and any following readings give consistent and accurate results.
- You need to increase/decrease InternalReferenceVoltage for every Arduino individually until you see accurate results.
So this works great for me:
void setup() {
Serial.begin(9600);
Serial.println(getAccurateVoltage());
}
void loop() {}
int getAccurateVoltage() {
getVoltage();
return getVoltage();
}
// Read the voltage of the battery the Arduino is currently running on (in millivolts)
int getVoltage(void) {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // For mega boards
const long InternalReferenceVoltage = 1115L; // Adjust this value to your boards specific internal BG voltage x1000
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else // For 168/328 boards
const long InternalReferenceVoltage = 1091L; // Adjust this value to your boards specific internal BG voltage x1000
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif
ADCSRA |= _BV( ADSC ); // Start a conversion
while( ( (ADCSRA & (1<<ADSC)) != 0 ) ); // Wait for it to complete
int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // Scale the value; calculates for straight line value
return results*10; // convert from centivolts to millivolts
}
If anyone could explain the reason for why the first call to getVoltage() is always inaccurate, even if you add a 30 seconds delay before it that would be awesome.
I thought you just wanted to know when the battery is getting low to save data and shut down.