Unfortunately my knowledge and experience with this topic is minimal - I hope to ask my question unerstandable:
I use an Arduino Pro Micro with a keypad with the pins 14, 2, 3, 5 (vertical lines) and 10, 7, 8, 9 (horizontal lines).
I want to wake up the Arduino from sleep mode (SLEEP_MODE_PWR_DOWN) with one of this keys via interrupt.
As far I understand the ProMicro has INTERRUPT1 on PIN2. So if PIN2 gets a LOW the Arduino wakes up.
That's why I set PIN10 as OUTPUT and LOW. If I press on the keypad the key, that connects PIN2 with PIN10 the interrupt should see LOW and should wake up.
The other Arduinos have interrupt 0 on pin 2. Are you sure that the Pro Micro is different?
Yes, the Micro has interrupt 1 on pin 2.
By the way, the pins used in the KeyPad library are all output pins, except when getKey() is called, so none of them will wake the Arduino.
How do you know without having seen the actual code? If they are all outputs the risk of a short circuit is quite high. Usually the libraries set them as inputs while they are not used.
Yes - the arduino wakes up, if I connect PIN2 to GND directly.
And no - I do not use the keypad library, but some similar code:
The rows are set to INPUT_PULLUP.
In a loop set the col to OUTPUT and LOW., assign key if row reads low and (re)set col to HIGH.
I was hoping that setting PIN10 to LOW will enable to wake up by pressing key "A" (PIN2, Interrupt 1).
The question is if the output state of the digital IOs will be kept while in power down sleep. I cannot find any hint on that in the datasheet. Try to write a HIGH to some pin and measure that signal while asleep. What do you measure with a multimeter?
After some measurements I saw that a pin (ie PIN10) which is set (as OUTPUT) to LOW or HIGH remains LOW or HIGH when the arduino falls asleep.
But if PIN10 is set to LOW a connection with the interrupt pin (PIN2) doesn't wake up the arduino (while a connection between PIN2 and GND wakes up the arduino immediately).
It seems that GND activates an interrupt but LOW doesn't ... really strange.
Nick Gammon wrote this sketch to wake an Arduino from sleep on key press:
// Wake from deep sleep with a keypress demonstration
// Author: Nick Gammon
// Date: 18th November 2012
#include <Keypad.h>
#include <avr/sleep.h>
const byte ROWS = 4;
const byte COLS = 4;
char keys[] = {
"123A"
"456B"
"789C"
"*0#D"
};
byte rowPins[ROWS] = {6, 7, 8, 9}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {2, 3, 4, 5}; //connect to the column pinouts of the keypad
// number of items in an array
#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg [0])))
const byte ledPin = 13;
// Create the Keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
/*
Pin change interrupts.
Pin Mask / Flag / Enable
D0 PCINT16 (PCMSK2 / PCIF2 / PCIE2)
D1 PCINT17 (PCMSK2 / PCIF2 / PCIE2)
D2 PCINT18 (PCMSK2 / PCIF2 / PCIE2)
D3 PCINT19 (PCMSK2 / PCIF2 / PCIE2)
D4 PCINT20 (PCMSK2 / PCIF2 / PCIE2)
D5 PCINT21 (PCMSK2 / PCIF2 / PCIE2)
D6 PCINT22 (PCMSK2 / PCIF2 / PCIE2)
D7 PCINT23 (PCMSK2 / PCIF2 / PCIE2)
D8 PCINT0 (PCMSK0 / PCIF0 / PCIE0)
D9 PCINT1 (PCMSK0 / PCIF0 / PCIE0)
D10 PCINT2 (PCMSK0 / PCIF0 / PCIE0)
D11 PCINT3 (PCMSK0 / PCIF0 / PCIE0)
D12 PCINT4 (PCMSK0 / PCIF0 / PCIE0)
D13 PCINT5 (PCMSK0 / PCIF0 / PCIE0)
A0 PCINT8 (PCMSK1 / PCIF1 / PCIE1)
A1 PCINT9 (PCMSK1 / PCIF1 / PCIE1)
A2 PCINT10 (PCMSK1 / PCIF1 / PCIE1)
A3 PCINT11 (PCMSK1 / PCIF1 / PCIE1)
A4 PCINT12 (PCMSK1 / PCIF1 / PCIE1)
A5 PCINT13 (PCMSK1 / PCIF1 / PCIE1)
*/
// we don't want to do anything except wake
EMPTY_INTERRUPT (PCINT0_vect)
EMPTY_INTERRUPT (PCINT1_vect)
EMPTY_INTERRUPT (PCINT2_vect)
void setup ()
{
pinMode (ledPin, OUTPUT);
// pin change interrupt masks (see above list)
PCMSK2 |= _BV (PCINT22); // pin 6
PCMSK2 |= _BV (PCINT23); // pin 7
PCMSK0 |= _BV (PCINT0); // pin 8
PCMSK0 |= _BV (PCINT1); // pin 9
} // end of setup
// set pins as keypad library expects them
// or call: kpd.initializePins ();
// however in the library I have that is a private method
void reconfigurePins ()
{
byte i;
// go back to all pins as per the keypad library
for (i = 0; i < NUMITEMS (colPins); i++)
{
pinMode (colPins [i], OUTPUT);
digitalWrite (colPins [i], HIGH);
} // end of for each column
for (i = 0; i < NUMITEMS (rowPins); i++)
{
pinMode (rowPins [i], INPUT);
digitalWrite (rowPins [i], HIGH);
} // end of for each row
} // end of reconfigurePins
void goToSleep ()
{
byte i;
// set up to detect a keypress
for (i = 0; i < NUMITEMS (colPins); i++)
{
pinMode (colPins [i], OUTPUT);
digitalWrite (colPins [i], LOW); // columns low
} // end of for each column
for (i = 0; i < NUMITEMS (rowPins); i++)
{
pinMode (rowPins [i], INPUT);
digitalWrite (rowPins [i], HIGH); // rows high (pull-up)
} // end of for each row
// now check no pins pressed (otherwise we wake on a key release)
for (i = 0; i < NUMITEMS (rowPins); i++)
{
if (digitalRead (rowPins [i]) == LOW)
{
reconfigurePins ();
return;
} // end of a pin pressed
} // end of for each row
// overcome any debounce delays built into the keypad library
delay (50);
// at this point, pressing a key should connect the high in the row to the
// to the low in the column and trigger a pin change
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
byte old_ADCSRA = ADCSRA;
// disable ADC to save power
ADCSRA = 0;
PRR = 0xFF; // turn off various modules
PCIFR |= _BV (PCIF0) | _BV (PCIF1) | _BV (PCIF2); // clear any outstanding interrupts
PCICR |= _BV (PCIE0) | _BV (PCIE1) | _BV (PCIE2); // enable pin change interrupts
// turn off brown-out enable in software
MCUCR = _BV (BODS) | _BV (BODSE);
MCUCR = _BV (BODS);
sleep_cpu ();
// cancel sleep as a precaution
sleep_disable();
PCICR = 0; // cancel pin change interrupts
PRR = 0; // enable modules again
ADCSRA = old_ADCSRA; // re-enable ADC conversion
// put keypad pins back how they are expected to be
reconfigurePins ();
} // end of goToSleep
void loop ()
{
byte key = kpd.getKey();
if (!key)
{
// no key pressed? go to sleep
goToSleep ();
return;
}
// confirmation we woke - flash LED number of times
// for the appropriate pin (eg. pin 1: one time)
for (byte i = 0; i < (key - '0'); i++)
{
digitalWrite (ledPin, HIGH);
delay (500);
digitalWrite (ledPin, LOW);
delay (500);
} // end of for loop
} // end of loop
It's almost seven years old and probably written for an UNO so you may have to make some adjustments.
The question is if the output state of the digital IOs will be kept while in power down sleep
In the ATmega328 the output pins maintain their state during power down sleep mode, and I doubt it is different in the ATmega32u4.
This statement from the ATmega32u4 data sheet strongly suggests that is the case:
When entering a sleep mode, all port pins should be configured to use minimum power. The
most important is then to ensure that no pins drive resistive loads.
Enable pin change interrupt (only PCIE0 was available)
Sleep CPU
Unfortunately the hardware is different. On the UNO (ATmega328p) all digital IOs are available for pin change interrupts. On the Micro (ATmega32U4) only a few pins have the option to work as a pin change interrupt. But the ATmega32U4 wakes up on INT0 and INT1 (pin 2 and 3) by a not only a level (LOW) interrupt but also change interrupts. Try setting the interrupt to CHANGE or FALLING and check if that awakes your Micro.
with every possibility of HIGH, LOW, FALLING, RISING, CHANGE of:
attachInterrupt(1, wakeupnow, LOW);
... but without success.
My last solution will be to (hardware-)separate one key from the keypad and connect it to an own interruptable pin.
An additional advantage could be to implement a "real" shift key to access some fast menu (of my scientific calculator).