I have this little project of mine that involves putting a ATTiny85 to sleep to save power. The main idea is to:
1- Putting ATTiny85 to sleep, including deactivation of the ADC
2- Wake-up MC on pin change
3- Activating ADC
4- Reading the voltage from the same pin that detected the change
The problem is that I'm unable to get a decent reading on the ADC after waking up the MC. It seems be to HIGH all the time.
Here is the code:
#include <avr/sleep.h>
#include <avr/interrupt.h>
// These constants won't change. They're used to give names
// to the pins used:
const int analogInPin = 2;
const int LED = 3;
volatile int outputValue = 0;
void setup() {
pinMode(LED, OUTPUT);
pinMode(analogInPin, INPUT);
digitalWrite(LED, LOW);
digitalWrite(analogInPin, HIGH);
}
void MCSleep() {
GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT2); // Use PB2 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT2); // Turn off PB2 as interrupt pin
sleep_disable(); // Clear SE bit
ADCSRA |= _BV(ADEN); // ADC on
sei(); // Enable interrupts
} // sleep
// Whatever the pin this IRS should always point to the PCINT0_vect, because is the only capable of
// providing the interrupt. The ISR must be provided otherwise, the MC just resets instead of resuming.
ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
delay(100);
}
void loop() {
MCSleep();
delay(100);
outputValue = analogRead(analogInPin);
if (outputValue > 100){
digitalWrite(LED, HIGH); // Door is open.
}
else{
digitalWrite(LED, LOW); // Door is closed.
}
delay(200);
}
From the ATTiny85 specs it seems that after reactivating the ADC there is some extended conversion, so I tried to add a delay after waking up (which didn't work) and later on
I've tried to implement some other ideas like saving the ADCSRA value before sleeping and recover it after waking up, but unfortunately, that hasn't work either.
#include <avr/sleep.h>
#include <avr/interrupt.h>
// These constants won't change. They're used to give names
// to the pins used:
const int analogInPin = 2;
const int LED = 3;
byte keep_ADCSRA;
volatile int outputValue = 0;
void setup() {
pinMode(LED, OUTPUT);
pinMode(analogInPin, INPUT);
digitalWrite(LED, LOW);
digitalWrite(analogInPin, HIGH);
}
void MCSleep() {
GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT2); // Use PB2 as interrupt pin
keep_ADCSRA = ADCSRA;
ADCSRA = 0;
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT2); // Turn off PB2 as interrupt pin
sleep_disable(); // Clear SE bit
ADCSRA = keep_ADCSRA;
sei(); // Enable interrupts
} // sleep
// Whatever the pin this IRS should always point to the PCINT0_vect, because is the only capable of
// providing the interrupt. The ISR must be provided otherwise, the MC just resets instead of resuming.
ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
delay(100);
}
void loop() {
MCSleep();
delay(100);
outputValue = analogRead(analogInPin);
if (outputValue > 100){
digitalWrite(LED, HIGH); // Door is open.
}
else{
digitalWrite(LED, LOW); // Door is closed.
}
delay(200);
}
Any ideas?
Thanks in advance.