I'm a bit stuck on this. I am using an accelerometer. When I send it to sleep, its interrupt pin goes HIGH. When it wakes up, because it detects motion, it goes LOW.
The sequence I want is this:
Put accelerometer to sleep
Put ATTINY85 to sleep
Wait for the accelerometer to wake up and send the interrupt pin LOW
Use this interrupt to wake up the ATTINY
Do stuff
repeat
I need to use the pin change interrupt, but I only want the interrupt to do anything if the accelerometer interrupt pin goes LOW (i.e. it's waking up) rather than HIGH (i.e. it's going to sleep).
The bare bones of the code I'm using is this:
//set up the interrupts
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
const int intpin = 4;
int asleep;
void setup(){
pinMode (intpin, INPUT_PULLUP);
sbi(GIMSK,PCIE); // Turn on Pin Change interrupt
sbi(PCMSK,PCINT4); // Which pins are affected by the interrupt
}
void loop(){
accelsleep(); // put the accelerometer to sleep. Function is defined elsewhere, it seems to work
system_sleep(); //wait for the interrupt
if (asleep==0) //i.e if the accelerometer is not asleep, i.e. it's awake
delay(5000); //actually I would have stuff happening here
}
void accelsleep(){
//Set the threshhold and time
SPIwriteTwoRegisters(0x20, 300);//300 is the threshhold
SPIwriteOneRegister(0x22, 10); //10 is the time
//Set the ACT_INACT_CTL bit 1
SPIwriteOneRegister(0x27, 0x03);
// Map awake status to interrupt 1
SPIwriteOneRegister(0x2A, 0x90);
SPIwriteOneRegister(0x2D, 0x02);
}
void SPIwriteOneRegister(byte regAddress, byte regValue){
digitalWrite(slaveSelectPin, LOW);
SPI.transfer(0x0A); // write instruction
SPI.transfer(regAddress);
SPI.transfer(regValue);
digitalWrite(slaveSelectPin, HIGH);
}
int SPIreadTwoRegisters(byte regAddress){
int twoRegValue = 0;
digitalWrite(slaveSelectPin, LOW);
SPI.transfer(0x0B); // read instruction
SPI.transfer(regAddress);
twoRegValue = SPI.transfer(0x00);
twoRegValue = twoRegValue + (SPI.transfer(0x00) << 8);
digitalWrite(slaveSelectPin, HIGH);
return twoRegValue;
}
void SPIwriteTwoRegisters(byte regAddress, int twoRegValue){
byte twoRegValueH = twoRegValue >> 8;
byte twoRegValueL = twoRegValue;
digitalWrite(slaveSelectPin, LOW);
SPI.transfer(0x0A); // write instruction
SPI.transfer(regAddress);
SPI.transfer(twoRegValueL);
SPI.transfer(twoRegValueH);
digitalWrite(slaveSelectPin, HIGH);
}
void system_sleep() {
cbi(ADCSRA,ADEN); // Switch Analog to Digital converter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode
sleep_mode(); // System sleeps here
sbi(ADCSRA,ADEN); // Switch Analog to Digital converter ON
}
ISR(PCINT0_vect) {
asleep=digitalRead(intpin); //if the interrupt has gone low, then the asleep should be LOW
SPIreadOneRegister(0x0B); //this is to clear the interrupt register on the accelerometer
}
What actually happens is that the accelerometer goes to sleep - what I want - and its interrupt pin goes high.
Then motion causes it to wake up - again what I want - and the interrupt pin goes low (actually to 0.05V, which I guess is low enough)
But the accelerometer never goes back to sleep again.
Is the problem maybe that I am using digitalRead against your advice? How do I read the port directly?
I am sure the library mentioned would be useful but I'm afraid I don't understand how to use it.