Tengo este pequeño proyecto mío que implica poner un ATTiny85 en suspensión para ahorrar energía. La idea principal es:
1- Poner ATTiny85 en reposo, incluida la desactivación del ADC 2- Despertador MC en cambio de pin 3- Activando ADC 4- Lectura de la tensión desde el mismo pin que detectó el cambio
El problema es que no puedo obtener una lectura decente del ADC después de activar el MC. Parece estar en ALTO todo el tiempo.
Aquí está el código:
#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);
}
De las especificaciones ATTiny85 parece que después de reactivar el ADC hay una conversión extendida, así que intenté agregar un retraso después de despertarme (que no funcionó) y más adelante He intentado implementar algunas otras ideas como guardar el valor de ADCSRA antes de dormir y recuperarlo después de despertarme, pero desafortunadamente, eso tampoco ha funcionado.
#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);
}
¿Alguna idea?
Gracias de antemano.
Aparentemente, si uso el pin 3 (PB3) en lugar de 2 (PB2) como pin de interrupción, obtengo lecturas decentes después de reactivar el ADC. ¡Todavía tengo que descubrir por qué!