user4906: I am working on project and using Arduino Pro Mini (Atmega328p running on 2xAA) to measure the time to charge a capacitor (when the volt level is high). This is the code I used while testing:
int counter = 0;

// Charge the capacitor
digitalWrite(8,HIGH);

while (digitalRead(7) == LOW) {
    counter = counter +1;
    if (counter > 250) {
        break; // CHARGING FAILED!
    }
}

The code was working fine when the board was running at 16MHz since the loop was fast enough to give good result. ( counter =~ 28 when the test cap is charged). 
However, the intention is to run the system on a battery with clock of 1MHz (to reduce power consumption) and when tested at that speed the counter only reaches 2~3 because the loop it too slow now that the cap will charge in about two to three cycles.
So I did two changes which are using byte instead of int for the counter, and reading the value of the pin directly from the PIND register:
byte counter = 0;

// Charge the capacitor
digitalWrite(8,HIGH);

while ((PIND & (1<<PD7)) == 0) {
    counter = counter +1;
    if (counter > 250) {
        break; // CHARGING FAILED!
    }
}

Both of these changes increased the speed and now counter reads ~20 which is much better and almost close to the 16MHz.
Is there any further optimizations?
Can I use one of the general registers instead of the counter, if yes then how? and will that improve the speed?
Is there a more clever and faster way to do this loop?


Update:

I am going to follow the suggested answer and use the analog comparator, but I also wanted to add to my finding which might help others with general optimization.
Instead of incrementing the counter and comparing if it is larger than some value, it is faster to decrements and compare if it is equal to zero. The counter improved to ~23.

user368: Get rid of the loop altogether. Instead of twiddling and checking bits manually, use timer 1 to trigger the output and capture the input.
If you perform the output on pin 10 and the input on pin 8 then you can use timer 1's output compare to send the pulse out and its input capture to detect when the capacitor has charged.
Untested:
#include <avr/interrupt.h>

void setup(void)
{
  cli();
  DDRB |= _BV(PB2); // Configure OC1B as output
  TCCR1B &= ~(_BV(CS12) | _BV(CS11) | _BV(CS10)); // Stop timer 1
  TCNT1 = 0; // Initialize timer count
  OCR1A = 0xffff; // Reset the timer at this count
  OCR1B = 0xf000; // Upper limit of the timed value, plenty of time before timer reset
  ICR1 = 0xff00; // Set to an invalid initial value
  TCCR1A = _BV(COM1B1); // Trigger output at 0, clear at upper limit
  TCCR1B = _BV(ICES1); // Capture on leading edge
  TCCR1B |= _BV(WGM13) | _BV(WGM12); // High bits for 16-bit fast PWM
  TCCR1A |= _BV(WGM11) | _BV(WGM10); // Low bits for 16-bit fast PWM
  TIMSK = _BV(ICIE1) | _BV(OCIE1B); // Enable input capture and limit interrupts
  sei();
  TCCR1B |= _BV(CS10); // Start the timer at its highest clock speed
}

ISR(TIMER1_CAPT_vect)
{
  TIMSK &= ~(_BV(ICIE1) | _BV(OCIE1B)); // Disable input and limit interrupts
  TCCR1B &= ~(_BV(CS12) | _BV(CS11) | _BV(CS10)); // Stop the timer
  PORTB &= ~_BV(PB2); // Kill the charging output
  // Check ICR1 for the captured value
}

ISR(TIMER1_COMPB_vect)
{
  if (ICR1 == 0xff00)
  {
    // WELL CRAP, charging is taking too long
    // Maybe try with a slower clock?
  }
}

void loop()
{
  // Do other stuff
}


user10794: It looks like Ignacio Vazquez-Abrams and I have been doing similar things. :)
I have a page about making a capacitor tester:
Turn your Arduino into a capacitor tester
However since link-only replies are frowned on (the link might go down) I'll summarize it here.
The simple approach is to charge the capacitor until it reaches 63.2% of the charging voltage.
That is because:
1 - e^(-1) = 0.63212

See RC Time constant - Wikipedia.
We can use the Analog Comparator to trigger an interrupt when the voltage reaches that level.
We need the capacitor to be on pin D6 on the Uno and a reference voltage on pin D7.
See Using the Arduino Analog Comparator for more details about the Analog Comparator.
This is much faster than using analogRead, because it triggers on an exact voltage.
Your basic objective is to find how long it takes to reach 63.2% of the supplied voltage (in the example being 1 volt):

In this particular example it took 47 µs for a 47 nF capacitor:

Instead of using an exact reference voltage (ie. 63.2% of 5 volts) you can do some fancy maths instead. Here is my test circuit:

DUT = Device Under Test
We plug the values of the resistors into the code like this:
const float Rc = 10000;    // charging resistor
const float R1 = 1000;     // between ground and D7
const float R2 = 1800;     // between +5V and D7
const float clockRate_us = 16;  // 16 MHz
const float k = 1000 / (clockRate_us * Rc * log ((R1 + R2) / R2));

Note: For high accuracy you should use the measured resistance values, not just the nominal ones.

Now with some fairly simple code we can use the constant k to work out the capacitance:
/*
Capacitance meter

Author: Nick Gammon
Date:   2 July 2013

Pulse pin (D2): Connect to capacitor via 10K resistor (Rc)

Reference voltage connected to D7 (AIN1) as per below.

Measure pin (D6 - AIN0) connected to first leg of capacitor, other leg connected to Gnd.

Like this:

Capacitor to test:

D2  ----> Rc ----> D6 ----> capacitor_under_test ----> Gnd

Reference voltage:

+5V ----> R2 ---> D7 ---> R1 ----> Gnd

*/

const byte pulsePin = 2;   // the pin used to pulse the capacitor
const float Rc = 10000;    // charging resistor
const float R1 = 1000;     // between ground and D7
const float R2 = 1800;     // between +5V and D7
const float clockRate_us = 16;  // 16 MHz

const float k = 1000 / (clockRate_us * Rc * log ((R1 + R2) / R2));

volatile boolean triggered;
volatile boolean active;

volatile unsigned long timerCounts;
volatile unsigned long overflowCount;

ISR (TIMER1_OVF_vect)
{
  ++overflowCount;               // count number of Counter 1 overflows  
}  // end of TIMER1_OVF_vect

ISR (TIMER1_CAPT_vect)
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = ICR1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  if (active)
    {
    // if just missed an overflow
    if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)
      overflowCopy++;
    // calculate total count
    timerCounts = (overflowCopy << 16) + timer1CounterValue;  // each overflow is 65536 more
    triggered = true;
    digitalWrite (pulsePin, LOW);  // start discharging capacitor
    TCCR1B = 0;    // stop the timer
    }  // end if active
  }  // end of TIMER1_CAPT_vect

void setup ()
  {
  pinMode (pulsePin, OUTPUT);
  digitalWrite (pulsePin, LOW);

  Serial.begin (115200);
  Serial.println ("Started.");
  ADCSRB = 0;           // (Disable) ACME: Analog Comparator Multiplexer Enable
  ACSR = bit (ACIC);    // Analog Comparator Input Capture Enable
  DIDR1 |= bit (AIN1D) | bit (AIN0D); // Disable digital buffer on comparator inputs
  PRR = 0;
  }  // end of setup

void startTiming ()
  {
  active = true;
  triggered = false;
  noInterrupts ();

  // prepare timer
  overflowCount = 0;            // no overflows yet
  // reset Timer 1
  TCCR1A = 0;             
  TCCR1B = 0;   
  TCNT1 = 0;      // Counter to zero
  // Timer 1 - counts clock pulses
  TIMSK1 = bit (TOIE1) | bit (ICIE1);   // interrupt on Timer 1 overflow and input capture

  // get on with it
  digitalWrite (pulsePin, HIGH);  // start charging capacitor
  // start Timer 1, no prescaler
  TCCR1B =  bit (CS10) | bit (ICES1);  // plus Input Capture Edge Select
  interrupts ();

  } // end of startTiming

void finishTiming ()
  {
  active = false;
  Serial.print ("Capacitance = ");
  float capacitance = (float) timerCounts * k;
  Serial.print (capacitance);
  Serial.println (" nF");
  triggered = false;
  delay (3000);
  }  // end of finishTiming

void loop ()
  {
  // start another test?
  if (!active)
    startTiming ();

  // if the ISR noted the time interval is up, display results
  if (active && triggered)
    finishTiming ();

  }  // end of loop


For extra accuracy the code uses the Input Capture Unit, which is something that remembers the exact value in Timer 1 when the match occurs. This avoids the delay of 2 to 3 µs while the ISR kicks into action.

Results
I measured a few values using a capacitance-substitution box. To check on the box I measured also with a high-precision multimeter. The value on the right is what the sketch gave (rounded).
(All values in nF)
Nominal    Meter     Sketch
Value      Measure   Measure

    40         42        42
   100         98       102
   200        202       201
   300        312       313
   400        389       391
  1000       1004      1010
  2000       2011      2012
  3000       2950      2953
  4000       4160      4170

The sketch output certainly seems to be close to the nominal and measured values.


What about using the internal voltage reference (1.1v) instead of AIN0? which one will be better as the 2xAA batteries voltage drops over time?

The voltage doesn't matter as it is not in the equation. It is the ratio that matters, and that will scale with battery drop (ie. the ratio between the two resistors will always be the same).
You need to use Vcc because it is turned on and off at an output pin (to start charging the capacitor).


Also what is the difference between TIMER1_CAPT_vect which you used here and ANALOG_COMP_vect which you used in the example in your site? 

If you are not using the Input Capture Unit, then you need to get the Analog Comparator interrupt. However if you use the Input Capture Unit then you use the Timer1 Capture Event which is triggered when you get the capture.

4906: <p>I am working on project and using Arduino Pro Mini (Atmega328p running on 2xAA) to measure the time to charge a capacitor (when the volt level is high). This is the code I used while testing:</p>

<pre><code>int counter = 0;

// Charge the capacitor
digitalWrite(8,HIGH);

while (digitalRead(7) == LOW) {
    counter = counter +1;
    if (counter &gt; 250) {
        break; // CHARGING FAILED!
    }
}
</code></pre>

<p>The code was working fine when the board was running at 16MHz since the loop was fast enough to give good result. ( counter =~ 28 when the test cap is charged). </p>

<p>However, the intention is to run the system on a battery with clock of 1MHz (to reduce power consumption) and when tested at that speed the counter only reaches 2~3 because the loop it too slow now that the cap will charge in about two to three cycles.</p>

<p>So I did two changes which are using byte instead of int for the counter, and reading the value of the pin directly from the PIND register:</p>

<pre><code>byte counter = 0;

// Charge the capacitor
digitalWrite(8,HIGH);

while ((PIND &amp; (1&lt;&lt;PD7)) == 0) {
    counter = counter +1;
    if (counter &gt; 250) {
        break; // CHARGING FAILED!
    }
}
</code></pre>

<p>Both of these changes increased the speed and now counter reads ~20 which is much better and almost close to the 16MHz.</p>

<p>Is there any further optimizations?</p>

<p>Can I use one of the general registers instead of the counter, if yes then how? and will that improve the speed?</p>

<p>Is there a more clever and faster way to do this loop?</p>

<hr>

<ul>
<li>Update:</li>
</ul>

<p>I am going to follow the suggested answer and use the analog comparator, but I also wanted to add to my finding which might help others with general optimization.</p>

<p>Instead of incrementing the counter and comparing if it is larger than some value, it is faster to decrements and compare if it is equal to zero. The counter improved to ~23.</p>
 368: <p>Get rid of the loop altogether. Instead of twiddling and checking bits manually, use timer 1 to trigger the output and capture the input.</p>

<p>If you perform the output on pin 10 and the input on pin 8 then you can use timer 1's output compare to send the pulse out and its input capture to detect when the capacitor has charged.</p>

<p>Untested:</p>

<pre><code>#include &lt;avr/interrupt.h&gt;

void setup(void)
{
  cli();
  DDRB |= _BV(PB2); // Configure OC1B as output
  TCCR1B &amp;= ~(_BV(CS12) | _BV(CS11) | _BV(CS10)); // Stop timer 1
  TCNT1 = 0; // Initialize timer count
  OCR1A = 0xffff; // Reset the timer at this count
  OCR1B = 0xf000; // Upper limit of the timed value, plenty of time before timer reset
  ICR1 = 0xff00; // Set to an invalid initial value
  TCCR1A = _BV(COM1B1); // Trigger output at 0, clear at upper limit
  TCCR1B = _BV(ICES1); // Capture on leading edge
  TCCR1B |= _BV(WGM13) | _BV(WGM12); // High bits for 16-bit fast PWM
  TCCR1A |= _BV(WGM11) | _BV(WGM10); // Low bits for 16-bit fast PWM
  TIMSK = _BV(ICIE1) | _BV(OCIE1B); // Enable input capture and limit interrupts
  sei();
  TCCR1B |= _BV(CS10); // Start the timer at its highest clock speed
}

