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.
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
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.
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
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
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 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;
}
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).