Author Topic: Can you wake Moteino Mega using Pin change interrupt?  (Read 2534 times)

dave_sausages

  • Newbie
  • *
  • Posts: 49
Can you wake Moteino Mega using Pin change interrupt?
« on: September 03, 2016, 03:22:42 AM »
Hi all,

How do you go about waking a Moteino Mega from sleep on a pin change interupt? I've got a momentary push button that is connected to Digital pin 3, and it goes low when pressed. It it held high when not pressed by a 10k resistor.

I've also mastered getting my moteino mega to sleep using the lowpower library, but I can't work out how to make it wakeup when the button is pressed.

I've searched for hours but I can't find anything that doesn't end with either no answer or someone saying they're doing it wrong.

Here's my non working code that I borrowed from here and tried to modify it: https://lowpowerlab.com/forum/moteinomega/pin-change-interrupts-moteino-mega-pinchange-(solutionlibrary)/msg7637/#msg7637 (although that post also ends with someone saying they've done it wrong, and should use a certain library. But when I try to use that library, I find it's missing files and won't compile.

Code: [Select]
#include <LowPower.h>
#include <avr/interrupt.h>
//#include <RFM69.h>
//#include <SPI.h>

// Help from
// http://www.geertlangereis.nl/Electronics/Pin_Change_Interrupts/PinChange_en.html

volatile int pinChanged;

void setup() {
 
  pinChanged = 0;
  // put your setup code here, to run once:
  pinMode(3, INPUT);
 
 
  PCMSK0 |= (1<<PCINT11);
  PCICR |= (1<<PCIE1);
  sei();
 
  Serial.begin(9600);
}
void loop() {
 
  // woken up, either because the button was pressed or we
  // woke up naturally
  Serial.flush();
  Serial.println("");
  Serial.println("Woke up");
 
  if (pinChanged == 1) {
    Serial.println("Button pressed!!!");
    // reset
    pinChanged = 0;
  } else {
    Serial.println("We woke up naturally");
  }
 
  doStuff();
 
  checkButton();

  kip();
  // going to kip
  //Serial.println("Going to sleep for 8 secs ... nite!!!");
  //Serial.flush();
  //LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

void kip() {
  // going to kip
  Serial.println("");
  Serial.println("Going to sleep for 8 secs ... nite!!!");
  Serial.flush();
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

ISR(PCINT0_vect) {
  pinChanged = 1;
}

void checkButton() {
  if (pinChanged == 1) {
    Serial.println("Button pressed");
    // reset
    pinChanged = 0;
  }
}

void doStuff() {
  // just sleep for 3 secs
  Serial.println("Doing stuff for 3 secs");
  for (int i = 0; i < 3; i++) {
    checkButton();
    Serial.print(".");
    delay(1000);
  }
  Serial.println("");
  Serial.println("Stuff done");
}

Surely someone knows an easyish way to do this?

And here is another sketch that I've been trying, and doesn't work. When I press the button it prints low once, but no amount of button pressing will make it wake up. It does print High constantly until I press it the first time of course.

Code: [Select]
#include "LowPower.h"
#include <PinChangeInt.h>
 

// constants won't change. They're used here to
// set pin numbers:
const int buttonPin = 3;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

void WakeHandler()
{
  // Nothing to do; just wakes the device.
}

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  Serial.print("begin");
 }

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    // turn LED on:
     Serial.print("high");
     
   
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
     Serial.println("Low");
     delay(500);
     Serial.flush();
    PCintPort::attachInterrupt(buttonPin, &WakeHandler, LOW);
     LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
     PCintPort::detachInterrupt(buttonPin);
     Serial.print("I woke");
  }
}

void burpcount()
{
  Serial.println("d");
}
« Last Edit: September 04, 2016, 03:29:10 AM by dave_sausages »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6007
  • Country: us
    • LowPowerLab

TomWS

  • Hero Member
  • *****
  • Posts: 1892
Re: Can you wake Moteino Mega using Pin change interrupt?
« Reply #2 on: September 05, 2016, 09:12:58 PM »
Hmm please see if this thread helps: https://lowpowerlab.com/forum/moteinomega/pin-change-interrupts-moteino-mega-pinchange-(solutionlibrary)/
Actually this is a better link: https://lowpowerlab.com/forum/moteinomega/moteino-mega-pin-change-interrupts/msg9379/#msg9379

GreyGnome fixed this with the EnableInterrupt library.  You do have to make a couple of insignificant changes to your sketch, but it's worth it to get this support on Mega.

Tom

syrinxtech

  • Sr. Member
  • ****
  • Posts: 306
  • Country: us
    • Syrinx Technologies
Re: Can you wake Moteino Mega using Pin change interrupt?
« Reply #3 on: September 06, 2016, 08:22:05 PM »
I haven't done it with a Mega but I do use the same concept with a regular Moteino.

The project is a water leak detector which uses a probe sitting in the tray beneath my hot water heater.

I sleep in a loop of 8sec and every 12 hours report in the battery voltage.

I use pin A0 for the leak detector, A7 for the voltage monitor, D7 for a buzzer and a pushbutton on D6 to silence the alarm.


dave_sausages

  • Newbie
  • *
  • Posts: 49
Re: Can you wake Moteino Mega using Pin change interrupt?
« Reply #4 on: September 08, 2016, 12:10:28 AM »
Hmm please see if this thread helps: https://lowpowerlab.com/forum/moteinomega/pin-change-interrupts-moteino-mega-pinchange-(solutionlibrary)/
Actually this is a better link: https://lowpowerlab.com/forum/moteinomega/moteino-mega-pin-change-interrupts/msg9379/#msg9379

GreyGnome fixed this with the EnableInterrupt library.  You do have to make a couple of insignificant changes to your sketch, but it's worth it to get this support on Mega.

Tom

so I've tyring to get it to work for a few hours, and have failed. I downloaded and installed the EnableInterrupt library and inserted these bits of code:

Code: [Select]
#include <EnableInterrupt.h>


void setup() {

}

void loop() {

enableInterrupt(3, wake, FALLING);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}

void wake()
{
 
}

But it get these error messages:
Code: [Select]
Arduino: 1.6.11 (Windows 10), Board: "MoteinoMEGA"

In file included from C:\Users\Dave\Documents\Arduino\My programs\v3 mexico\handset\_0.5_power_extend\_0.5_power_extend.ino:17:0:

C:\Users\Dave\Documents\Arduino\libraries\EnableInterrupt/EnableInterrupt.h:22:121: note: #pragma message: NOTICE: *** EnableInterrupt library version 0.9.7. This is not a problem. Keep calm, and carry on. ***

 #pragma message("NOTICE: *** EnableInterrupt library version 0.9.7. This is not a problem. Keep calm, and carry on. ***")

                                                                                                                         ^

C:\Users\Dave\AppData\Local\Temp\build840e61a59f774754f0d7861c820526fd.tmp/core\core.a(WInterrupts.c.o): In function `__vector_1':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WInterrupts.c:309: multiple definition of `__vector_1'

sketch\::5_power_extend.ino.cpp.o:C:\Users\Dave\Documents\Arduino\libraries\EnableInterrupt/EnableInterrupt.h:1284: first defined here

C:\Users\Dave\AppData\Local\Temp\build840e61a59f774754f0d7861c820526fd.tmp/core\core.a(WInterrupts.c.o): In function `nothing':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WInterrupts.c:35: multiple definition of `__vector_2'

sketch\::5_power_extend.ino.cpp.o:C:\Users\DaveEd\Documents\Arduino\My programs\v3 mexico\handset\::5_power_extend/::5_power_extend.ino:580: first defined here

C:\Users\Dave\AppData\Local\Temp\build840e61a59f774754f0d7861c820526fd.tmp/core\core.a(WInterrupts.c.o): In function `nothing':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WInterrupts.c:35: multiple definition of `__vector_3'

sketch\::5_power_extend.ino.cpp.o:C:\Users\Dave\Documents\Arduino\My programs\v3 mexico\handset\::5_power_extend/::5_power_extend.ino:580: first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board MoteinoMEGA.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

So I did some searching and found this post explaining that there's a conflict between the radiohead library and enable interrupt. https://github.com/GreyGnome/EnableInterrupt/issues/3

The author suggested a fix so inserted two new lines of /* and */ like so:

Code: [Select]
#ifndef EI_NOTEXTERNAL
#ifndef EI_NOTINT0
/*
ISR(INT0_vect) {/*{{{*/
#ifndef NEEDFORSPEED
#ifdef EI_ARDUINO_INTERRUPTED_PIN

and

Code: [Select]
#endif
#endif
#if defined ARDUINO_328
#ifdef INTERRUPT_FLAG_PIN3
  INTERRUPT_FLAG_PIN3++;
#endif
#endif
#endif // NEEDFORSPEED
}/*}}}*/
*/
#endif // EI_NOTINT1
#endif

#if defined ARDUINO_MEGA || defined ARDUINO_LEONARDO || defined MIGHTY1284
#ifndef EI_NOTINT2
ISR(INT2_vect) {/*{{{*/
#ifndef NEEDFORSPEED
#ifdef EI_ARDUINO_INTERRUPTED_PIN
#if defined MIGHTY1284

Now I get these error messages:
Code: [Select]
Arduino: 1.6.11 (Windows 10), Board: "MoteinoMEGA"

In file included from C:\Users\Dave\Documents\Arduino\My programs\v3 mexico\handset\_0.5_power_extend\_0.5_power_extend.ino:17:0:

C:\Users\Dave\Documents\Arduino\libraries\EnableInterrupt/EnableInterrupt.h:22:121: note: #pragma message: NOTICE: *** EnableInterrupt library version 0.9.7. This is not a problem. Keep calm, and carry on. ***

 #pragma message("NOTICE: *** EnableInterrupt library version 0.9.7. This is not a problem. Keep calm, and carry on. ***")

                                                                                                                         ^

In file included from C:\Users\Dave\Documents\Arduino\My programs\v3 mexico\handset\_0.5_power_extend\_0.5_power_extend.ino:17:0:

C:\Users\Dave\Documents\Arduino\libraries\EnableInterrupt/EnableInterrupt.h:1303:39: error: expected constructor, destructor, or type conversion before ';' token

   (*functionPointerArrayEXTERNAL[0])();

                                       ^

C:\Users\Dave\Documents\Arduino\libraries\EnableInterrupt/EnableInterrupt.h:1339:1: error: expected declaration before '}' token

 }/*}}}*/

 ^

exit status 1
Error compiling for board MoteinoMEGA.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

And the library is now downloaded from here https://bintray.com/greygnome/generic/EnableInterrupt/view#files
« Last Edit: September 08, 2016, 12:19:29 AM by dave_sausages »

incognico

  • Newbie
  • *
  • Posts: 15
  • Country: au
Re: Can you wake Moteino Mega using Pin change interrupt?
« Reply #5 on: September 08, 2016, 01:50:21 AM »
I don't have a Moteino Mega or even any ATmega1284 here so I can't really help work this through, sorry.

In my mind using a PINCHANGE interrupt here is adding complexity - can you use D10 or D11 (hardware INT0 and INT1) instead? Or are you using Serial1? I'd be trying to get basic external wakeup working before adding PCINT complexity.

Looking at your first post, with the first [non working] code, I notice that the pin change mask PCMSK0 is being set -

Code: [Select]
PCMSK0 |= (1<<PCINT11);
However, looking at the 1284p datasheet, PCINT11 is actually masked by the PCMSK1 register...  :-X


TomWS

  • Hero Member
  • *****
  • Posts: 1892
Re: Can you wake Moteino Mega using Pin change interrupt?
« Reply #6 on: September 08, 2016, 07:24:46 AM »
@dave_sausages, all you should need to do to get EnableInterrupt to coexist with RFM69 library is add:

Code: [Select]
#define EI_NOTEXTERNAL

to the beginning of your sketch file.  This disables the logic to map Int0 & Int1 to EnableInterrupt pins and maps only normal pins as interrupt sources. 

Tom