ISR(TIMER1_CAPT_vect)
{
  TIMSK &amp;= ~(_BV(ICIE1) | _BV(OCIE1B)); // Disable input and limit interrupts
  TCCR1B &amp;= ~(_BV(CS12) | _BV(CS11) | _BV(CS10)); // Stop the timer
  PORTB &amp;= ~_BV(PB2); // Kill the charging output
  // Check ICR1 for the captured value
}

ISR(TIMER1_COMPB_vect)
{
  if (ICR1 == 0xff00)
  {
    // WELL CRAP, charging is taking too long
    // Maybe try with a slower clock?
  }
}

void loop()
{
  // Do other stuff
}
</code></pre>
 10794: 

<p>It looks like Ignacio Vazquez-Abrams and I have been doing similar things. :)</p>

<p>I have a page about making a capacitor tester:</p>

<p><a href="http://www.gammon.com.au/forum/?id=12075" rel="nofollow noreferrer">Turn your Arduino into a capacitor tester</a></p>

<p>However since link-only replies are frowned on (the link might go down) I'll summarize it here.</p>

<p>The simple approach is to charge the capacitor until it reaches 63.2% of the charging voltage.</p>

<p>That is because:</p>

<pre class="lang-C++ prettyprint-override"><code>1 - e^(-1) = 0.63212
</code></pre>

<p>See <a href="http://en.wikipedia.org/wiki/RC_time_constant" rel="nofollow noreferrer">RC Time constant - Wikipedia</a>.</p>

<p>We can use the Analog Comparator to trigger an interrupt when the voltage reaches that level.</p>

<p>We need the capacitor to be on pin D6 on the Uno and a reference voltage on pin D7.</p>

<p>See <a href="http://www.gammon.com.au/forum/?id=11916" rel="nofollow noreferrer">Using the Arduino Analog Comparator</a> for more details about the Analog Comparator.</p>

<p>This is much faster than using analogRead, because it triggers on an exact voltage.</p>

<p>Your basic objective is to find how long it takes to reach 63.2% of the supplied voltage (in the example being 1 volt):</p>

<p><a href="https://i.stack.imgur.com/3uMaN.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/3uMaN.png" alt="Capacitor tester 1"></a></p>

<p>In this particular example it took 47 µs for a 47 nF capacitor:</p>

<p><a href="https://i.stack.imgur.com/K1r42.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/K1r42.png" alt="Capacitor tester 2"></a></p>

<p>Instead of using an exact reference voltage (ie. 63.2% of 5 volts) you can do some fancy maths instead. Here is my test circuit:</p>

<p><a href="https://i.stack.imgur.com/snZkL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/snZkL.png" alt="Capacitor test circuit"></a></p>

<p><em>DUT = Device Under Test</em></p>

<p>We plug the values of the resistors into the code like this:</p>

<pre class="lang-C++ prettyprint-override"><code>const float Rc = 10000;    // charging resistor
const float R1 = 1000;     // between ground and D7
const float R2 = 1800;     // between +5V and D7
const float clockRate_us = 16;  // 16 MHz
const float k = 1000 / (clockRate_us * Rc * log ((R1 + R2) / R2));
</code></pre>

<p><strong>Note</strong>: For high accuracy you should use the <em>measured</em> resistance values, not just the nominal ones.</p>

<hr>

<p>Now with some fairly simple code we can use the constant <strong>k</strong> to work out the capacitance:</p>

<pre class="lang-C++ prettyprint-override"><code>/*
Capacitance meter

Author: Nick Gammon
Date:   2 July 2013

Pulse pin (D2): Connect to capacitor via 10K resistor (Rc)

Reference voltage connected to D7 (AIN1) as per below.

Measure pin (D6 - AIN0) connected to first leg of capacitor, other leg connected to Gnd.

Like this:

Capacitor to test:

D2  ----&gt; Rc ----&gt; D6 ----&gt; capacitor_under_test ----&gt; Gnd

Reference voltage:

+5V ----&gt; R2 ---&gt; D7 ---&gt; R1 ----&gt; Gnd

*/

const byte pulsePin = 2;   // the pin used to pulse the capacitor
const float Rc = 10000;    // charging resistor
const float R1 = 1000;     // between ground and D7
const float R2 = 1800;     // between +5V and D7
const float clockRate_us = 16;  // 16 MHz

const float k = 1000 / (clockRate_us * Rc * log ((R1 + R2) / R2));

volatile boolean triggered;
volatile boolean active;

