Pages: [1]   Go Down
Author Topic: more external interrupts?  (Read 7768 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a design in mind that would be possible with 4 interrupts. I see that the m168 has, in addition to the INT0 and INT1 that attachInterrupt() uses, there are the PCINT registers (pin change interrupt.) Wouldn't it be great to have access to these within our IDE? (feature request  smiley-wink) But until then- has anyone had some success using these PCINTs within the context of arduino? Some examples would be really useful to me!

Thanks,

Collin

« Last Edit: October 24, 2007, 06:35:31 am by coldham » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 27
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just implemented some PCINT's on the analog pins 5 and 6 on the arduino.  I don't have access to the code right now but I think I did something like this to set them up:

PCICR = (1 << PCIE1);
PCMSK= (1<<PCINT5) | (1<<PCINT6);

and then declared the interrupt routine as:

ISR( PCINT1_vect)


Note, this interrupt routine will be called for both of the above intterupts.  You will need to then read the appropiate PIN (in my case PINJ) to figure out which pin caused the interrupt.

Check out sections 12 and 13 of http://www.atmel.com/dyn/resources/prod_documents/doc2545.pdf to figure out what you will need to set PCICR and PCMSK to, and which PCINTx_vect you will need to use in your interrupt routine.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks, that's the kind of thing I was looking for to get me going. And so quick too! I'd be glad if you could post a chunk of code, so I could learn from the context, if you get a chance.

cheers,
Collin
Logged

Brisbane, Australia
Offline Offline
God Member
*****
Karma: 1
Posts: 593
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Alternatively you could fire one interrupt and also use a digital in for each 'extra' one you want.
When the interrupt fires you check to see which one it was.
Logged

0
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2526
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't want to hijack the excellent discussion on using the ATmega's IO pins, but another option is an IO expander IC from Microchip MCP23017/MCP23S17 (I2C and SPI, respectively) that gives you 16 bidirectional IO pins, and can be configured to trigger an interrupt on some/all of these inputs.

-j
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 27
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I like the idea of an i/o expander and think it's the best option.  I have problems with the PCINT option in that my software works best with the RISING option.   CHANGE can be tricky to code depending on how the sensor is working and the idea of having to read in the state of the pins after the interrupt has inherent problems.  What happens if the state of the pin changes between the interrupt happening and the READ?

However, for a bunch of reasons, I'm using the external interrupts and I can see that it is a useful thing to know how to do.   So here is a quick example of what I am doing.  I have a DC motor that's moving between two sensors - one on the left and one on the right.  I want the motor to switch direction whenever it hits a sensor.   The sensors are on Analog pins 5 and 6 of the arduino:

#include <avr/interrupt.h>  
#include <avr/io.h>

#define LEFT false
#define RIGHT true

int mPin1 = 5; // H-bridge leg 1
int mPin2 = 6; // H-bridge leg 2
int mEnable = 7;

boolean volatile mDirection = RIGHT;
int volatile mSpeed = 200;

ISR( PCINT1_vect )
{
  if( ( ( PINC & _BV( PC4 ) ) && mDirection == LEFT ) ||
      ( ( PINC & _BV( PC5 ) ) && mDirection == RIGHT ) )
      switch_direction();
}

void setup() {
  pinMode( mPin1, OUTPUT );
  pinMode( mPin2, OUTPUT );
  pinMode( mEnable, OUTPUT );
  
  //make analog pins 5 and 6 into pin change interrupts  
  PCICR |= (1 << PCIE1);
  PCMSK1 |= (1 << PCINT12);
  PCMSK1 |= (1 << PCINT13);  
  
  digitalWrite( mEnable, HIGH );
  set_motor();
 }

void loop() {  
}

void set_motor()
{
  boolean speedPin = ( mDirection ) ? mPin1 : mPin2;
  boolean unusedPin = ( mDirection ) ? mPin2 : mPin1;

  analogWrite( unusedPin, 0 );
  analogWrite( speedPin, mSpeed );  
}

void switch_direction()
{
  mDirection = !mDirection;  
  set_motor();
}


Hope it helps, and good luck!



  
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks all,

I've been thinking about cheater's option, and below is my attempt to read four pins after an interrupt to see which one was the trigger. I can't test this until Monday, so I'll be entertained by your predictions, and I welcome pointers of any kind. (insert pointer joke here) I'll look into a IO expander when it turns out this doesn't work!

A bit more about my project: I'm trying to do a 4 channel version of an earlier project called "clapboard" which depended on 2 interrupts to find the time difference between the arrival of a sound impulse at 2 contact mics attached to a table. That gives me one dimension of position data I can use to control a sound process in Pd. It works (sort of) and you can find out all about it on this webpage: http://homepage.mac.com/coldham/klang/clapboard.html   Anyway, it would be cool to get it working in 2d, so I can use the whole table! Thanks for sharing!

Collin


Code:
#include <SimpleMessageSystem.h>

/* clapboard
 * ---------------
 *
 * This version tries to read 4 piezos sharing one interrupt
 * each circuit terminates at digital pin 2 (INTO) and one each at
 * digital pins 8, 9, 10, &11 (PB0-3)
 *
 * (copyleft) 2007 by Collin Oldham
 * <http://ccrma.stanford.edu/~coldham>
 * coldham (at) mac.com
 *
 */
 
 
#define MAXCOUNT 4500

int clock[0xF]; //that's 15
char i=0;
char pins=0;



void setup(void) {
  pinMode(8,INPUT);
  pinMode(9,INPUT);
  pinMode(10,INPUT);
  pinMode(11,INPUT);
  Serial.begin(115200);
  attachInterrupt(0, hit, RISING);
  TCCR1A=0x0;    // reset timer 1 (the sixteen bit counter) to it's default mode
  TCCR1B=0x2;    //set the timer to increment once every 256 clock cycles


}

void loop(void) {
  if (TCNT1>MAXCOUNT){      //reset everything when the clock gets higher than it should need to.
    pins=0;    
    for(i=0;i<0xF;i++){
      clock[i] = 0;
    }
  }

  if (pins==0xF) {          //all four pins are hit, so send the time tags.
    cli();                  //disable interrupts
    for(i=0;i<0xF;i++){
      if(clock[i] != 0){
        messageSendChar(i);
        messageSendInt(clock[i]);
        messageEnd();
        clock[i] = 0;
      }
    }
    delay(70);
    pins=0;
    sei();                  //enable interrupts
  }
}



void hit()
{

  pins |= PINB & 0x0f; // I just want to read the fist 4 pins of port b, and I "|=" them into "pins" so I don't overwrite previous hits with a zero. PINB reprsents the values read on port b.
  if(pins==1||2||4||8){   // If only one bit is high, this is the first hit, so reset the clock.
    TCNT1=0;
  }
  clock[pins]=TCNT1;


}
Logged

New Zealand
Offline Offline
God Member
*****
Karma: 0
Posts: 999
Arduino pebbles
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'll look into a IO expander when it turns out this doesn't work!

Hi,

You might want to check out this forum post to links to my code and demo for using the 8-bit version of the Microchip I/O expander over SPI: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1192447714/0

I haven't tried the interrupt stuff yet, but what I've done might get you started.

--Phil.
Logged

Pages: [1]   Go Up
Jump to: