Wake up from sleep

Hi, I desperately need help with this.

Hardware

Arduino Pro Mini atmega328 5V 16M
4X4 Keypad attached to D2 -> D9

Case

I am using a power saving library that puts the arduino to sleep for 8 seconds, then wake up and check some stuff - and then falling a sleep again.

During this process, I would like to power up the arduino if it is asleep by hitting a key on the keypad, and then enter a programming mode by setting a boolean, to avoid getting to sleep. When programming is done, the boolean is set to false - and then the arduino goes back to sleepmode.

Is this possible, and how do I do this? I dont know that much about interrupts and code behind it.

Best regards, Joakim

I would like to power up the arduino if it is asleep by hitting a key on the keypad

Since the keypad does nothing unless you are actively reading from it, and that doesn't happen while sleeping, that won't happen.

You can connect a switch to an external interrupt pin, and use that to wake the Arduino.

Ahh, that is correct. I guess I have to add a separate pushbutton for this then :slight_smile:

Joakim

You can wake the mcu from a key on the keypad, if either you don't mind if only certain keys on the keypad wake up the mcu, or you use pin change interrupts. You are probably driving the keypad as a matrix, with the columns connected to pins that are driven low one at a time, while the rows are connected to input pins that have the internal pullup resistors enabled. Before you put the mcu to sleep, drive all the column pins low. Then pressing a key will pull one of the row input lines low. If that row line is connected to an input that is also one of the external interrupt pins (digital pins 2 and 3 on an Arduino Uno, corresponding to interrupts 0 and 1), then you can enable that interrupt with mode LOW, and that will wake up the mcu from sleep. If you want keys on row lines attached to other pins to wake up the mcu, then you can use pin change interrupts on those row lines.

dc42 is correct. The keypad library works by polling the pins so if the microcontroller is asleep then the keypad is asleep. You can wire up some diodes and connect the pins to an external interrupt. CrossRoads added a hardware interrupt to his keypad and if you scroll down two more posts you'll see his code to go with it.

Yep. Had to write the keypad columns low when going into sleep, so that pressing a key brought a row pin low, then return the column pins high on waking up so the pins were back where they started.
This app note helped to make the hardware concept clearer. I still used keypad.h library to return the key that was pressed in void loop after the ISR just took the uC out of sleep.
http://www.atmel.com/Images/doc1232.pdf

Thanks guys!

I will redraw all my wiring and start all over again! I will get back when I get lost again!

Joakim

This is so weird, it seems to work fine as long as I don't touch anything. If i touch it very gently and carefully lift up the keypad it works fine as it should. Even if I lay one finger on the board, it shoots an interrupt...what could this interference come from?

I have just check all soldering and they look fine? Could it be my experimental circuit board that affects the arduiono?

I took the code from your sample and sets the rows to low, and then high - after the sleep.

Joakim

Not the rows - the columns.
Need the columns low as the last thing before going to sleep - then a button press bring the Row low and creates the interrupt.

Yes the columns, not the rows. I just wrote it wrong.

Question, if I only want one column to react to the interrupt - could I skip the diode?

Question 2, Is it possible to hook up the keypad to D2 - > D9 and still use D2 for interrupt? Then my column 4 on the keypad would be connected to D2. The keypad fits perfect on this row on my Pro mini so it would have been nice to just hook up the keypad on that row :slight_smile:

Joakim

Ok, I think that I solved this and got everything to work. Thanks for all input guys, it was a bit more clear for me today, was so tired yesterday :slight_smile:

Big Kudos to you all!

Great that I don't need an extra button since I already got 16 :wink:

regards, Joakim

jkrassman:
Question, if I only want one column to react to the interrupt - could I skip the diode?

You don't need the diode anyway.

jkrassman:
Question 2, Is it possible to hook up the keypad to D2 - > D9 and still use D2 for interrupt? Then my column 4 on the keypad would be connected to D2. The keypad fits perfect on this row on my Pro mini so it would have been nice to just hook up the keypad on that row :slight_smile:

If you are using the keypad library at Arduino Playground - HomePage, then you can do this. That library leaves all of the keypad pins configured as inputs with pullup enabled when you are not scanning it. Before going to sleep, digitalWrite 0 to all the row pins, then change their pinModes to Output. Enable the interrupt with mode LOW. Any key connected to the column on the D2 pin will then wake up the mcu. After waking up, disable the interrupt (that bit is best done in the ISR), change all the row pins back to inputs, then digitalWrite HIGH to them all to turn the pullup resistors back on.

DC42, I will try the second thing since it would be much nicer!

I got it to work by freeing D2 now - so I am going the right direction!

Thanks!

DC42, I cant figure out whats going on here, but I feel a little bit insecure when the D2 is the interrupt. Do you think that you could look over my code below?

The interrupt doesn't trigger now and when the sleep is over, it is triggered? Even if I am not touching anything?

Joakim

#include <LowPower.h>
#include <Keypad.h>

// ---------------------------------
// KEPAD DEFINITIONS AND VARIABLES
// ---------------------------------

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};


byte rowPins[ROWS] = {9, 8 , 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4 , 3, 2 }; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

// ---------------------------------
//VARIABLES
// ---------------------------------

  //Programming variables
  boolean enterProgramming = false;
  volatile boolean isWaked = false;
 
  char key;
  
 
  //Interupt / sleep
  int wakePin = 2; 
  
