Setting up interrupts with the Analog Comparator on a Micro

I am attempting to build an auto-ranging cap meter based off the Micro based off this article
Turn your Arduino into a capacitor tester ... - General Electronics - Arduino Forum.

I am having trouble converting the sample code posted for use on the micro as it does not have AIN1 and the pin mapping is quite different than the Uno. Yes, I could use a Uno or another Arduino but I am attempting to learn something!

In section 23.2 of the ATmega32U4 datasheet it states "It is possible to select any of the ADC13..0 pins to replace the negative input to the Analog Comparator." Taking a stab at it, seems I would need to set ADMUX = B00100000; to set the AIN- to ADC8 (D4 on the Micro I think) leaving my AIN0 input on D7. Am I correct so far?

The rest of the register settings listed in cap meter script three should still apply yes? Also, Exactly WHAT is being counted? Clock cycles?

And last, I was considering using the 3.3v pin as my reference voltage instead of a resistor divider. The Micro seems to get a little warm when I connect the 3.3 to D7. Bad idea?

Capacitance = (Timer_counts/(Resistance_value[Range]*log(1-(3.3/5))));

Keshka

Since this is a programming question please post your code.

Please use code tags.

Read this before posting a programming question

Thank you Nick, will do tomorrow. Nearly midnight here and I need to clean up the code a bit before posting it.

Keshka

test code:

/*

Untested rough draft
Keshka Kotera 27 Jan 2016
basic outline courtesy of Nick Gammon

*/

#include <Wire.h>
#include <Math.h>

#define Analog_pin	D7	// Comparator AIN+ pin for measuring capacitor voltage
#define Charge_pin1	4	// pin to charge .1F (100,000uf) and smaller caps
#define Charge_pin2	5	// pin to charge 100uF and smaller caps
#define Charge_pin3	6	// pin to charge .1uf (100000pf) and smaller caps
#define Charge_pin4	7	// pin to charge 100pF and smaller caps
#define Discharge_pin	8	// pin to discharge the capacitor


char message[80];

unsigned long startTime;
unsigned long elapsedTime;
volatile unsigned long Timer_counts;		//volatile- for vars used in AND out of ISR's (interupt service routines)
volatile unsigned long overflowCount;
unsigned int timer1CounterValue;
unsigned long overflowCopy = overflowCount;
volatile boolean Triggered;
volatile boolean Active;
float Resistance_value[3];
int Charge_pin[3];
int Range = 0;




void setup()
{
	pinMode(Charge_pin1, INPUT);		// set Charge_pin to input (high impedance)
	pinMode(Charge_pin2, INPUT);		// set Charge_pin to input (high impedance)
	pinMode(Charge_pin3, INPUT);		// set Charge_pin to input (high impedance)
	pinMode(Charge_pin4, OUTPUT);		// set Charge_pin to output for range 4
	pinMode(Analog_pin,  INPUT);		// set Analog_pin to input
	digitalWrite(Charge_pin4, LOW);		// turn it off
	pinMode(Discharge_pin, INPUT);		// set Charge_pin to output for range 4
	digitalWrite(Discharge_pin, LOW);	// set to high impedance
	Active = false;				// we have no capacitor to test

	Serial.begin(19200);

	ADCSRB = 0;				// (Disable) ACME: Analog Comparator Multiplexer Enable
	ACSR = bit (ACIC);			// Analog Comparator Input Capture Enable bit (ACIC) of the Analog Comparator Control and Status Register (ACSR)
	DIDR1 |= bit (AIN1D) | bit (AIN0D);	// Disable digital buffer on comparator inputs
	ADMUX = B00100000;			// set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 input on D7
		
		//PRR won't compile----
	//PRR = 0x00;				// turns on this stuff (TWI | TIMER2 | TIMER0 | VOID | TIMER1 | SPI | USART | ADD), PRR=0xFF turns it all off 
						// how to do each PRR=(1<<7)|(0<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);

	digitalWrite(Charge_pin[Range], HIGH);	// set ready for testing
	delay(1000);				// let things stablize
}

void loop() 
{

	if(analogRead((Analog_pin) < 1020) && !Active)	// we have a cap to test!
	{
		delay(100);
		if(analogRead(Analog_pin) < 900) || (Range == 3))	// taking too long, go to next range or we just have a really big cap
		{
			discharge_cap();
			Range++;			// next range
		}
		else					// we have a live one!
		{
			discharge_cap();		// start over
			Active = true;			// start timing loop
			Triggered = true;		// start timing loop
		}
	}

	if (Active && Triggered)
	{
		startTiming();
		Triggered = false;		// only want to start once
	}

	if (!Active && Triggered)
	{
		char Flt_str[15];
		float Capacitance = 0;
		
		Active = false;
		Triggered = false;
		dtostrf(Timer_counts, 8, 2, Flt_str);
		Serial.println(message,"time is %s",Flt_str);		// debug
		
		// calc capicitance  C=-t/R ln(1-(Vc(t)/Vin)) ......Vc(t) is current charge level t is time, R resistance
		Capacitance = (Timer_counts/(Resistance_value[Range]*log(1-(3.3/5))));		// rough draft! not sure what we counted

		dtostrf(Capacitance, 8, 2, Flt_str);
		Serial.println(message,"Capacitance is %s",Flt_str);
	}
}


void startTiming ()
{
	// prepare timer
	noInterrupts ();
	overflowCount = 0;			// no overflows yet
	TCCR1A = 0;				// reset Timer 1          
	TCCR1B = 0;				// reset Timer 1
	TCNT1 = 0;				// Counter to zero
	TIMSK1 = bit (TOIE1) | bit (ICIE1);	// set bits in timer/counter1 (TIMSK1) register for interrupt on Timer 1 overflow (TOIE1) and input capture (ICIE1)

	digitalWrite (Charge_pin[Range], HIGH);	// start charging capacitor
	TCCR1B =  bit (CS10) | bit (ICES1);	// start Timer 1, no prescaler plus Input Capture Edge Select
	interrupts ();				// enable interupts
}

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

ISR (TIMER1_CAPT_vect)
{
	timer1CounterValue = ICR1;		// grab timer count, see datasheet, page 117 (accessing 16-bit registers)

	if (!Active)				// did we finish?
	{
		if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)	// if just missed an overflow
		{
			overflowCopy++;
		}
		Timer_counts = (overflowCopy << 16) + timer1CounterValue;  //calculate total count, each overflow is 65536 more
		Triggered = true;
		TCCR1B = 0;    // stop the timer
	}
}

void discharge_cap()
{
	pinMode(Charge_pin[Range], INPUT);	// set Charge_pin to input (high impedance)
	pinMode(Discharge_pin, OUTPUT);		// set discharge pin to output 
	digitalWrite(Discharge_pin, LOW);	// set discharge pin LOW 
	while(analogRead(Analog_pin) > 0);	// wait until capacitor is completely discharged
	pinMode(Discharge_pin, INPUT); 
}

And last, I was considering using the 3.3v pin as my reference voltage instead of a resistor divider. The Micro seems to get a little warm when I connect the 3.3 to D7. Bad idea?

#define Charge_pin4 7 // pin to charge 100pF and smaller caps

...
  pinMode(Charge_pin4, OUTPUT);  // set Charge_pin to output for range 4
...
  digitalWrite(Charge_pin4, LOW);  // turn it off

Bad idea, because you are shorting 3.3V to ground via pin 7.


            // how to do each PRR=(1<<7)|(0<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);

Try:

power_all_enable();
...
power_all_disable();

See the power macros. (You would need to re-enable bit 6 whatever that is).


From the datasheet:

It is possible to select any of the ADC7...0 pins to replace the negative input to the Analog Comparator. The
ADC multiplexer is used to select this input, and consequently, the ADC must be switched off to utilize this
feature.

You are doing an analogRead which turns the ADC on. You may have to re-think that part.

Plan B! lol,

  1. Was not paying attention to pin numbers on charge pins ---- fixed. Now can I use 3.3v? Should be connected to D7 (set to high impedance input till comparator takes over) (does it need to be reset after comparator use?)
  2. Replace PRR with power_all_enable(); (is this needed for this app? Are not all these on by default?)
  3. Moved enables for comparator into timer begin to avoid interference by analogRead.
/*

/*

Untested rough draft
Keshka Kotera 27 Jan 2016
basic outline courtesy of Nick Gammon

*/

#include <Wire.h>
#include <Math.h>

#define Charge_pin1	3	// pin to charge .1F (100,000uf) and smaller caps
#define Charge_pin2	4	// pin to charge 100uF and smaller caps
#define Charge_pin3	5	// pin to charge .1uf (100000pf) and smaller caps
#define Charge_pin4	6	// pin to charge 100pF and smaller caps
#define Reference_pin	7	// pin used by comparator for reference
#define Discharge_pin	8	// pin to discharge the capacitor
#define Analog_pin	A0	// analog pin for measuring capacitor voltage



char message[80];

unsigned long startTime;
unsigned long elapsedTime;
volatile unsigned long Timer_counts;		//volatile- for vars used in AND out of ISR's (interupt service routines)
volatile unsigned long overflowCount;
unsigned int timer1CounterValue;
unsigned long overflowCopy = overflowCount;
volatile boolean Triggered;
volatile boolean Active;
float Resistance_value[3];
int Charge_pin[3];
int Range = 0;




void setup()
{
	pinMode(Charge_pin1, INPUT);		// set Charge_pin to input (high impedance)
	pinMode(Charge_pin2, INPUT);		// set Charge_pin to input (high impedance)
	pinMode(Charge_pin3, INPUT);		// set Charge_pin to input (high impedance)
	pinMode(Charge_pin4, OUTPUT);		// set Charge_pin to output for range 4
	digitalWrite(Charge_pin[Range], HIGH);	// set ready for testing
	
	pinMode(Analog_pin,  INPUT);		// set Analog_pin to input
	pinMode(Reference_pin, INPUT);		// AIN0 input on D7 set to input (high impedance for ref voltage from 3.3v pin
	digitalWrite(Reference_pin, LOW);	// make sure pull-up resistor is off
	pinMode(Discharge_pin, INPUT);		// set Charge_pin to output for range 4

	digitalWrite(Discharge_pin, LOW);	// set to high impedance
	Active = false;				// we have no capacitor to test

	Serial.begin(19200);

	power_all_enable();			// turns on this stuff (TWI | TIMER2 | TIMER0 | VOID | TIMER1 | SPI | USART | ADD)

}

void loop() 
{

	if(analogRead((Analog_pin) < 1020) && !Active)	// we have a cap to test!
	{
		delay(100);
		if((analogRead(Analog_pin) < 900) || (Range == 3))	// taking too long, go to next range or we just have a really big cap
		{
			discharge_cap();
			Range++;				// next range
		}
		else						// we have a live one!
		{
			discharge_cap();			// start over
			Active = true;				// start timing loop
			Triggered = true;			// start timing loop
			ADCSRB = 0;				// (Disable) ACME: Analog Comparator Multiplexer Enable
			ACSR = bit (ACIC);			// Analog Comparator Input Capture Enable bit (ACIC) of the Analog Comparator Control and Status Register (ACSR)
			DIDR1 |= bit (AIN1D) | bit (AIN0D);	// Disable digital buffer on comparator inputs
			ADMUX = B00100000;			// set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 input on D7
			delay(500);				// settle time
		}
	}

	if (Active && Triggered)
	{
		startTiming();
		Triggered = false;		// only want to start once
	}

	if (!Active && Triggered)
	{
		char Flt_str[15];
		float Capacitance = 0;
		
		Active = false;
		Triggered = false;
		dtostrf(Timer_counts, 8, 2, Flt_str);
		sprintf(message,"time is %s",Flt_str);		// debug
		Serial.print(message);		// debug
		
		// calc capicitance  C=-t/R ln(1-(Vc(t)/Vin)) ......Vc(t) is current charge level t is time, R resistance
		Capacitance = (Timer_counts/(Resistance_value[Range]*log(1-(3.3/5))));		// rough draft! not sure what we counted

		dtostrf(Capacitance, 8, 2, Flt_str);
		sprintf(message,"Capacitance is %s",Flt_str);
		Serial.println(message);
		delay(10000);						// display value for ten seconds
		pinMode(Analog_pin, INPUT);				// reset Analog_pin to input
	}
}


void startTiming ()
{
	// prepare timer
	noInterrupts ();
	overflowCount = 0;			// no overflows yet
	TCCR1A = 0;				// reset Timer 1          
	TCCR1B = 0;				// reset Timer 1
	TCNT1 = 0;				// Counter to zero
	TIMSK1 = bit (TOIE1) | bit (ICIE1);	// set bits in timer/counter1 (TIMSK1) register for interrupt on Timer 1 overflow (TOIE1) and input capture (ICIE1)

	digitalWrite (Charge_pin[Range], HIGH);	// start charging capacitor
	TCCR1B =  bit (CS10) | bit (ICES1);	// start Timer 1, no prescaler plus Input Capture Edge Select
	interrupts ();				// enable interupts
}

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

ISR (TIMER1_CAPT_vect)
{
	timer1CounterValue = ICR1;		// grab timer count, see datasheet, page 117 (accessing 16-bit registers)

	if (!Active)				// did we finish?
	{
		if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)	// if just missed an overflow
		{
			overflowCopy++;
		}
		Timer_counts = (overflowCopy << 16) + timer1CounterValue;  //calculate total count, each overflow is 65536 more
		Triggered = true;
		TCCR1B = 0;    // stop the timer
	}
}

void discharge_cap()
{
	pinMode(Charge_pin[Range], INPUT);	// set Charge_pin to input (high impedance)
	pinMode(Discharge_pin, OUTPUT);		// set discharge pin to output 
	digitalWrite(Discharge_pin, LOW);	// set discharge pin LOW 
	while(analogRead(Analog_pin) > 0);	// wait until capacitor is completely discharged
	pinMode(Discharge_pin, INPUT); 
}

Now can I use 3.3v?

I don't see why not.

  1. Replace PRR with power_all_enable(); (is this needed for this app? Are not all these on by default?)

Power is normally enabled.

  1. Moved enables for comparator into timer begin to avoid interference by analogRead.

So is it working now?

test result to follow!
stay tuned!

Nick, how would the following statement be done using bit()?

ADMUX = B00100000; // set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 input on D7

Also, in script one and two of your capacitance meter example you use:
ACSR = bit (ACI) // (Clear) Analog Comparator Interrupt Flag
| bit (ACIE) // Analog Comparator Interrupt Enable
| bit (ACIS0) | bit (ACIS1); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on rising edge)

but on script three, only:
ACSR = bit (ACIC); // Analog Comparator Input Capture Enable

I don't follow why the bits have changed. After reading the data sheet for the ATmega32U4 it appears that all four bits would need to be set properly.

No, it doesn't work....
enters timing routine but never ends.

/*

Untested rough draft
Keshka Kotera 27 Jan 2016
basic outline courtesy of Nick Gammon

*/

#include <Wire.h>
#include <Math.h>

#define Charge_pin1 3 // pin to charge .1F (100,000uf) and smaller caps
#define Charge_pin2 4 // pin to charge 100uF and smaller caps
#define Charge_pin3 5 // pin to charge .1uf (100000pf) and smaller caps
#define Charge_pin4 12 // pin to charge 100pF and smaller caps
#define Reference_pin 7 // pin used by comparator for reference
#define Analog_pin A0 // analog pin for measuring capacitor voltage



char message[80];

unsigned long startTime;
unsigned long elapsedTime;
volatile unsigned long Timer_counts; //volatile- for vars used in AND out of ISR's (interupt service routines)
volatile unsigned long overflowCount;
unsigned int timer1CounterValue;
unsigned long overflowCopy = overflowCount;
volatile boolean Triggered;
volatile boolean Active;
float Resistance_value[] = {250000000000, 250000000, 250000, 250};
int Charge_pin[] = {Charge_pin4, Charge_pin3, Charge_pin2, Charge_pin1};
int Range = 0;
unsigned long Previous_millis = 0;      





void setup()
{
 pinMode(Charge_pin1, INPUT); // set Charge_pin to input (high impedance)
 pinMode(Charge_pin2, INPUT); // set Charge_pin to input (high impedance)
 pinMode(Charge_pin3, INPUT); // set Charge_pin to input (high impedance)
 pinMode(Charge_pin4, OUTPUT); // set Charge_pin to output for range 4
 digitalWrite(Charge_pin[Range], HIGH); // set ready for testing
 
 pinMode(Analog_pin,  INPUT); // set Analog_pin to input, will be pulled high by the current charge pin if no cap
 pinMode(Reference_pin, INPUT); // AIN0 input on D7 set to input (high impedance for ref voltage from 3.3v pin
 digitalWrite(Reference_pin, LOW); // make sure pull-up resistor is off

 Active = false; // we have no capacitor to test

 Serial.begin(19200);
 Previous_millis = millis(); 

}

void loop() 
{
 if(millis() - Previous_millis > 5000)  // only update every 5 seconds
 {
 Serial.print("analog pin = ");
 Serial.println(analogRead(Analog_pin));
 Serial.println(Active);
 Previous_millis = millis(); 
 }


 if((analogRead(Analog_pin) < 1020) && !Active) // we have a cap to test!
 {
 discharge_cap(); // start over
 ADCSRB |= bit (ACME); // (Disable) ACME: Analog Comparator Multiplexer Enable
 ADCSRA |= bit (ADEN); // (Disable) ADEN: Analoge digital converter disable (ADC)
 ACSR = bit (ACI) // (Clear) Analog Comparator Interrupt Flag
 | bit (ACIC) // Analog Comparator Input Capture Enable bit (ACIC) of the Analog Comparator Control and Status Register (ACSR)
 | bit (ACIE) // Analog Comparator Interrupt Enable
 | bit (ACIS0) | bit (ACIS1); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on rising edge)
 DIDR1 |= bit (AIN0D); // Disable digital buffer on comparator inputs
 ADMUX = B00100000; // set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 (AIN+) input on D7
 delay(500); // settle time
 Serial.println("Starting timer");

 // prepare timer
 noInterrupts ();
 overflowCount = 0; // no overflows yet
 TCCR1A = 0; // reset Timer 1          
 TCCR1B = 0; // reset Timer 1
 TCNT1 = 0; // Counter to zero
 TIMSK1 = bit (TOIE1) | bit (ICIE1); // set bits in timer/counter1 (TIMSK1) register for interrupt on Timer 1 overflow (TOIE1) and input capture (ICIE1)
 Active = true;
 digitalWrite (Charge_pin[Range], HIGH); // start charging capacitor
 TCCR1B =  bit (CS10) | bit (ICES1); // start Timer 1, no prescaler plus Input Capture Edge Select
 interrupts (); // enable interupts
 }

 if (Triggered)
 {
 char Flt_str[15];
 float Capacitance = 0;
 
 Triggered = false;
 Active = false;
 dtostrf(Timer_counts, 8, 2, Flt_str);
 sprintf(message,"time is %s",Flt_str); // debug
 Serial.print(message); // debug
 
 // calc capicitance  C=-t/R ln(1-(Vc(t)/Vin)) ......Vc(t) is current charge level t is time, R resistance
 Capacitance = (Timer_counts/(Resistance_value[Range]*log(1-(3.3/5)))); // rough draft! not sure what we counted

 dtostrf(Capacitance, 8, 2, Flt_str);
 sprintf(message,"Capacitance is %s",Flt_str);
 Serial.println(message);
 delay(10000); // display value for ten seconds
 pinMode(Analog_pin, INPUT); // reset Analog_pin to input
 }
}

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

