Interrupts and Millis() [SOLVED]

Hi everyone, I'm using an interrupt to read a remote controls input. I'm not using delay() but a function that uses millis() to delay. My problem is that as soon as I attach the interrupt, the function doing the delay with millis() never completes. Is there an alternate timer I should be using?
If someone could point me in the right direction.... I've included the code below if anyone fancies wadig through it!

#include <IRremote.h>
#include <IRremoteInt.h>
#include <Wire.h>
#include "RTClib.h"
#include <HomeEasyAdv.h> 

// Setup PIR
const int pirPin = 8;
int pirVal = 0;     // Raw value

// Setup IR 
IRsend irsend;
const int RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);
decode_results results;

// Setup Light sensor
int lightLevel = 0;
int ldrPin = A0;

// Setup RTC 
RTC_DS1307 RTC;

// Setup 433Mhz RF
#define TXPIN 4
#define RXPIN 0    // This is never used as we only TX. Generates a compiler error w/o pin assignment.
#define REMOTE_ADDRESS 4597902  // Address of the HomeEasy Remote
HomeEasyAdv homeeasy = HomeEasyAdv(RXPIN, TXPIN, REMOTE_ADDRESS );
const byte socketLamp = 0;
const byte socketDome = 1;
const byte socketXBMC = 2;

// Samsung IR Code Array
// These are raw codes copied from remote
unsigned int samKeyZero[68] = {4550,4400,600,1650,600,1600,600,1650,600,500,600,550,600,500,600,500,600,550,600,1600,600,1650,600,1600,600,550,600,500,600,500,600,550,600,500,600,1650,550,550,600,500,600,500,600,1650,600,500,600,550,600,500,600,500,600,1650,600,1650,550,1650,600,500,600,1650,600,1650,600,1600,600};  
unsigned int samSource[68] = {4550,4400,600,1650,600,1600,600,1650,600,500,600,550,600,500,600,500,600,550,600,1600,600,1650,600,1600,600,550,600,500,600,500,600,550,600,500,600,1650,600,500,600,500,600,550,550,550,600,500,600, 500,600,550,600,500,600,1650,600,1600,600,1650,600,1650,550,1650,600,1650,600,1600,600};
unsigned int samDown[68] = { 4500,4350,600,1600,600,1600,600,1650,600,500,600,500,600,500,600,500,600,500,600,1600,600,1650,550,1650,600,500,600,500,600,500,600,500,600,500,600,1600,600,500,600,500,600,550,550,550,550,1650,600,1600,600,500,600,500,600,1600,600,1650,550,1650,600,1600,600,500,600,500,600,1600,600};
unsigned int samKeyTV[68] = {4500,4450,600,1600,600,1650,600,1650,600,500,600,500,600,550,550,550,600,500,600,1650,600,1600,600,1650,600,500,600,550,550,550,600,500,600,500,600,1650,600,1650,600,500,600,1650,600,1600,600,550,600,500,600,500,600,500,600,550,600,1600,600,550,600,500,600,1650,600,1600,600,1650,600};
unsigned int samSelect[68] = {4500,4450,600,1600,600,1650,600,1600,600,550,600,500,600,500,600,550,600,500,600,1600,600,1650,600,1650,600,500,600,500,600,550,600,500,600,500,600,550, 600,500,600,500,600,1650,600,500,600,1650,600,1600,600,550,600,1600,600,1650,600,1650,600,500,600,1600,600,550,600,500,600,1650,600};
unsigned int samPowerOff[68] = {4550,4400,600,1600,650,1600,600,1650,600,500,600,500,650,500,600,500,600,500,600,1650,600,1600,650,1600,600,500,650,500,600,500,600,500,650,500,600,500,600,1600,650,500,600,500,600,500,650,500,600,500,600,500,600,1650,600,500,650,1600,600,1600,600,1650,600,1650,600,1600,650,1600,600};

// XBMC Button ID Codes
long xbmcOne = 1231295254;
long xbmcTwo = 485710105;
long xbmcThree = 4048549466;
long xbmcFour = 1048693617;
long xbmcFive = 2368749434;
long xbmcSix =  959017269;
long xbmcSeven = 226889334;
long xbmcEight = 2408122201;
long xbmcMenu = 168945401;
long xbmcUp = 4004649538;
long xbmcDown = 2684593721;
long xbmcEnter = 3468483545;

// Xbox 360 PowerOn Code
unsigned long long OnOff = 0xc800f740cLL;
// Toggle bit for RC6 Codes
int toggle = 0;