void setup()
{
  Serial.begin(115200);
  Serial.println("Starting up....");
  delay(1000);

  //PIN 2 to INPUT för interupt
  pinMode(wakePin, INPUT);
  
}  
void loop()
{  
 
   
   //First check if we are getting a keystroke to enter programming mode
    key = keypad.getKey();
    delay(100);
 
   if(isWaked==true){
     //we are waken up from our slumber...
     enterProgramming = true;
     isWaked = false;
     delay(100);
     Serial.println("");
     Serial.println("Entering programming mode");
     
   }
   if(enterProgramming==true){
    if(key!=NO_KEY){
      Serial.println(key);
      
      if(key=='D'){
        Serial.println("Exiting programmingmode.");
        enterProgramming = false;
        isWaked = false;
      }
     }
 
   } 

      
 
  
  
  // Main loop when we are not in programming mode
  // Within this statement we should check time and do our powersaving stuff
  
  if(enterProgramming==false){
   isWaked  = 0;
   
   //Set all pins to LOW
   for (int i=2; i <= 9; i++){
      digitalWrite(i, LOW);
      delay(10);
   } 
   
   //Set pinmode to OUTPUT
    for (int i=3; i <= 9; i++){
       pinMode(i, OUTPUT); 
       delay(10);
     } 
 
    
   delay(500);
   Serial.println("Running mode"); 
   attachInterrupt(0,wakeUpNow, LOW);
   delay(100);
   Serial.println("Going to sleep...");
   delay(100);
   // Kör sleep koden
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);  
   delay(100);
   Serial.println("Sleep is over...");
   delay(200);
  
   delay(100);

  	//Put back correct pinmode
    for (int i=3; i <= 9; i++){
       pinMode(i, INPUT); 
       delay(10);
     } 
   
   delay(100);
    //Set all pin to HIGH
   for (int i=3; i <= 9; i++){
      digitalWrite(i, LOW);
      delay(10);
   } 
   
  }
}

void wakeUpNow() {
  detachInterrupt(0); 
  isWaked = true;  
}

You should only be setting the row pins to output, not all the keypad pins. Leave the column pins alone.

Getting the same behavior as before. Now I am only changing pin 6 -> 9 which are my rows?

Joakim

Please post all your code again.

#include <LowPower.h>
#include <Keypad.h>


// ---------------------------------
// KEPAD DEFINITIONS AND VARIABLES
// ---------------------------------

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};


byte rowPins[ROWS] = {9, 8 , 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4 , 3, 2 }; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

// ---------------------------------
//VARIABLES
// ---------------------------------

  //Programming variables
  boolean enterProgramming = false;
  volatile boolean isWaked = false;
 
  char key;
  
 
  //Interupt / sleep
  int wakePin = 2; 
  
void setup()
{
  Serial.begin(115200);
  Serial.println("Starting up....");
  delay(1000);
  //PIN 2 til INPUT för interupt
  pinMode(wakePin, INPUT);
  
}  
void loop()
{  
 
   
   //First check if we are getting a keystroke to enter programming mode
    key = keypad.getKey();
    delay(100);
 
   if(isWaked==true){
     //we are waken up from our slumber...
     enterProgramming = true;
     isWaked = false;
     delay(100);
     Serial.println("");
     Serial.println("Entering programming mode");
     
   }
   if(enterProgramming==true){
    if(key!=NO_KEY){
      Serial.println(key);
      
      if(key=='D'){
        Serial.println("Exiting programmingmode.");
        enterProgramming = false;
        isWaked = false;
      }
     }
 
   } 

      
 
  
  
  // Main loop when we are not in programming mode
  // Within this statement we should check time and do our powersaving stuff
  
  if(enterProgramming==false){
   isWaked  = 0;
   
   //börja med att sätta alla pinnar till LOW
   for (int i=6; i <= 9; i++){
      digitalWrite(i, LOW);
      delay(10);
   } 
   
   //Sätt alla pinmode till output
    for (int i=6; i <= 9; i++){
       pinMode(i, OUTPUT); 
       delay(10);
     } 
 
    
   delay(500);
   Serial.println("Running mode"); 
   attachInterrupt(0,wakeUpNow, LOW);
   delay(100);
   Serial.println("Going to sleep...");
   delay(100);
   // Kör sleep koden
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);  
   delay(100);
   Serial.println("Sleep is over...");
   delay(200);
  
   delay(100);
   //digitalWrite(3, HIGH);
  delay(100);
  //Sätt alla pinmode till input
    for (int i=6; i <= 9; i++){
       pinMode(i, INPUT); 
       delay(10);
     } 
   
   delay(100);
    //börja med att sätta alla pinnar till HIGH
   for (int i=6; i <= 9; i++){
      digitalWrite(i, LOW);
      delay(10);
   } 
   
  }
}

void wakeUpNow() {
   detachInterrupt(0); 
  isWaked = true;
  // DISABLE PIN
  
}

After the comment "börja med att sätta alla pinnar till HIGH" your code sets the pins LOW, but it should set them HIGH (to enable the pullup resistors).

Before you make the powerDown call, you should check the isWaked flag in case there has already been an interrupt.

If it still doesn't work after these changes, check with a multimeter that when it is sleeping, all 4 row outputs are at 0V (due to setting the pins as outputs) and all 4 column inputs are at +5V (because the pullup resistors should already be enabled by the keypad library).

No, that didnt do the trick either. I just checked all pins and they are all LOW?

Joakim