ISR (TIMER1_CAPT_vect)
{
 timer1CounterValue = ICR1; // grab timer count, see datasheet, page 117 (accessing 16-bit registers)

 if (!Active) // did we finish?
 {
 if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF) // if just missed an overflow
 {
 overflowCopy++;
 }
 Timer_counts = (overflowCopy << 16) + timer1CounterValue;  //calculate total count, each overflow is 65536 more
 Triggered = true;
 TCCR1B = 0;    // stop the timer
 }
}

void discharge_cap()
{
 Serial.println("start discharge");
 pinMode(Charge_pin[Range], INPUT); // set Charge_pin to input (high impedance)
 pinMode(Charge_pin4, OUTPUT); // Use our lowest resistance pin for discharge
 digitalWrite(Charge_pin4, LOW); // set it to LOW 
 while(analogRead(Analog_pin) > 0); // wait until capacitor is completely discharged
 pinMode(Charge_pin4, INPUT); // put pin back to high impedance 
 Serial.println("end discharge");
}

Keshka:
Nick, how would the following statement be done using bit()?
ADMUX = B00100000; // set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 input on D7

You count bits from the right, starting at zero, so it would be:

ADMUX = bit (5);

However looking at the datasheet that bit doesn't seem to do what your comments there say.

Thank you Nick.
From what I read in your tutorial, that would set bit five and leave the others as they are. How would that format be used to make sure the remaining bits are off? ADMUX = !Bit(6) perhaps? My goal here was to follow "clarity" guide lines and name the bits as you demonstrated here:
ACSR = bit (ACI) // (Clear) Analog Comparator Interrupt Flag
not sure with something with a name like MUX5..0

My information comes from this datasheet listed for the Arduino Micro:
http://www.atmel.com/Images/Atmel-7766-8-bit-AVR-ATmega16U4-32U4_Datasheet.pdf

24.9.1 ADC Multiplexer Selection Register – ADMUX pg 313, 314

AIN- can only be connected to the ADC multiplexer. pg 293

23.2 Analog Comparator Multiplexed Input
It is possible to select any of the ADC13..0 pins to replace the negative input to the Analog Comparator. The
ADC multiplexer is used to select this input, and consequently, the ADC must be switched off to utilize this
feature. If the Analog Comparator Multiplexer Enable bit (ACME in ADCSRB) is set and the ADC is switched off
(ADEN in ADCSRA is zero), and MUX2..0 in ADMUX select the input pin to replace the negative input to the
Analog Comparator, as shown in the table. pg 295

Table 23-2. seems to show a subset of the ADC pins where as Table 24-4. seems to show the entire set. I do not understand why page 295 refers to those bits in the register as MUX2..0 while pg 313 refers to them as MUX5..0. I assume it is just a shorthand to identify the last six bits?

Keshka:
Thank you Nick.
From what I read in your tutorial, that would set bit five and leave the others as they are.

ADMUX = bit (5);

No, that sets bit five to 1 and the others to zero, as that is an assignment.

To set bit five to 1, and leave the others alone, you do this:

ADMUX |= bit (5);

To clear bit 5 (only) you do this:

ADMUX &= ~bit (5);

I assume it is just a shorthand to identify the last six bits?

It looks like the relevant bits in the first table are the low-order three, so that is all they showed.

MUX2..0

Yes, that is their notation for MUX register, bits 0 to 2 (low-order three bits).

Thank you Nick!
That clears up a great deal on bit wise manipulation.

Here is the latest script? Does it look like I have the registers configured correctly per the spec sheet? Something is not quite right. On connection of a test capacitor (47uf) It seems to come out of the input compare too quickly and then on when the program cycles for the second attempt, it gets stuck and the comparitor never fires.

Current output:
analog pin = 1023
analog pin = 1023
analog pin = 1023
start discharge
end discharge
analog pin = 29
Starting timer
in capt
Number of counts 65659.00
start discharge
end discharge
analog pin = 1
analog pin = 8
start discharge
end discharge
analog pin = 1
Starting timer

Current version:

/*

Untested rough draft
Keshka Kotera 27 Jan 2016
basic outline courtesy of Nick Gammon

*/

#include <Wire.h>
#include <Math.h>

#define Charge_pin4 12 // pin to charge 100pF and smaller caps
#define Reference_pin 7 // pin used by comparator for reference
#define Analog_pin A0 // analog pin for measuring capacitor voltage



char message[80];

