Thats a nice circuit.
Thanks!
I decided to add back in the code I had that allows you to read Vcc without an external divider, and re-run my test. (It's a clever little piece of code that I got online - maybe from this forum? It uses Vcc as the A/D reference, and compares the Vcc voltage to the internal 1.10V ref.) I use this now in all of my portable Arduino projects, so that I can see the battery voltage at startup, without the need for a pair of resistors.
This code, which comes before Setup, sets the reference to Vcc, so then it takes even longer if you want to use the internal reference later in your sketch, because Vref now has to decay from Vcc to 1.10V.
I've attached a scope photo. In this case, with Vcc=3.0V, it took 3.1msec for Vref to decay and reach 1.10V. Using my loop test in the code below, it took ten consecutive A/D readings before it was correct. If Vcc had been 5V, it would of course taken even longer.
I realize this isn't rocket science, but a warning to anyone who switches from using Vcc to the internal reference that you should wait several msec (for 5V apps, probably five msec or more), even after the first A/D read, before you do a reading you care about.
// This is a test to see when the Internal Reference is actually enabled
// and how long it takes to rise and reach regulation
// Rev 2.0, 1/22/2024, D. Salerno
int count = 0; // A/D reading
int enable = 10; // Trigger output for 'scope
int isense = A0; // This is the A/D input pin that is used
int n = 0; // Counter
// This measures the battery voltage at Startup, without needing a resistor divider
long readVcc() { // This measures the Vcc voltage, using the internal reference to compare it to
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(20); // Allow time for the reference to settle
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA, ADSC));
long result = ADCL;
result |= ADCH << 8;
result = 1135530L / result; // Back-calculate AVcc in mV (1.1V * 1023 * 1000)
return result;
}
void setup() {
Serial.begin(9600);
analogReference(INTERNAL); // Use the internal 1.10V reference for the A/D
pinMode(enable, OUTPUT);
digitalWrite(enable, LOW); // Command enable Low - use this as a time reference and trigger source
float Vcc = readVcc(); // gives the Vcc voltage in mV
Serial.print("Vcc =");
Serial.print(Vcc/1000);
Serial.println(" V");
}
void loop() {
while (n < 20) {
digitalWrite(enable, HIGH); // Set enable high - use this as a time reference
count = analogRead(isense); // read the A/D again
Serial.println(count); // Compare readings
n++;
}
Serial.println("done");
delay(2000);
}
Here's another couple of scope photos. The top trace is the Vref pin and the bottom trace is a digital output that goes high immediately before the first analog read.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.