volatile unsigned long timerCounts;
volatile unsigned long overflowCount;

ISR (TIMER1_OVF_vect)
{
  ++overflowCount;               // count number of Counter 1 overflows  
}  // end of TIMER1_OVF_vect

ISR (TIMER1_CAPT_vect)
  {
  // grab counter value before it changes any more
  unsigned int timer1CounterValue;
  timer1CounterValue = ICR1;  // see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  if (active)
    {
    // if just missed an overflow
    if ((TIFR1 &amp; bit (TOV1)) &amp;&amp; timer1CounterValue &lt; 0x7FFF)
      overflowCopy++;
    // calculate total count
    timerCounts = (overflowCopy &lt;&lt; 16) + timer1CounterValue;  // each overflow is 65536 more
    triggered = true;
    digitalWrite (pulsePin, LOW);  // start discharging capacitor
    TCCR1B = 0;    // stop the timer
    }  // end if active
  }  // end of TIMER1_CAPT_vect

void setup ()
  {
  pinMode (pulsePin, OUTPUT);
  digitalWrite (pulsePin, LOW);

  Serial.begin (115200);
  Serial.println ("Started.");
  ADCSRB = 0;           // (Disable) ACME: Analog Comparator Multiplexer Enable
  ACSR = bit (ACIC);    // Analog Comparator Input Capture Enable
  DIDR1 |= bit (AIN1D) | bit (AIN0D); // Disable digital buffer on comparator inputs
  PRR = 0;
  }  // end of setup

void startTiming ()
  {
  active = true;
  triggered = false;
  noInterrupts ();

  // prepare timer
  overflowCount = 0;            // no overflows yet
  // reset Timer 1
  TCCR1A = 0;             
  TCCR1B = 0;   
  TCNT1 = 0;      // Counter to zero
  // Timer 1 - counts clock pulses
  TIMSK1 = bit (TOIE1) | bit (ICIE1);   // interrupt on Timer 1 overflow and input capture

  // get on with it
  digitalWrite (pulsePin, HIGH);  // start charging capacitor
  // start Timer 1, no prescaler
  TCCR1B =  bit (CS10) | bit (ICES1);  // plus Input Capture Edge Select
  interrupts ();

  } // end of startTiming

void finishTiming ()
  {
  active = false;
  Serial.print ("Capacitance = ");
  float capacitance = (float) timerCounts * k;
  Serial.print (capacitance);
  Serial.println (" nF");
  triggered = false;
  delay (3000);
  }  // end of finishTiming

void loop ()
  {
  // start another test?
  if (!active)
    startTiming ();

  // if the ISR noted the time interval is up, display results
  if (active &amp;&amp; triggered)
    finishTiming ();

  }  // end of loop
</code></pre>

<hr>

<p>For extra accuracy the code uses the Input Capture Unit, which is something that remembers the exact value in Timer 1 when the match occurs. This avoids the delay of 2 to 3 µs while the ISR kicks into action.</p>

<hr>

<h3>Results</h3>

<p>I measured a few values using a capacitance-substitution box. To check on the box I measured also with a high-precision multimeter. The value on the right is what the sketch gave (rounded).</p>

<p><em>(All values in nF)</em></p>

<pre class="lang-C++ prettyprint-override"><code>Nominal    Meter     Sketch
Value      Measure   Measure

    40         42        42
   100         98       102
   200        202       201
   300        312       313
   400        389       391
  1000       1004      1010
  2000       2011      2012
  3000       2950      2953
  4000       4160      4170
</code></pre>

<p>The sketch output certainly seems to be close to the nominal and measured values.</p>

<hr>

<blockquote>
  <p>What about using the internal voltage reference (1.1v) instead of AIN0? which one will be better as the 2xAA batteries voltage drops over time?</p>
</blockquote>

<p>The voltage doesn't matter as it is not in the equation. It is the <strong>ratio</strong> that matters, and that will scale with battery drop (ie. the ratio between the two resistors will always be the same).</p>

<p>You need to use Vcc because it is turned on and off at an output pin (to start charging the capacitor).</p>

<hr>

<blockquote>
  <p>Also what is the difference between TIMER1_CAPT_vect which you used here and ANALOG_COMP_vect which you used in the example in your site? </p>
</blockquote>

<p>If you are <strong>not</strong> using the Input Capture Unit, then you need to get the Analog Comparator interrupt. However if you use the Input Capture Unit then you use the Timer1 Capture Event which is triggered when you get the capture.</p>