// Status LEDS
int statusLED = 5;
int redLED = 6;
int amberLED = 7;

// Time related vars
const int delay_time = 300;  // Delay for the IR TX
int lastSelected = 0; // Last command selected
long currentTime; // Holds timestamp from RTC

void setup()
{
  Serial.begin(9600);
  Serial.println("Serial enabled...");
  attachInterrupt(0, handleISR, CHANGE);
  irrecv.enableIRIn();          // Start the receiver
  pinMode(pirPin, INPUT);
  pinMode(redLED, OUTPUT);
  pinMode(amberLED, OUTPUT);
  pinMode(statusLED, OUTPUT);
  Wire.begin();
  RTC.begin();
  
}  


//  // Soft reset function jmp to add 0 - start of code!
void(* resetFunc) (void) = 0;

// Delay() won''t work with interrupts!
// This is the problem... 
void pause(long duration)    
{
    long currentTime = millis();
    long endTime = currentTime + duration;
    while(millis() < endTime)
    {
    // Do nothing
    }
} 

// Blinks LED
void blinkLED(int duration, int pin)
{
  pinMode(pin,OUTPUT);
  digitalWrite(pin, HIGH);
  pause(duration);
  digitalWrite(pin, LOW);
}


void handleISR()
{
  {
    digitalWrite(amberLED, LOW);    
    if (irrecv.decode(&results))
    { 
      digitalWrite(statusLED, LOW);    //turn off status led so we know not to re send  
      Serial.println(results.value);
      blinkLED(200, amberLED);         // Blink amber led to show IR recv
     
      if (results.value == xbmcOne)
      { 
        irsend.sendSony(0xa90, 12);    
        HEsocketOn(socketXBMC);     
        switchToXBMCVideos();
        Serial.println("XBMC Videos");  
      }
      if (results.value == xbmcTwo)
      { 
        switchToXBox360();
        Serial.println("Xbox 360");
      }
   
      if (results.value == xbmcThree)
      { 
      // XBMC Volume Control 
      }
   
      if (results.value == xbmcFour)
      {
        irsend.sendSony(0xa90, 12);
        HEsocketOn(socketLamp);
        irsend.sendSony(0xa90, 12);
        HEsocketOn(socketDome);
        Serial.println("Lights on");
       } 
    
      if (results.value == xbmcFive)
      {
        irsend.sendSony(0xa90, 12);
        HEsocketOff(socketLamp);
        irsend.sendSony(0xa90, 12);
        HEsocketOff(socketDome);
        Serial.println("Lights off");
      }
  
      if (results.value == xbmcSix)
      {
        // XBMC Volume Control
      }
   
      if (results.value == xbmcSeven)
      {
         
      }

      if (results.value == xbmcEight)
      {
        switchAllOff();
        Serial.println("All off");
      }   
    resetFunc();
  }
}
}


void switchToXBMCVideos()
{
  digitalWrite(amberLED, HIGH);
  blinkLED(100,redLED);
  irsend.sendRaw(samKeyZero,68,38);
  pause(1000);
  blinkLED(100,redLED);
  irsend.sendRaw(samKeyTV,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samSource,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samDown,68,38);
  pause(delay_time);
  blinkLED(100,redLED);  
  irsend.sendRaw(samDown,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samSelect,68,38);
}
Part 2 of code...
[code]// Sends simulated key presses to Samsung TV
void switchToXBox360()
{
  digitalWrite(amberLED, HIGH);
  blinkLED(100,redLED);
  irsend.sendRaw(samKeyZero,68,38);
  pause(1000);
  blinkLED(100,redLED);
  irsend.sendRaw(samKeyTV,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samSource,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samDown,68,38);
  pause(delay_time);
  blinkLED(100,redLED);  
  irsend.sendRaw(samDown,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samDown,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samDown,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samSelect,68,38);
}

// Sends XBox 360 On/Off
void sendOnOff() {
  blinkLED(200, amberLED);
  if (toggle == 0) {
    irsend.sendRC6(OnOff, 36);
  } 
  else {
    irsend.sendRC6(OnOff ^ 0x8000, 36);
  }
  toggle = 1 - toggle;
}

// Everything off
void switchAllOff()
{
  blinkLED(100,redLED);
  irsend.sendRaw(samKeyTV,68,38);
  pause(delay_time);
  blinkLED(100,redLED);
  irsend.sendRaw(samPowerOff,68,38);
  for (int a=0; a<= 10; a++)
  {
    blinkLED(250, amberLED);
    pause(500);
    blinkLED(250, redLED);
  }
  HEsocketOff(socketLamp);
  HEsocketOff(socketDome);
  HEsocketOff(socketXBMC);
  
}