unsigned long startTime;
unsigned long elapsedTime;
volatile unsigned long Timer_counts; //volatile- for vars used in AND out of ISR's (interupt service routines)
volatile unsigned long overflowCount;
unsigned int timer1CounterValue;
unsigned long overflowCopy = overflowCount;
volatile boolean Triggered;
volatile boolean Active;
float Resistance_value = 330; 
unsigned long Previous_millis = 0;      





void setup()
{
 
 pinMode(Analog_pin,  INPUT); // set Analog_pin to input, will be pulled high by the current charge pin if no cap
 pinMode(Reference_pin, INPUT); // AIN0 input on D7 set to input (high impedance for ref voltage from 3.3v pin
 digitalWrite(Reference_pin, LOW); // make sure pull-up resistor is off

 Active = false; // we have no capacitor to test

 Serial.begin(19200);
 Previous_millis = millis(); 
 pinMode(Charge_pin4, OUTPUT); // set Charge_pin to output for range 4
 digitalWrite(Charge_pin4, HIGH); // set ready for testing

}

void loop() 
{
 if((millis() - Previous_millis > 5000) && !Active) // only update every 5 seconds
 {
 Serial.print("analog pin = ");
 Serial.println(analogRead(Analog_pin));
 Previous_millis = millis(); 
 }


 if((analogRead(Analog_pin) < 1020) && !Active) // we have a cap to test!
 {
 discharge_cap(); // start over
 Serial.println("Starting timer");
 ADCSRB |= bit (ACME); // (Disable) ACME: Analog Comparator Multiplexer Enable
 ADCSRA |= bit (ADEN); // (Disable) ADEN: Analoge digital converter disable (ADC)
 ACSR = bit (ACI) // (Clear) Analog Comparator Interrupt Flag
 | bit (ACIC) // Analog Comparator Input Capture Enable bit (ACIC) of the Analog Comparator Control and Status Register (ACSR)
 | bit (ACIE) // Analog Comparator Interrupt Enable
 | bit (ACIS0) | bit (ACIS1); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on rising edge)
 DIDR1 |= bit (AIN0D); // Disable digital buffer on comparator inputs
 ADMUX = B00100000; // set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 (AIN+) input on D7

 // prepare timer
 noInterrupts ();
 overflowCount = 0; // no overflows yet
 TCCR1A = 0; // reset Timer 1          
 TCCR1B = 0; // reset Timer 1
 TCNT1 = 0; // Counter to zero
 TIMSK1 = bit (TOIE1) | bit (ICIE1); // set bits in timer/counter1 (TIMSK1) register for interrupt on Timer 1 overflow (TOIE1) and input capture (ICIE1)
 Active = true;
 TCCR1B =  bit (CS10) | bit (ICES1); // start Timer 1, no prescaler plus Input Capture Edge Select
 digitalWrite (Charge_pin4, HIGH); // start charging capacitor
 interrupts (); // enable interupts
 }

 if (Triggered)
 {
 char Flt_str[15];
 float Capacitance = 0;
 
 Triggered = false;
 Active = false;
 dtostrf(Timer_counts, 8, 2, Flt_str);
 sprintf(message,"Number of counts %s",Flt_str); // debug
 Serial.print(message); // debug
 
 // calc capicitance  C=-t/R ln(1-(Vc(t)/Vin)) ......Vc(t) is current charge level t is time, R resistance
 // Capacitance = (Timer_counts/(Resistance_value*log(1-(3.3/5)))); // rough draft! not sure what we counted

 // dtostrf(Capacitance, 8, 2, Flt_str);
 // sprintf(message,"Capacitance is %s",Flt_str);
 // Serial.println(message);
 delay(10000); // display value for ten seconds
 discharge_cap(); // drain the cap. get ready for next read
 pinMode(Analog_pin, INPUT); // reset Analog_pin to input
 }
}

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

ISR (TIMER1_CAPT_vect)
{
 timer1CounterValue = ICR1; // grab timer count, see datasheet, page 117 (accessing 16-bit registers)
 Serial.println("in capt");

 if (Active) // did we finish?
 {
 if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF) // if just missed an overflow
 {
 overflowCopy++;
 }
 Timer_counts = (overflowCopy << 16) + timer1CounterValue;  //calculate total count, each overflow is 65536 more
 Triggered = true;
 TCCR1B = 0;    // stop the timer
 }
}

