Hi,
I'd like to ask for some help correctly putting an Atmega328p to sleep. My goals are to have it use the LEAST amount of energy while being able to listen to 3 interrupt inputs to wake up. I've gotten the below coding to work... just looking to see if it needs improvement.
Setup:
-Atmega328P custom barebones PCB design fed by 12v through 5v reg,
2 questions:
-Can I reduce the amount of energy any further than this coding will do? (PCB drawing about 5.5ma)
-How do I write the code to clear the Interrupt Flags for the entire port when using PCINT?
The following code exert is for an automotive project that puts it to Sleep when the Ignition is turned off. Waking occurs from one of 3 Interrupts:
- INT0 from switch 1 going LOW
- INT1 from switch 2 going LOW
- PCINT from Ignition voltage going HIGH
(PCINT is Pin 16 with Atmega328p)
How do I write the code to clear the PCINT flag? I followed Guru Nick for the INT0 and INT1 flags, but don't understand how to do the PCINTs.
THANKS!
#define PCINT_PIN 16 // For PCINT setting
static const int IGN = A2; // Analog input Ignition voltage
int IGNThreshold = 350; // Level below which enters Sleep Mode
~~~~~~~~~
void wakeISR() { // Wakes from any Interrupt
sleep_disable();
detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(PCINT_PIN));
detachInterrupt (0);
detachInterrupt (1);
}
void loop() {
// Check Ignition power status
if (analogRead(IGN) <= IGNThreshold) { // Check if Ignition voltage is off
IGNOFF = 1; // Set Ignition Status to OFF
LEDSOFF(); // Turns off ALL LEDs
static byte prevADCSRA = ADCSRA; // Copy ADC registers
ADCSRA = 0; // disable ADC
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
MCUCR = bit (BODS) | bit (BODSE); // turn off brown-out enable in software. BODS must be set to one and BODSE must be set to zero within four clock cycles
MCUCR = bit (BODS); // The BODS bit is automatically cleared after three clock cycles
// Guarantees that the sleep_cpu call will be done as the processor executes the next instruction after interrupts are turned on.
noInterrupts (); // Do not interrupt before we go to sleep, or the ISR will detach interrupts and can't wake.
//INSERT CODE HERE CLEARING PCINT_PIN INTERRUPT
EIFR = (1 << INTF0); // use before attachInterrupt(0,isr,xxxx) to clear interrupt 0 flag
EIFR = (1 << INTF1); // use before attachInterrupt(1,isr,xxxx) to clear interrupt 1 flag
attachInterrupt (digitalPinToInterrupt(2), wakeISR, LOW); // Calls ISR when INT0 goes low
attachInterrupt (digitalPinToInterrupt(3), wakeISR, LOW); // Calls ISR when INT1 goes low
attachPCINT(digitalPinToPCINT(PCINT_PIN), wakeISR, HIGH); // Calls ISR when Ignition power is on (line is tied to GND via 10k)
interrupts (); // Interrupts Activated
sleep_cpu (); // CPU is ASLEEP and waiting for Interrupts
//CPU IS NOW AWAKE
ADCSRA = prevADCSRA;