The interrupt usage with keypad

Hi All,

I try to use keypad with interrupt on ARDUINO UNO, but i met some issue.
The code target is :

  1. After 10 sec., it will enter sleep mode (power_down) if no button been pressed.
  2. in power down, if any key in ROW[3] (1,2,3) been pressed, it will execute pin2Interrupt ISR and wake up.

I use the pin2 (INT0) in ROW[3].

My question is that it can go into "POWER DOWN", but when i pressed the key (1,2,3), it can't not wake up.
Can give me some suggestion?

Thanks

#include <limits.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <Keypad.h>
const byte interruptPin = 2;
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
    {'1','2','3'},
    {'4','5','6'},
    {'7','8','9'},
    {'*','0','#'}
};

byte rowPins[ROWS] = {2, 3, 4, 5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {A2, A3, A4}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
const byte ledPin = 13; 

volatile unsigned long previous_time;
volatile unsigned long current_time;
volatile unsigned long time_passed;
volatile byte low_power_st;

void pin2Interrupt(void)
{
  Serial.println("Enter ISR");
  digitalWrite(ledPin, HIGH);
  previous_time = millis();
  low_power_st = 0;
  detachInterrupt(digitalPinToInterrupt(interruptPin));
}

void enterSleep(void)
{
  
  /* Setup pin2 as an interrupt and attach handler. */
  digitalWrite(ledPin, LOW);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  attachInterrupt(digitalPinToInterrupt(interruptPin), pin2Interrupt, RISING); //這行是重要的, enable interrupt 要在sleep之前, 不然容易一睡不醒

  sleep_enable();
  
  sleep_mode();
  
  /* The program will continue from here. */
  Serial.println("Disable Sleep");
  /* First thing to do is disable sleep. */
  sleep_disable(); 
}

void setup(){
    Serial.begin(9600);
    low_power_st = 0;
    previous_time = millis();
    pinMode(2, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);              // Sets the digital pin as output.
    digitalWrite(ledPin, HIGH);           // Turn the LED on.
    keypad.addEventListener(keypadEvent); // Add an event listener for this keypad
}

void loop(){
  char key = keypad.getKey();
  current_time = millis();

  if (low_power_st == 0) {
    if (current_time >= previous_time) {
      time_passed = current_time - previous_time;
      if (time_passed > 5000) {
        low_power_st = 1;
        enterSleep();
      }
    }
    else {
      time_passed = ULONG_MAX - previous_time + current_time;
      if (time_passed > 5000) {
        low_power_st = 1;
        enterSleep();
      }
    }
  }
  
}

// Taking care of some special events.
void keypadEvent(KeypadEvent key){
    low_power_st = 0;
    previous_time = millis();
    switch (keypad.getState()){
    case PRESSED:
          Serial.println(key);
        break;
    }
}

Can give me some suggestion?

Do you understand how the Keypad library works? No pins are read until you call getKey(), at which point the code runs through the row and column pins making them input or output, high or low, as needed, to determine which, if any, key is pressed.

I really do not think you can expect the keypad to generate an external interrupt.

When you go into sleep mode, you need to hold one wire on the keypad high, to give power to the key you want to use as the wakeup key.

When recovering from sleep mode, you need to relinquish control of this pin back to the keypad library. This should not be difficult.

Hi Paul,

Thanks for your suggestion and reply. I look the source codes of keypad library.
Yes. The button was been pressed and been detected when calling getKey().
It gives me some idea like as Morgan's suggestion.

Hi Morgan,

Thanks for your suggestion and reply.
Yes. I use the same way to making one button(#) as the external interrupt.
Before go into sleep, i make one row pin in "INPUT_PULLUP" type and one column pin in "OUTPUT" type.
When go into interrupt, i change the column pin back to "INPUT" type.
It works.

Thanks
Charles