void discharge_cap()
{
 Serial.println("start discharge");
 digitalWrite(Charge_pin4, LOW); // set it to LOW 
 while(analogRead(Analog_pin) > 0); // wait until capacitor is completely discharged
 Serial.println("end discharge");
 Serial.print("analog pin = ");
 Serial.println(analogRead(Analog_pin));
 digitalWrite(Charge_pin4, HIGH); // set it back to high
}
ISR (TIMER1_CAPT_vect)
{
 timer1CounterValue = ICR1; // grab timer count, see datasheet, page 117 (accessing 16-bit registers)
 Serial.println("in capt");

How many times do I have to say this? Don't do serial prints in an ISR.

Thanks Nick;
Could I have a little more detail please? I would expect the print to have quite an impact on timing but other than slow down the routine does it disturb the program flow? I placed it there for debugging to see if that ISR was even being called.

Removing the Serial print did not stop the program from hanging.

analog pin = 1023
analog pin = 1023
analog pin = 1023
analog pin = 1023
start discharge
end discharge
analog pin = 0
Starting timer
Number of counts 65646.00start discharge
end discharge
analog pin = 0
analog pin = 6
start discharge
end discharge
analog pin = 1
Starting timer

Prints are placed in a buffer so it wouldn't necessarily slow down program flow. If the buffer fills up it waits for it to empty. It will never empty in an ISR so it will hang.

As for the problems, try clearing the flag that indicates you have got an input capture interrupt before enabling interrupts:

    Active = true;
    TIFR1 = bit (ICF1);  // *clear* ICF1

Some times one has to go back to square one......

More reading.....looks like I had the AIN0 and AIN1 input signals reversed (see schematic above)

...When the voltage on the positive pin AIN0 is higher than the voltage on the negative pin
AIN1, the Analog Comparator output, ACO, is set...

There for, my ref needed to be on AIN1 ...the AIN-, ADC8 (D4 on the Micro) after I set it with the ADMUX = B00100000;

my changing voltage, the capacitor goes on the AIN0 ....the AIN+, (D7 on the Micro).

I made a quick and dirty hook up. One jumper from 3.3v to D4 and another jumper from D7 to D12. Then this script works. I can un-comment the falling edge code, comment out the rising edge and see the results in the output.

/*
this works on the micro
*/



volatile boolean triggered;
unsigned long Previous_millis = 0;      
boolean toggle;



void setup ()
{
 pinMode(12, OUTPUT); // set Charge_pin to output
 digitalWrite(12, LOW); // set ready for testing
 Serial.begin (115200);
 delay(4000); // couple seconds to get the serial monitor open
 Serial.println ("Started.");
 Previous_millis = millis();

 delay(2000); // couple seconds to get the serial monitor open

 ADCSRB = 0; // (Disable) ACME: Analog Comparator Multiplexer Enable
 ACSR =  bit (ACI) // (Clear) Analog Comparator Interrupt Flag
 | bit (ACIE) // Analog Comparator Interrupt Enable
 // | bit (ACIS1); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on falling edge)
 | bit (ACIS1) | bit (ACIS0); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on rising edge)
 ADMUX = B00100000; // set the AIN- to ADC8 (D4 on the Micro) leaving AIN0 input on D7

}  // end of setup

void loop ()
{
 
 if(millis() - Previous_millis > 2000)
 {
 if(toggle == 1)
 {
 Serial.println ("charge.");
 digitalWrite(12, HIGH); // start charging
 toggle = 0;
 }
 else
 {
 Serial.println ("discharge.");
 digitalWrite(12, LOW); // start charging
 toggle = 1;
 }
 Previous_millis = millis(); 
 }

 if (triggered)
 {
 Serial.println ("Triggered!"); 
 triggered = false;
 }

}  // end of loop

ISR (ANALOG_COMP_vect)
{
 triggered = true;
}

output:

Started.
discharge.
charge.
Triggered!
discharge.
charge.
Triggered!
discharge.
charge.
Triggered!

Ok! Next question,
Just what are these counts from Timer1? Nick, I see in your example that you multiply the counts time 1000 then divide by 16. (the micro also has a 16 mhz clock)

From my diagnostic output on the serial monitor my count is approximately 59850
X 1000 / 16 = 3738875

Using this formula: t = -RC*ln(1-(V/Vc(t)))
with V=5v, Vc(t)=3.3v, R=330ohms and C=47uF
I get a time of 0.016732337848
If I did my math right, it doesn't resemble 3738875 at all.

DIAGNOSTIC OUTPUT:
analog pin = 1023
analog pin = 1023
analog pin = 1023
analog pin = 1023
analog pin = 1023
start discharge
end discharge
analog pin = 1
start discharge
end discharge
analog pin = 1
Number of counts 59860.00
start discharge
end discharge
analog pin = 1
analog pin = 1
start discharge
end discharge
analog pin = 1
Number of counts 59833.00
start discharge
end discharge
analog pin = 0
analog pin = 1
start discharge
end discharge
analog pin = 0
Number of counts 59822.00

CURRENT SCHEMATIC:

CURRENT SCRIPT:

/*
Untested rough draft
Keshka Kotera 7 Feb 2016
*/

#include <Math.h>

#define Charge_pin4 12 // pin to charge 100pF and smaller caps
#define CapPositive_pin 7 // pin used by comparator for reference
#define Analog_pin A0 // analog pin for measuring capacitor voltage

char message[80];

volatile unsigned long Timer_counts; //volatile- for vars used in AND out of ISR's (interupt service routines)
volatile unsigned long overflowCount;
unsigned int timer1CounterValue;
unsigned long overflowCopy = overflowCount;
volatile boolean Triggered;
volatile boolean Active;
float Resistance_value = 330; 
unsigned long Previous_millis = 0;      
int times;

void setup()
{
 
 pinMode(Analog_pin,  INPUT); // set Analog_pin to input, will be pulled high by the current charge pin if no cap
 pinMode(4, INPUT); // set D4 (our AIN- later) to input
 digitalWrite(4, LOW); // make sure pull-up resistor is off so as not to load the 3.3v ref
 pinMode(CapPositive_pin, INPUT); // AIN0 (PE6) the + input on D7 on the Micro cap to test here.
 digitalWrite(CapPositive_pin, LOW); // make sure pull-up resistor is off

 Active = false; // we have no capacitor to test

 Serial.begin(19200);
 Previous_millis = millis(); 
 pinMode(Charge_pin4, OUTPUT); // set Charge_pin to output for range 4
 digitalWrite(Charge_pin4, HIGH); // set ready for testing

 ADCSRB = 0; // (Disable) ACME: Analog Comparator Multiplexer Enable
 ACSR = bit (ACI) // (Clear) Analog Comparator Interrupt Flag
 | bit (ACIC) // Analog Comparator Input Capture Enable bit (ACIC) of the Analog Comparator Control and Status Register (ACSR)
 | bit (ACIE) // Analog Comparator Interrupt Enable
 | bit (ACIS0) | bit (ACIS1); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on rising edge)
 ADMUX = B00100000; // set the AIN- to ADC8 (D4 on the Micro) for our reference voltage


}

void loop() 
{
 if(millis() - Previous_millis > 5000) // only update every 5 seconds
 {
 Serial.print("analog pin = ");
 Serial.println(analogRead(Analog_pin));
 Previous_millis = millis(); 
 if(times++ > 3) // my auto start for testing when cap is already charged 
 {
 discharge_cap();
 times = 0;
 }
 }


 if((analogRead(Analog_pin) < 1020) && !Active) // we have a cap to test!
 {
 Active = true;
 discharge_cap(); // start over
 // prepare timer
 noInterrupts ();
 overflowCount = 0; // no overflows yet
 TCCR1A = 0; // reset Timer 1          
 TCCR1B = 0; // reset Timer 1
 TIFR1 = bit (ICF1); // *clear* ICF1
 TCNT1 = 0; // Counter to zero
 TIMSK1 = bit (TOIE1) | bit (ICIE1); // set bits in timer/counter1 (TIMSK1) register for interrupt on Timer 1 overflow (TOIE1) and input capture (ICIE1)
 TCCR1B =  bit (CS10) | bit (ICES1); // start Timer 1, no prescaler plus Input Capture Edge Select
 digitalWrite (Charge_pin4, HIGH); // start charging capacitor
 interrupts (); // enable interupts
 }

 if (Triggered)
 {
 char Flt_str[15];
 float Capacitance = 0;
 
 Triggered = false;
 Active = false;
 dtostrf(Timer_counts, 8, 2, Flt_str);
 sprintf(message,"Number of counts %s",Flt_str); // debug
 Serial.println(message); // debug
 
 // calc capicitance  C=-t/R ln(1-(Vc(t)/Vin)) ......Vc(t) is current charge level t is time, R resistance
 // Capacitance = (Timer_counts/(Resistance_value*log(1-(3.3/5)))); // rough draft! not sure what we counted
 // dtostrf(Capacitance, 8, 2, Flt_str);
 // sprintf(message,"Capacitance is %s",Flt_str);
 // Serial.println(message);
 delay(10000); // display value for ten seconds
 discharge_cap(); // drain the cap. get ready for next read
 pinMode(Analog_pin, INPUT); // reset Analog_pin to input
 }
}

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

ISR (TIMER1_CAPT_vect)
{
 timer1CounterValue = ICR1; // grab timer count, see datasheet, page 117 (accessing 16-bit registers)

 if (Active) // did we finish?
 {
 if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF) // if just missed an overflow
 {
 overflowCopy++;
 }
 Timer_counts = (overflowCopy << 16) + timer1CounterValue;  //calculate total count, each overflow is 65536 more
 Triggered = true;
 TCCR1B = 0;    // stop the timer
 }
}

ISR (ANALOG_COMP_vect) // hangs if this ISR does not exist
{
 int do_something;
 do_something = 1;
 do_something = 10;
 do_something = 100;
}

void discharge_cap()
{
 Serial.println("start discharge");
 digitalWrite(Charge_pin4, LOW); // set it to LOW 
 while(analogRead(Analog_pin) > 0); // wait until capacitor is completely discharged
 Serial.println("end discharge");
 Serial.print("analog pin = ");
 Serial.println(analogRead(Analog_pin));
}