Keypad sleep and interrupt execute help

Hi. I'd like to use an Arduino and keypad to operate a scoreboard remotely. Code I've written works for that.

I'm now trying to conserve power by sleeping the processor when not in use and wake it with any button press.

From what I read, an interrupt with diode to each key could work. However I would like the single key press to not only trigger the interrupt to get the Arduino out of the deep sleep state, but also acknowledge which button was just pressed and execute the code for that button (i.e. update the score, etc), then go back to sleep in say 30 seconds.

Is this possible? I'm having problems finding any similar code that I can work with - my coding knowledge is not great. Any direction would really be appreciated.

From what I read, an interrupt with diode to each key could work.

Not from a keypad, though. The way that a keypad is read requires active participation from the Arduino, which won't happen when it is sleeping.

PaulS: Not from a keypad, though. The way that a keypad is read requires active participation from the Arduino, which won't happen when it is sleeping.

Would this work. I pull each keypad column LOW with say a 10K resistor. I connect each row to the single interrupt via a diode. When the processor is put to sleep, the interrupt pin is left HIGH(possible??). So when I press a keypad button, the FALLING state wakes it. If the button is not released too quickly, can the keypad code still read what button is down and execute the correct code.

I've been looking at the following LINK

Alternatively, can a device (CDxxxx?) pull each column HIGH with a resistor whilst the processor is asleep, but flip it to low with the same resistor when the processor is asleep and function normally?

Would this work.

No. Look at the keypad library. It iterates over the rows and columns, changing pin states, to detect that a key is pressed, and returns the value at the row and column of the array of values, if any key is pressed.

You can not know, when you go to sleep, what state the pins are in.

Adding a "wake me up" switch would work. The keypad switches will not work to wake the Arduino.

What does the scoreboard look like? How is it powered? Why can't that power power the Arduino?

The keypad can be used to wake the Arduino.
Heres is a Promini with 4x4 keypad, coded so that a keypress causes a Low on the interrupt pin to wake the Promini and have it scan the keypad. Sends the key pressed, and goes back to power down sleep mode.

The key to getting it work was to write the column pins low just before going to sleep so that when a key was pressed, it would put a low on a diode’s cathode to pull down the internally-pulled up interrupt line.
Simpler_remote.jpg

CrossRoads:
The keypad can be used to wake the Arduino.
Heres is a Promini with 4x4 keypad, coded so that a keypress causes a Low on the interrupt pin to wake the Promini and have it scan the keypad. Sends the key pressed, and goes back to power down sleep mode.

Yes, I think that’s exactly what I was hoping to do.

I’m experimenting on using a mini pro 3.3V, powered by a 9V alkaline battery with 3.3V reduction via an LDO that has a quiescent current of just 10uA, along with an NRF24L01 (discussions in a previous thread). The deep sleep mode I think will keep the remote unit working alot longer. Waking and operating is just my issue here.

CrossRoad, where I’m struggling is in the code (as said, I’m a novice). I’ve got the score transmitting working. I’ve also experimented with deep sleep and wake via an interrupt. Works well. It’s the arrangement of merging in the sleep, interrupt wake, read, execute then go back to bed! Any help would be appreciated.

(PS. Paul, my guess is you were thinking I was trying to drive the interrupt directly via the keypad library, that yes, requires the arduino awake. My intent was to bypass with diodes somehow).

See my page about power saving - that has an example of using pin-change interrupts to wake up on pressing any key on a keypad.

No diodes required, I don't think. It uses 100 nA when asleep.

[quote author=Nick Gammon date=1477183455 link=msg=2971432] See my page about power saving - that has an example of using pin-change interrupts to wake up on pressing any key on a keypad. [/quote] Interesting Nick. I was your other thread (LINK), that lead me down this path, thinking this was possible. I'll check out the new link you provided (thanks)...

Here’s what I did. I couldn’t make PCINTs work, but I was pretty new to C++ programming back in 2011.

transmitter_Weapon_March2.ino (11.1 KB)

[quote author=Nick Gammon link=msg=2971432 date=1477183455] See my page about power saving - that has an example of using pin-change interrupts to wake up on pressing any key on a keypad[/quote] Nick, I tried this, however it came up with the error:

sketch_oct23a:30: error: 'Keypad' does not name a type Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

You mentioned in the article something about using a library Keypad2.h. However, even when I installed it, the same error appears.

Restart the IDE after installing it. You should be able to get past that error.

[quote author=Nick Gammon date=1477199516 link=msg=2971542]
Restart the IDE after installing it. You should be able to get past that error[/quote]
I’ve resolved the error by using keypad.h library instead. I changed that in the code, including the row length (for my 4 x 3 keypad), changed the pin numbers and juggled until they read correctly.

I’ve got a problem however. Only every second press runs the blink part of the code. It seems with the 1st press it works - blinks the right number. Then with the next press, blinks nothing. I’m guessing it somehow picks up a value of 0 to blink. The next blink works correctly again. Any ideas what’s wrong here

Code below with my changes. Changes highlighted with //---------

// Wake from deep sleep with a keypress
// Author: Nick Gammon
// Date: 18th November 2012

//---------copy of nick's notes from website:
// This code enables sleeping a processor until a key on the keypad is pressed.
// The general idea is that, before sleeping, the sketch sets all the rows
// to HIGH (pull-up) and all columns to LOW (output).
// If no button is pressed all the rows will be high (because of the pull-up).
// Then if a button is pressed the row will go LOW, and cause a pin change.
// The pin-change interrupt triggers, waking up the processor and executing code
// Before falling asleep again


#include <Keypad.h>
#include <avr/sleep.h>
#include <avr/power.h>

const byte ROWS = 4;
const byte COLS = 3;

char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'},
};

//---------pin numbers below changed to suit:
byte rowPins[ROWS] = {14, 15, 16, 17}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {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)
*/


// turn off interrupts until we are ready
ISR (PCINT0_vect)
{
  PCICR = 0;  // cancel pin change interrupts for D8 to D13
} // end of ISR (PCINT0_vect)

ISR (PCINT1_vect)
{
  PCICR = 0;  // cancel pin change interrupts for A0 to A5
} // end of ISR (PCINT1_vect)

ISR (PCINT2_vect)
{
  PCICR = 0;  // cancel pin change interrupts for D0 to D07
} // end of ISR (PCINT2_vect)

void setup ()
{
  Serial.begin(115200);
  pinMode (ledPin, OUTPUT);

//---------pin changes below altered to suit:
  // pin change interrupt masks (see above list)
  PCMSK1 |= bit (PCINT8);   // pin 14
  PCMSK1 |= bit (PCINT9);   // pin 15
  PCMSK1 |= bit (PCINT10);  // pin 16
  PCMSK1 |= bit (PCINT11);  // pin 17

}  // end of setup

// set pins as keypad library expects them


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;

  power_all_disable ();  // turn off various modules

  PCIFR  |= bit (PCIF0) | bit (PCIF1) | bit (PCIF2);   // clear any outstanding interrupts
  PCICR  |= bit (PCIE0) | bit (PCIE1) | bit (PCIE2);   // enable pin change interrupts

  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS);
  sleep_cpu ();

  // cancel sleep as a precaution
  sleep_disable();
  power_all_enable ();   // 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();
//---------rough way to convert ascii numbers to keypad number:
  byte keyValue = key - 48; // Setup for serial monitor converted to keypad number
  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
//----------print out key number
  Serial.println(keyValue);

} // end of loop

It seems no matter what change I do, the first key press does wake the processor, the print to screen the button I press, however prior to going to sleep kid.getkey sets the variable "key" to zero. Hence when I press a key again, on waking it doesn't return that key number. It needs a second press to correct itself.

Can someone please help here.

Can you give the exact link to the keypad library you used please?

My keypad2 library (well - it isn’t mine, but the one I used) is available here.

I just tested it with the code from my website I linked above and it works perfectly. It responds each time you press a key.

I tried restarting my IDE, however for me the keypad2.h still didn't work. I'm not an expert in libraries, but I would have thought, given the name of the library being Keypad2, that the line:

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

should have read ??:

Keypad2 kpd = Keypad2( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

I'm probably just showing my ignorance.

Regardless, here's the link to the keypad library I used (last edit seems 2013) : LINK

PS. Thanks for sharing that code - it's fabulous!

However I'd really would like to fully understand it. Is the way it's working by using a power signal to trigger an interrupt? Is it possible that on your website where you have this written, you give a bit of an outline of how it works. From what I read, it seems to wake the processor then sleep it immediately after. Also, not sure why all the extra code for sleeping, when I thought the power and the sleep the libraries took care of all that in: set_sleep_mode (SLEEP_MODE_PWR_DOWN);. I really would like to fully understand it if possible. Chris.

Keypad2 is just the name of the include file. Things within it can be named anything. It compiled fine for me. I suggest you move the other keypad library somewhere else outside the sketches and library folders (like your desktop), and then restart the IDE. Make sure you include the new library:

#include <Keypad2.h>

however for me the keypad2.h still didn’t work

Please copy and paste the error messages. “Didn’t work” can mean anything.

Also, not sure why all the extra code for sleeping …

The extra code is what makes it work. It reconfigures the keypad pins so that columns are all low, and rows are all high (input_pullup). That way, you get a pin-change interrupt on the rows because now any key-press pulls that row low (from the input pullup) which make the pin-change interrupt trigger.

It then reconfigures the rows and columns back to how the Keypad library expects them, and exits. The keypad library then re-reads the rows and columns and works out which key was pressed.

I've tried to remove all keypad libraries bar the one and loaded the keypad2 library in the code. The following error comes up:

'Keypad' does not name a type. In the text window it then says:

_09_Keypad_sleep_interrupt:39: error: 'Keypad' does not name a type

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); ^ C:\Users\CJ\arduino-1.0.5-r2\examples_09_Keypad_sleep_interrupt_09_Keypad_sleep_interrupt.ino: In function 'void loop()':

_09_Keypad_sleep_interrupt:182: error: 'kpd' was not declared in this scope

byte key = kpd.getKey(); ^ exit status 1 'Keypad' does not name a type

Try a more modern version of the IDE. I was compiling under 1.6.9 - your IDE of 1.0.5 is way out of date.

Sorry, the file location for the code is in an old directory (that's where you're reading the 1.05), but the version I'm using is 1.6.7.

I do however also have loaded 1.6.3. I might try that one when I get home and see if that resolves the issue.