Go Down

Topic: ATtiny85 Pin Change Interrupt Problem (Read 19 times) previous topic - next topic

Senso

Just read the datasheet....
Pin change interrupts are sort of global to each port, after having a PCINT you must write some code to determine wich pin as changed and then react accordind, its all in the datasheet...
That and google avr pin change interrupt..

bHogan

Senso,

I assumed
PCMSK |= (1<<PCINT3);    //  tell pin change mask to listen to D3

Would only cause the INT to fire with D3, but I'll look at the data sheet and google some more.

My understanding of what your saying is that I need some code in the ISR - correct?
In any case, thanks for the hint.
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

Graynomad

Quote
My understanding of what your saying is that I need some code in the ISR - correct?

Only if there are two or more possible interrupt sources. If you only have one then by definition the interrupt comes form that pin and there's no need to figure anything out.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Coding Badly

#8
Feb 11, 2011, 08:55 am Last Edit: Feb 11, 2011, 08:57 am by Coding Badly Reason: 1
If you only have one then by definition the interrupt comes form that pin and there's no need to figure anything


Bah!  Where's the fun in that!

@BroHogan...

Quote
The ability to detect rising and falling would be great too!


Call attachPcInterrupt in exactly the same fashion as attachInterrupt (LEVEL interrupts are not supported)...

Code: [Select]
void Rising( void )
{
 digitalWrite( 2, ! digitalRead( 2 ) );
}

void setup( void )
{
 attachPcInterrupt( 1, Rising, RISING );
}


The code is available here...
http://code.google.com/p/arduino-tiny/downloads/detail?name=PinChangeInterrupt-0001.zip

The readme.txt file is very sparse.  I simply don't have time to write up install / usage instructions.  If you get stuck, ask here for help.

Quote
The serial sounds interesting


Some instruction here (I'll try to get 16 MHz support published this weekend)...
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1285218245/25#25

Good luck and please let me know how you make out!


bHogan

Quote
Good luck and please let me know how you make out!


I had good luck and this is how I made out . . .
The PinChangeInterrupt lib worked great! It even perfectly handled the FALLING mode.
I'm reading the IR remote every time and it had no effect on ISR0 so my I2C is working fine for the LCD display.
Major thanks CB. Thats a fine little lib.  :D

Here's the code FWIW. (The IR_ISR() may be worth taking a look at.)

Code: [Select]
/* ATtiny85 IR Receiver Test               BroHogan                        2/11/11
* Tests IR receiver (using pin change interrupt) while I2C LC display is used.
* SETUP:
* ATtiny Pin 1 = (RESET) N/U                      ATtiny Pin 2 = (PB3) IR OUTPUT PIN
* ATtiny Pin 3 = (PB4) to LED1                    ATtiny Pin 4 = GND
* ATtiny Pin 5 = PB0/SDA on GPIO                  ATtiny Pin 6 = (PB1) N/U
* ATtiny Pin 7 = PB2/INT0/SCK on GPIO             ATtiny Pin 8 = VCC (2.7-5.5V)
*/

#include <PinChangeInterrupt.h>         // mimics attachInterrupt() but a PCI for ATtiny
#include "TinyWireM.h"                  // uses TinyWireM lib low level functions
#include <LiquidCrystal_I2C.h>          // for LCD w/ GPIO MODIFIED for the ATtiny85

#define LED1_PIN         4              // ATtiny Pin 3
#define IR_PIN 3                        // IR sensor - ATtiny Pin 2
#define GPIO_ADDR        0x3F           // (PCA8574A A0-A2 @5V) typ. A0-A3 Gnd 0x20 / 0x38 for A

// IR receiver defines
#define ENTER 12
#define UP    17
#define DOWN  18
#define RIGHT 19
#define LEFT  20
#define OK    21
#define POWER 22
#define SLEEP 55
#define INFO  59

// vars for IR_ISR() (must be global)
volatile boolean IR_Avail;              // flag set if IR has been  read
volatile unsigned int IR_Return;        // returns IR code received
volatile unsigned long ir_mask;         // Loads variable ir_string
volatile unsigned int ir_bit_seq;       // Records bit sequence in ir string
volatile unsigned int ir_string;        // Stores ir string

LiquidCrystal_I2C lcd(GPIO_ADDR,16,2);  // set address & 16 chars / 2 lines

void setup(){
  pinMode(LED1_PIN,OUTPUT);             // for general DEBUG use
  pinMode(IR_PIN,INPUT);                // IR on pin 3
  digitalWrite(IR_PIN, HIGH);           // turn on pullup resistor
  lcd.init();                           // initialize the lcd & TinyWireM
  lcd.backlight();                      // Print a message to the LCD.
  lcd.print("Hello, IR!");
  attachPcInterrupt(3,IR_ISR,FALLING);  // Catch IR sensor on PB3 with pin change interrupt
}

void loop(){
  Check_IR();
}

void Check_IR(){ // check if remote used and process     
  int remoteInput;                      // normalized input from remote

  if(IR_Avail){                         // check if key on IR has been pressed
    remoteInput = IR_Return + 1;        // convert raw return to actual digit values
    if (remoteInput == 10) remoteInput = 0; // special case for zero key
    lcd.clear();
    switch (remoteInput) {              // a case for each key

    case 0 ... 9:                       // digits 0-9
      lcd.print("Digit-");
      lcd.print(remoteInput,DEC);
      break;
    case ENTER:
      lcd.print("Enter");
      break;
    case UP:
      lcd.print("Up");
      break;
    case DOWN:
      lcd.print("Down");
      break;
    case RIGHT:
      lcd.print("Right");
      break;
    case LEFT:
      lcd.print("Left");
      break;
    case OK:
      lcd.print("OK");
      break;
    case POWER:
      lcd.print("Power");
      break;
    case SLEEP:
      lcd.print("Sleep");
      break;
    case INFO:
      lcd.print("Info");
      break;
    default:
      lcd.print("????-");
      lcd.print(remoteInput,DEC);
    }
    IR_Avail = false;                   // allow IR again
    digitalWrite(LED1_PIN, LOW);        // turn off LED
  }
}


void IR_ISR(){ // This ISR is called for EACH pulse of the IR sensor
  if(ir_bit_seq == 0){                  // it is the long start pulse
    for(int i = 0; i<20; i++){          // see if it lasts at least 2 ms
      delayMicroseconds(100); // 100
      if(digitalRead(IR_PIN)) return;   // it's doesn't so get out (low active)
    } 
    ir_bit_seq = 1;                     // mark that the start pulse was received
    ir_mask = 1;                        // set up a mask for the next bits
    return;
  }
  delayMicroseconds(900);               // wait 900 us and test
  if(!digitalRead(IR_PIN)) ir_string = ir_string | ir_mask;  // Stores 1 in bit
  ir_mask = ir_mask << 1;               // shifts ir_mask by one to the left
  ir_bit_seq++;                         // ir_bit_seq is incrimented by one
  if(ir_bit_seq == 12){                 // after remote sends 12 bits it's done
    ir_mask = 63;                       // only want the last 6 bits - the command
    ir_string = ir_string & ir_mask;    // only keep last 6 bits
    IR_Return = ir_string;              // final result
    IR_Avail = true;                    // indicate new command received
    digitalWrite(LED1_PIN, HIGH);       // turn on LED to show you got something
    ir_bit_seq = 0;                     // clean up
    ir_string = 0;
    ir_mask = 0;
    for(int i = 0; i<25; i++){          // delay to stop repeat 10ms / loop ~250ms about right
      delayMicroseconds(10000);         // 16383 is maximum value so need to repeat
    }
  }
}



"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

Go Up