// HomeEasy socket on
void HEsocketOn(int socketNo)
{
  for (int a=0; a<=5; a++){
  homeeasy.on(socketNo);}
  Serial.print("Socket On - ");
  Serial.println(socketNo);
}

//HomeEasy socket off
void HEsocketOff(int socketNo)
{
  for (int a=0; a<=5; a++)
      {homeeasy.off(socketNo);}
   Serial.print("Socket off - ");
   Serial.println(socketNo);
}


void loop() 
{
  digitalWrite(amberLED, LOW);
  digitalWrite(statusLED, LOW);
  lightLevel = analogRead(ldrPin);
  pirVal = digitalRead(pirPin);
 
  if (pirVal == HIGH && lightLevel <= 100)  // If it's dark, let there be light and TV
   {
     irsend.sendRaw(samKeyZero,68,38);
     HEsocketOn(socketLamp);
     HEsocketOn(socketDome);
     HEsocketOn(socketXBMC);
     switchToXBMCVideos();
     resetFunc();
   }
  
  if (pirVal == HIGH && lightLevel >= 100)    // Someone in room
  {                                           // LED to show system is ready
    digitalWrite(statusLED, HIGH);
  }
 
  if (pirVal == LOW && (millis() >= 900000))   // If room is empty for <=
    {                                          // 15 mins, switch off
     for (int a=0; a<4; a++)
     { 
       blinkLED(500, statusLED);
       blinkLED(500, amberLED);
       blinkLED(500, redLED);
     }
     switchAllOff();
     resetFunc();
    }
}

[/code]

Timer 0 is used by the system code that implements millis(). I suggest you use timer 2 instead. There is a library called MsTimer2 that may help you.

Thanks @dc42 - you pointed me in the correct direction.
I stumbled across this...

#include <util/delay.h>
void pause(long time)     // Delay() won''t work with interrupts!  
{ 
 while (time--) 
   _delay_ms(1); 
}

From what I gather it counts CPU cycles for the timekeeping?! I'm just happy to have a delay I can use within an interrupt!

I'm just happy to have a delay I can use within an interrupt!

This is a poor solution to properly arranging the code. An interrupt service routine should be FAST! No serial printing, no lcd clearing, no diddling at all. All that the ISR should do is set a flag that indicates that loop() needs to do something. The something that loop() does can include delay()s, since they can then be interrupted, when serial data arrives, for instance, or when the clock ticks.

As PaulS says, you should not be doing anything in an ISR that involves delaying other than for very short amounts of time (e.g. a few microseconds). Change your ISR to set a flag that tells the code in your main loop() function that the LED needs to be blinked. Don't forget to declare the flag variable 'volatile'.

Fair enough! All I need the ISR to do is read a remote control keypress. I could send that value to function.
I'll have another look at my code, I've got everything working the way it should - now it's just a case of doing things properly!
I rejigger things and let you know how I get on!
Thanks for the input guys - I'm learning, albeit slowly!

I'm learning, albeit slowly!

The first half of that statement is the important part. Speed doesn't matter. Progress does,

Hi PaulS - thanks for the words of encouragement!
I've rejiggered my code as per your instructions, and it's easier to read, and I think I've cracked the ISR...

boolean gotInput = LOW;
void handleISR()
{ 
    if (irrecv.decode(&results))
    {
      inputCode = results.value;
      gotInput = HIGH;
    }
}

And the vastly simplified main loop.

void loop() 
{
  digitalWrite(amberLED, LOW);
  digitalWrite(statusLED, LOW);
  lightLevel = analogRead(ldrPin);
  pirVal = digitalRead(pirPin);
  pollSensors();
  if (gotInput == HIGH)
    {getInput();} 
 
  
}

One question though - should I replace the lazy delay_ms I found in <util/delay.h> with the regular delay()? I've not declared gotInput as volatile boolean. Should I?
Thanks again for taking the time to read through all this PaulS, you're an enormous help, and it's massively appreciated!

and it's easier to read

That it is. One thing, though. Boolean variables are typically assigned values of true and false, not HIGH and LOW.

should I replace the lazy delay_ms I found in <util/delay.h> with the regular delay()?

For now, yes, since delay() can be used to delay more than one millisecond.

Then, look at the blink without delay example to see how to get rib of delay() altogether.

Thanks PaulS! I'll take a look at that example - and get rid of delay() and delay_ms()