Pages: [1] 2   Go Down
Author Topic: Analog Comparator Interrupt  (Read 6397 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 1
Posts: 186
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've had a read around this subject and want to confirm that my understanding is correct, I am using an Arduino board that has an ATMega 1280 chip.

As I understand it, the Analog Comparator can be set up to trigger an interrupt when the voltage on the A1 pin exceeds the voltage on the A0 pin. So presumably if I connect a potentiometer to A0 can set the trigger voltage to a suitable threshold (I'm looking at something that swings from around 2.5v to 1v)?

Can I set it up to trigger an interrupt if the voltage at A1 falls below A0?
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can set it up to trigger an interrupt on either edge of the comparator output or on a toggle.  RTM
Logged

Experience, it's what you get when you were expecting something else.

Offline Offline
Full Member
***
Karma: 1
Posts: 186
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the reply, any hints on how to do that? Also is the potentiometer approach for setting the threshold ok, is ther a better alternative?
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The analog comparator is all documented in Chapter 23 of the datasheet/manual.  You will want to download the big version of the datasheet to get detailed information.  I could set it all up for you, but you wouldn't learn anything.  Start by looking at the datasheet and then come back with your questions after doing some research of your own.  I'll be happy to help then.
Logged

Experience, it's what you get when you were expecting something else.

Offline Offline
Full Member
***
Karma: 1
Posts: 186
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, thanks. The issue I usually have is converting datasheet info into Arduino code, it's all well and good the datasheet giving a bit pattern on a register but what is that in Arduino code?

The first para of section 25 says
Quote
...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...

Table 25.2 says
Quote
Bits 1, 0 – ACIS1, ACIS0: Analog Comparator Interrupt Mode Select
...
1, 0,  Comparator Interrupt on Falling Output Edge
1, 1, Comparator Interrupt on Rising Output Edge

If I want an interrupt when the analog value falls Below a given voltage I assume I need to set Bits 1,0 to 1,1?  Still no clude how to write Arduino code to do that though????
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 186
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bump!

Still trying to understand how I write Arduino code (as opposed to AVR machine code) to do this...
Logged

Offline Offline
Full Member
***
Karma: 5
Posts: 207
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Typically arduino code doesn't have functions for low level stuff like this. You'll have to use good old avr register writes.
Logged

Denmark
Offline Offline
Edison Member
*
Karma: 35
Posts: 1072
Happy Hobbyist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

As an inspiration, here how you coul set up the comparator on a Attiny2313:

http://kalshagar.wikispaces.com/attiny2313
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't of any library that you can use to make it simpler, so you'll pretty much have to code things the same way that you'd do it in assembler.  I will make a test program today for my Uno that uses the analog comparator. 
Logged

Experience, it's what you get when you were expecting something else.

Denmark
Offline Offline
Edison Member
*
Karma: 35
Posts: 1072
Happy Hobbyist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

There is no reason to use  assembler.
In my test code below, I set the relevant bits according to the datasheet

Although this is for Attiny2313, I think you could adopt it for the 1280

It is more or less the code I posted earlier http://kalshagar.wikispaces.com/attiny2313

Code:

#include <avr/interrupt.h>
#include <TinyDebugKnockBang.h>
  int a=0;
  static volatile uint8_t capture;
  static volatile uint8_t flag;
  const uint8_t led = 13;
 
//Interrupt code of the comparator
// NB : you need to stabilize the power rail with a capacitor (otherwise you'll have ripples and misreading). With AIN1=Comp-=0v a 200uF is fine.
ISR(ANA_COMP_vect) {
 
    //with this test, ensure that indeed the interrupt result is 1 = V(AIN0) > V(AIN1)
    //(double check ?)
    if ( (ACSR & (1 << ACO))== 0 ) {
        flag=true;
        }
      else
      {
      flag=false;
      }
}
 

void setup() {
    //factory settings is to divide internal clock 8MHz by 8.
    //don't, and just run at 8 MHz (set the clock divider to 1 so no effect)
     Debug.begin(250000);
     pinMode(led,OUTPUT);   
    CLKPR = (1<<CLKPCE);
    CLKPR = 0; // Divide by 1
 
    PORTB &= ~(1<<PB0);    // no Pull-up on PB0
 
    ACSR  |=  (1<<ACI);    // clear Analog Comparator interrupt
    ACSR  |=
        (0<<ACD)   |         // Comparator ON
        (0<<ACBG)  |         // Disconnect 1.23V reference from AIN0 (use AIN0 and AIN1 pins)
        (1<<ACIE)  |         // Comparator Interrupt enabled
        (0<<ACIC)  |         // input capture disabled
        (0<<ACIS1) |         // set interrupt bit on rising edge
        (0<<ACIS0);          //    (ACIS1 and ACIS0 == 11)
   // Enable the interrupt
  ACSR = ACSR | (1 << ACIE);
 
    sei();                 // enable global interrupts
 
 
}
 
   void loop() {/*all the job is done in the interrupt */
     
    //    Debug.println(flag);
       if (flag==true){
       digitalWrite(led,HIGH);
       
       }
      if (flag==false){
       digitalWrite(led,LOW);
       }

    }
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's what I meant, I didn't mean I was going to write him an actual assembly language program.  I was referring to the fact that the OP will have to refer to register and bit names and positions to set it up.  Just like in your example.  Libraries generally eliminate (or at least abstract) that to insulate users from having to know the gory details and also to make programs more portable. 
Logged

Experience, it's what you get when you were expecting something else.

Denmark
Offline Offline
Edison Member
*
Karma: 35
Posts: 1072
Happy Hobbyist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, I was just looking in the 328 datasheet, I think the only difference will be the name of the Interrupt vector name:

ANALOG_COMP_vect
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 186
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks guys, that's really useful

<<Edit>>
meant to ask, is there some documentation on names like "ACIS0", or is it safe to assume if it's in the datasheet it exists in Arduino land?
« Last Edit: February 25, 2013, 12:13:19 pm by sirch » Logged

Denmark
Offline Offline
Edison Member
*
Karma: 35
Posts: 1072
Happy Hobbyist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In the datasheet for 1280 it is page 271 and a couple of pages more

page 272 for example:

Quote
• Bits 1, 0 – ACIS1, ACIS0: Analog Comparator Interrupt Mode Select
These bits determine which comparator events that trigger the Analog Comparator interrupt.
The different settings are shown in Table 121.
When changing the ACIS1/ACIS0 bits, the Analog Comparator Interrupt must be disabled
by clearing its Interrupt Enable bit in the ACSR Register. Otherwise an interrupt
can occur when the bits are changed.
Table 121. ACIS1/ACIS0 Settings
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is the sample program I promised, sorry it took so long but life got in the way.  It's tested and works.

Code:
/*
  Analog comparator example using interrupt and testing ACO flag
 
 Compares voltage sensed at pins 6 (AIN0) and 7 (AIN1) which are the analog inputs into the comparator.  AIN0 is
 the positve input and AIN1 is the negative input to the comparator. Once the voltage on AIN0(+) rises above the voltage
 sensed at AIN1(-), the comparator output becomes high and triggers the interrupt to run.  The interrupt routine toggles
 the LED connected to Pin 13.  The ACO flag is tested in the loop() and Pin 9 is set to match.  
 
 The circuit:
 * Simple voltage divider made from two 10k resistors with the midpoint connected to AIN1(Pin 7 -)
 The end points of the resistors connect to +5V and ground
 
 * Varying input voltage that is normally below the set point of the divider.  I used a CDS photocell above a 10k resistor
 configured as a voltage divider.  The photocell connects to +5 and the 10k resistor, the other resistor leg connects to
 ground.
 
 * On board LED connected to Pin 13
 
 * Another LED connected to Pin 9 that reflects the status of the comparator output.
 
 
 created 27 Feb 2013
 by Anthony Fremont
 
 */

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);

  ACSR =
    (0 << ACD) |    // Analog Comparator: Enabled
    (0 << ACBG) |   // Analog Comparator Bandgap Select: AIN0 is applied to the positive input
    (0 << ACO) |    // Analog Comparator Output: Off
    (1 << ACI) |    // Analog Comparator Interrupt Flag: Clear Pending Interrupt
    (1 << ACIE) |   // Analog Comparator Interrupt: Enabled
    (0 << ACIC) |   // Analog Comparator Input Capture: Disabled
    (1 << ACIS1) | (1 << ACIS0);   // Analog Comparator Interrupt Mode: Comparator Interrupt on Rising Output Edge

  pinMode(13, OUTPUT);  // toggles when ISR runs

  pinMode(9, OUTPUT);   // indicates status of comparator output
}

void loop() {

  if(ACSR & (1 << ACO))         //  check status of comparator output flag
    digitalWrite(9, HIGH);    //   and mirror it to Pin 9
  else
    digitalWrite(9, LOW);

  delay(100);                    
}

ISR(ANALOG_COMP_vect ) {
  digitalWrite(13, !digitalRead(13));   // toggle state of Pin 13
}

« Last Edit: February 27, 2013, 03:37:01 pm by afremont » Logged

Experience, it's what you get when you were expecting something else.

Pages: [1] 2   Go Up
Jump to: