[Solved] Virtualwire message on Interrupt works on "LOW" but not on "CHANGE"

I want RF 434MHz RF transmitter (via virtualwire) to transmit a message whenever an interrupt pin's state is changed. Rest of the time it is expected to sleep.

Interrupt works fine when I am attaching interrupt to "LOW" but it doesn't work on "CHANGE". What is the timing criteria for the CHANGE interrupt??? What am I doing wrong... Please help! (FYI... I am using this code on ATMega8 if it makes any difference)

#include <VirtualWire.h> //load virtual wire library for RF communication 
#include <avr/sleep.h> //load sleep library to allow the Ardunio to go to sleep

const int TxPin = 10;
const int Tx_en_pin = 11;
const int ReedSwitch = 2;    //Reed switch

char msgopen[] = "O\n";
char msgclose[] = "C\n";

int DoorState = 0;  //current state of the Door
int count = 3;        //timer

void setup()
{
  //ADCSRA |= (0 << ADEN); //Disabling ADC
  vw_set_tx_pin(TxPin);
  vw_set_ptt_pin(Tx_en_pin);
  vw_setup(2000); //Virtual wire bits per sec
  pinMode(ReedSwitch, INPUT_PULLUP);
  attachInterrupt(0, wakeUpNow, CHANGE); //either 0 or 1 for interrupts on pin 2 or 3. 
}

void loop()                     
{
  DoorState = digitalRead(ReedSwitch); //read Door State
  
  if (DoorState == LOW) //if door is close the reed switch goes low
  { 
	  count--;               //count down

   if (count == 0) //when counter is 0 send analog value then go to sleep
	 { 
	  vw_send((uint8_t *)msgclose, strlen(msgclose));
	  vw_wait_tx(); // Wait until the whole message is gone
      count = 3;
      sleepNow();     // sleep function called here
	 }
   } 
 
  else 
  {
     count = 3; //reset counter to 3
	 vw_send((uint8_t *)msgopen, strlen(msgopen));
	 vw_wait_tx(); // Wait until the whole message is gone
	 sleepNow();
   }
}

void sleepNow()         // here we put the Ardunio to sleep
{
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	attachInterrupt(0, wakeUpNow, CHANGE);
	sleep_mode();
	sleep_disable();
	detachInterrupt(0);
}

void wakeUpNow()      // here the interrupt is handled after wakeup
{

}

When going to sleep, you detach the interrupt. That's going to make it hard for the interrupt to wake the Arduino, don't you think?

The ISR does nothing. Why do you think it works with LOW but not with CHANGE, when it does nothing?

  if (DoorState == LOW) //if door is close the reed switch goes low
  { 
	  count--;               //count down

WRONG! You should only change the value of count when the switch BECOMES pressed, not when it IS pressed.

Thanks for quick reply... I see your point regarding disabling interrupts in sleep...

Earlier, I tried to disable interrupts in ISR and set a volatile flag and then compare the flag state in the loop. But without much success...

I am comparing the pin state as a double check. A measure to check the proper data of the state.

Let me try that again and see... or u have any other ideas?

I updated the code to moving functions sleep_disable() and detachInterrupt(0) to the ISR.

It still works on interrupt LOW. But if I change it to CHANGE it doesn't work...

Seems like the classic debouncing problem.

Any ideas on implementing software debouncing with interrupts? ( I know the way with hardware but it consumes more power which defeats the purpose :frowning: )

I updated the code to moving functions sleep_disable() and detachInterrupt(0) to the ISR.

So, once you go to sleep, there should be some kind of external interrupt to wake you up. When that happens, you want to disable the interrupt permanently. So, next time you go to sleep, you can't be awakened.

I'm failing to understand that. Must be a weekend thing. Set the alarm. Wake up when it goes off. Smash the alarm into bits. Go back to sleep. Forever.

So, once you go to sleep, there should be some kind of external interrupt to wake you up. When that happens, you want to disable the interrupt permanently. So, next time you go to sleep, you can't be awakened.

This is not right... If you look at the code carefully... When I call the sleepNow() function, the interrupt gets attached again. I disabled sleep in ISR (wakeUpNow() function) , detachInterrupt() in loop. After doing whatever activity in the loop, I attach interrupts again before entering sleep.

void sleepNow()         // here we put the Ardunio to sleep
{
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	attachInterrupt(0, wakeUpNow, CHANGE);
	sleep_mode();
}
void wakeUpNow()      // here the interrupt is handled after wakeup
{
sleep_disable();
}
void loop()
{
detachInterrupt(0);
//do whatever else you want...
sleepNow();
}

This scheme works perfectly for when the interrupt goes LOW. I checked that it goes to sleep by current consumption measurement and wakes up every time the interrupt goes LOW and does the job in the loop goes back to sleep. It wakes up every single time! :slight_smile:

I believe the problem is with not having an external pull up resistor at the interrupt to detect "CHANGE". ( I am currently use internal pull-up by defining the pin as INPUT_PULLUP)

I missed the fact that you are reattaching the interrupt handler. Sorry about that.

I still can't see the need to detach and reattach it, though.

I simply used the standard ways people have done with all those interrupt/sleep examples in numerous tutorials... :slight_smile:

If you have something in mind... why don't you share it? How would you have implemented it?

Turns out it is a limitation of atmega8 only...

For more details on this please see [Solved] ATMEGA8L with External Interrupts won't wake from sleep - Microcontrollers - Arduino Forum