timer not working in a function

I have a function with a timer in it which doesn't seem to be working toggleLeds(). When I hit a button the pin strobes quickly, so fast that it's hard to turn it on or off. You'll see in the code below that I have the timer set to 2 seconds but the pin still strobes. How can I get this timer to function properly?

Thanks
Rich

void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      // toggle led i
      toggleLed(i);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

You're going to have to show the rest of the code. Nobody can tell from this one function why your code doesn't work unless you show us how and when it is called. If you know where the problem is, then fix it. If you don't know where the problem is then how do you know which section of code to show? So show it all if you want help.

#include <IRLib.h>

const byte RECV_PIN = A4; //byte big enough

byte LedPins[] = {4, 5, 6, 7, 8, 9, 10, 11, 12}; //byte is big enough
bool ledsState = LOW; //bool is big enough

byte LedValues[sizeof(LedPins)];

// a struct to hold information about a led
struct LED
{
  byte pin;
  byte value;
  bool canDim;  // indicate if LED can be dimmed or not
};

// an array of 3 LED structs
LED leds[] = {
  {5, 128, true},   // pin 5, start value half dimmed, can be dimmed
  {6, 128, true},   // pin 6, start value half dimmed, can be dimmed
  {9, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {10, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {11, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {4, 255, false},  // pin 4, start value ON (255)
  {7, 0, false},   // pin 7, start value OFF (0)
  {8, 0, false},   // pin 8, start value OFF (0)
  {12, 0, false},   // pin 13, start value OFF (0)
};

IRrecv My_Receiver(RECV_PIN);

void setup()
{
  //Make all LedPins output
  for (byte i = 0; i < sizeof(LedPins); i++) { //LedPins is a byte so no need to devide the size
    pinMode(LedPins[i], OUTPUT);
  }
  for(int cnt=0;cnt<3;cnt++)
  {
    pinMode(leds[cnt].pin, OUTPUT);
    digitalWrite(leds[cnt].pin, leds[cnt].value);
  }
  My_Receiver.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  Serial.print("Ready!");
}

void loop()
{
  unsigned long code = irSignals();
  switch (code)
  {
    case 0:           // no new IR code
      break;
    case 0x95EB7802:  // button #0
      // toggle all LEDs
      Serial.println("0 button");
      toggleLeds();
      break;
    case 0x153350A5:  // button #1
      // toggle first LED
      Serial.println("1 button");
      toggleLed(0);
      break;
    case 0x37D56044:  // button #2
      // toggle second LED
     Serial.println("2 button");
     toggleLed(1);
      break;
    case 0xF3DFCA53:  // button #3
      // toggle third LED
      Serial.println("3 button");
      toggleLed(2);
      break;      
    case 0xB1C9F528:  // button #4
      // toggle first LED
      Serial.println("4 button");
      toggleLed(3);
      break;
    case 0x5C12F8FF:  // button #5
      // toggle second LED
     Serial.println("5 button");
     toggleLed(4);
      break;
    case 0x1305A3CE:  // button #6
      // toggle third LED
      Serial.println("6 button");
      toggleLed(5);
      break;  
    case 0xC860610F:  // button #7
      // toggle first LED
      Serial.println("7 button");
      toggleLed(6);
      break;
    case 0xDD495E6C:  // button #8
      // toggle second LED
     Serial.println("8 button");
     toggleLed(7);
      break;
    case 0x9CD0273:  // button #9
      // toggle third LED
      Serial.println("9 button");
      toggleLed(8);
      break;        
      case 0x68733A46:  // button TV Vol Up
      // brighten third LED
      brightenLed(2);
      break;     
    case 0x83B19366:  // button TV Vol Down
      // bridimghten third LED
      dimLed(2);
      break;   
    default:
      Serial.print("Non supported function: 0x");
      Serial.println(code, HEX);
      break;
  }
}

/*
  decrement brightness of LED identified by ldNumber
*/
void dimLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if minimum value not reaached
    if (leds[ledNumber].value > 0)
    {
      // decrement brightness
      leds[ledNumber].value--;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  increment brightness of LED identified by ldNumber
*/
void brightenLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if maximum value not reaached
    if (leds[ledNumber].value < 255)
    {
      // increment brightness
      leds[ledNumber].value++;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  toggle a single LED idientified by ledNumber

  ledNumber: index for LED to toggle
*/
void toggleLed(byte ledNumber)
{
  // if the current value is not zero
  if (leds[ledNumber].value != 0)
  {
    // indicate OFF
    leds[ledNumber].value = 0;
  }
  else
  {
    // indicate  ON
    leds[ledNumber].value = 255;
  }

  // apply the new value
  // for toggling, we simply write LOW or HIGH
  digitalWrite(leds[ledNumber].pin, leds[ledNumber].value == 0 ? LOW : HIGH);
}

/*
  toggle a single LED idientified by ledNumber
  ledNumber: index for LED to toggle
*/
void toggleLed(int ledNumber)
{
  // set the new state of the LED
  leds[ledNumber].value = !leds[ledNumber].value;
  // apply the new state
  digitalWrite(leds[ledNumber].pin, leds[ledNumber].value);
}

/*
  toggle all LEDs
*/
void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      // toggle led i
      toggleLed(i);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

unsigned long irSignals() {//unsinged long to hold the 32-bit ;)
  IRdecode My_Decoder;
  if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
    IRdecodeHash My_Hash_Decoder;    //decoders are only needed here
  
    My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
    My_Decoder.decode();
    Serial.print("real decode type:");
    Serial.print(Pnames(My_Decoder.decode_type));
    Serial.print(" value: 0x");
    Serial.println(My_Decoder.value, HEX);
    My_Hash_Decoder.decode();
    Serial.print("Hash decode: 0x");
    Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
    My_Receiver.resume(); // Turn on the IR receiver for more singnals
    return My_Hash_Decoder.hash; //Yes, new hash is:
    //WE exit NOW so next return is only executed when the if is not executed
  }
  return 0; //No new IR
}

Question, how does it turn off after 2 seconds if the function which does so is only called once when a button is pressed, it is not called again until you press a button to check if it has been 2 seconds?

As for the fast toggling, check if irSignal function is returning the same code many times per second instead of just once when you press the button.

So I guess this means I need to put the delay in the main loop?

I've tried inserting the delay into the main loop but it still doesn't work.

#include <IRLib.h>

const byte RECV_PIN = A4; //byte big enough

byte LedPins[] = {4, 5, 6, 7, 8, 9, 10, 11, 12}; //byte is big enough
bool ledsState = LOW; //bool is big enough

byte LedValues[sizeof(LedPins)];

// a struct to hold information about a led
struct LED
{
  byte pin;
  byte value;
  bool canDim;  // indicate if LED can be dimmed or not
};

    static unsigned long starttime = 0;  // variable to remember start time of delay


// an array of 3 LED structs
LED leds[] = {
  {5, 128, true},   // pin 5, start value half dimmed, can be dimmed
  {6, 128, true},   // pin 6, start value half dimmed, can be dimmed
  {9, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {10, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {11, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {4, 255, false},  // pin 4, start value ON (255)
  {7, 0, false},   // pin 7, start value OFF (0)
  {8, 0, false},   // pin 8, start value OFF (0)
  {12, 0, false},   // pin 13, start value OFF (0)
};

IRrecv My_Receiver(RECV_PIN);

void setup()
{
  //Make all LedPins output
  for (byte i = 0; i < sizeof(LedPins); i++) { //LedPins is a byte so no need to devide the size
    pinMode(LedPins[i], OUTPUT);
  }
  for(int cnt=0;cnt<3;cnt++)
  {
    pinMode(leds[cnt].pin, OUTPUT);
    digitalWrite(leds[cnt].pin, leds[cnt].value);
  }
  My_Receiver.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  Serial.print("Ready!");
}

void loop()
{
  unsigned long code = irSignals();

  switch (code)
  {
    case 0:           // no new IR code
      break;
    case 0x95EB7802:  // button #0
      // toggle all LEDs
      Serial.println("0 button");
      toggleLeds();
      break;
    case 0x153350A5:  // button #1
      // toggle first LED
      Serial.println("1 button");
      toggleLed(0);
      break;
    case 0x37D56044:  // button #2
      // toggle second LED
     Serial.println("2 button");
     toggleLed(1);
      break;
    case 0xF3DFCA53:  // button #3
      // toggle third LED
      Serial.println("3 button");
      toggleLed(2);
      break;      
    case 0xB1C9F528:  // button #4
      // toggle first LED
      Serial.println("4 button");
      toggleLed(3);
      break;
    case 0x5C12F8FF:  // button #5
      // toggle second LED
     Serial.println("5 button");
     toggleLed(4);
      break;
    case 0x1305A3CE:  // button #6
      // toggle third LED
      Serial.println("6 button");
      toggleLed(5);
      break;  
    case 0xC860610F:  // button #7
      // toggle first LED
      Serial.println("7 button");
      toggleLed(6);
      break;
    case 0xDD495E6C:  // button #8
      // toggle second LED
     Serial.println("8 button");
     toggleLed(7);
      break;
    case 0x9CD0273:  // button #9
      // toggle third LED
      Serial.println("9 button");
      toggleLed(8);
      break;        
      case 0x68733A46:  // button TV Vol Up
      // brighten third LED
      brightenLed(2);
      break;     
    case 0x83B19366:  // button TV Vol Down
      // bridimghten third LED
      dimLed(2);
      break;   
    default:
      Serial.print("Non supported function: 0x");
      Serial.println(code, HEX);
      break;

  }
    starttime = millis();    // set the start time

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
  
}

/*
  decrement brightness of LED identified by ldNumber
*/
void dimLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if minimum value not reaached
    if (leds[ledNumber].value > 0)
    {
      // decrement brightness
      leds[ledNumber].value--;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  increment brightness of LED identified by ldNumber
*/
void brightenLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if maximum value not reaached
    if (leds[ledNumber].value < 255)
    {
      // increment brightness
      leds[ledNumber].value++;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  toggle a single LED idientified by ledNumber

  ledNumber: index for LED to toggle
*/
void toggleLed(byte ledNumber)
{
  // if the current value is not zero
  if (leds[ledNumber].value != 0)
  {
    // indicate OFF
    leds[ledNumber].value = 0;
  }
  else
  {
    // indicate  ON
    leds[ledNumber].value = 255;
  }

  // apply the new value
  // for toggling, we simply write LOW or HIGH
  digitalWrite(leds[ledNumber].pin, leds[ledNumber].value == 0 ? LOW : HIGH);
}

/*
  toggle a single LED idientified by ledNumber
  ledNumber: index for LED to toggle
*/
void toggleLed(int ledNumber)
{
  // set the new state of the LED
  leds[ledNumber].value = !leds[ledNumber].value;
  // apply the new state
  digitalWrite(leds[ledNumber].pin, leds[ledNumber].value);
}

/*
  toggle all LEDs
*/
void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      // toggle led i
      toggleLed(i);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

unsigned long irSignals() {//unsinged long to hold the 32-bit ;)
  IRdecode My_Decoder;
  if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
    IRdecodeHash My_Hash_Decoder;    //decoders are only needed here
  
    My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
    My_Decoder.decode();
    Serial.print("real decode type:");
    Serial.print(Pnames(My_Decoder.decode_type));
    Serial.print(" value: 0x");
    Serial.println(My_Decoder.value, HEX);
    My_Hash_Decoder.decode();
    Serial.print("Hash decode: 0x");
    Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
    My_Receiver.resume(); // Turn on the IR receiver for more singnals
    return My_Hash_Decoder.hash; //Yes, new hash is:
    //WE exit NOW so next return is only executed when the if is not executed

  }
  return 0; //No new IR


}

richiep:
So I guess this means I need to put the delay in the main loop?

Generally, no. It's very common and safe to implement millis() based timed events inside a function.

I've looked at your function and I believe it should work. I would have used a flag instead of making the timestamp multipurpose, but that is just me.

Perhaps the mills() should be in the irSignals function? I've tried inserting it there but it doesn't seem to work.

richiep:
Perhaps the mills() should be in the irSignals function? I've tried inserting it there but it doesn't seem to work.

No. It's where it should be. You have some other problem. Try running the function in a simplified sketch without all the other stuff in it, to isolate the issue. I think you will find that it works.

Have you looked at toggleLed()? What does your serial debug look like when you press IR key 0?

Actually, it appears that you are trying to prohibit a toggle for two seconds after each request. Why? If you make no such request, it should still toggle. So it should work without any delay.

starttime = millis();    // set the start time

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }

starttime is being updated every iteration of loop...put it inside the if statement
You are basically checking if millis() - millis() > 2000...it wont be...

I played around and tried to put this in the if statement

static unsigned long starttime = 0; // variable to remember start time of delay

it didn't work...

How can I get this sketch to delay?

Thanks
Rich

First off...it shouldn't even compile...
Look, you are declaring starttime AFTER you use it in the if statement...

if (millis() - starttime > 2000) // if delay lapsed
  {
    static unsigned long starttime = 0;  // variable to remember start time of delay
  }

However, what I said to do was "starttime is being updated every iteration of loop...put it inside the if statement".

SOLVED

I needed to have timers in the other functions, not just toggleLeds() Here is the working code.

#include <IRLib.h>

const byte RECV_PIN = A4; //byte big enough

byte LedPins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; //byte is big enough
bool ledsState = LOW; //bool is big enough

byte LedValues[sizeof(LedPins)];

// a struct to hold information about a led
struct LED
{
  byte pin;
  byte value;
  bool canDim;  // indicate if LED can be dimmed or not
};

static unsigned long starttime = 0;  // variable to remember start time of delay


// an array of 3 LED structs
LED leds[] = {
  {3, 55, true},  // pin 3, start value ON (255)
  {5, 128, true},   // pin 5, start value half dimmed, can be dimmed
  {6, 128, true},   // pin 6, start value half dimmed, can be dimmed
  {9, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {10, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {11, 128, true},   // pin 9, start value half dimmed, can be dimmed
  {4, 255, false},  // pin 4, start value ON (255)
  {7, 0, false},   // pin 7, start value OFF (0)
  {8, 0, false},   // pin 8, start value OFF (0)
  {12, 0, false},   // pin 13, start value OFF (0)
};

IRrecv My_Receiver(RECV_PIN);

void setup()
{
  //Make all LedPins output
  for (byte i = 0; i < sizeof(LedPins); i++) { //LedPins is a byte so no need to devide the size
    pinMode(LedPins[i], OUTPUT);
  }
  for (int cnt = 0; cnt < 3; cnt++)
  {
    pinMode(leds[cnt].pin, OUTPUT);
    digitalWrite(leds[cnt].pin, leds[cnt].value);
  }
  My_Receiver.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  Serial.print("Ready!");
}

void loop()
{
  unsigned long code = irSignals();

  switch (code)
  {
    case 0:           // no new IR code
      break;
    case 0x95EB7802:  // button #0
      // toggle all LEDs
      Serial.println("0 button");
      toggleLeds();
      break;
    case 0x153350A5:  // button #1
      // toggle first LED
      Serial.println("1 button");
      toggleLed(0);
      break;
    case 0x37D56044:  // button #2
      // toggle second LED
      Serial.println("2 button");
      toggleLed(1);
      break;
    case 0xF3DFCA53:  // button #3
      // toggle third LED
      Serial.println("3 button");
      toggleLed(2);
      break;
    case 0xB1C9F528:  // button #4
      // toggle first LED
      Serial.println("4 button");
      toggleLed(3);
      break;
    case 0x5C12F8FF:  // button #5
      // toggle second LED
      Serial.println("5 button");
      toggleLed(4);
      break;
    case 0x1305A3CE:  // button #6
      // toggle third LED
      Serial.println("6 button");
      toggleLed(5);
      break;
    case 0xC860610F:  // button #7
      // toggle first LED
      Serial.println("7 button");
      toggleLed(6);
      break;
    case 0xDD495E6C:  // button #8
      // toggle second LED
      Serial.println("8 button");
      toggleLed(7);
      break;
    case 0x9CD0273:  // button #9
      // toggle third LED
      Serial.println("9 button");
      toggleLed(8);
      break;
    case 0x68733A46:  // button TV Vol Up
      // brighten third LED
      brightenLed(2);
      break;
    case 0x83B19366:  // button TV Vol Down
      // dim third LED
      dimLed(2);
      break;
    default:
      Serial.print("Non supported function: 0x");
      Serial.println(code, HEX);
      break;

  }
  starttime = millis();    // set the start time

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }

}

/*
  decrement brightness of LED identified by ldNumber
*/
void dimLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if minimum value not reaached
    if (leds[ledNumber].value > 0)
    {
      // decrement brightness
      leds[ledNumber].value--;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  increment brightness of LED identified by ldNumber
*/
void brightenLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if maximum value not reaached
    if (leds[ledNumber].value < 255)
    {
      // increment brightness
      leds[ledNumber].value++;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  toggle a single LED idientified by ledNumber

  ledNumber: index for LED to toggle
*/
void toggleLed(byte ledNumber)
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // if the current value is not zero
    if (leds[ledNumber].value != 0)
    {
      // indicate OFF
      leds[ledNumber].value = 0;
    }
    else
    {
      // indicate  ON
      leds[ledNumber].value = 255;
    }

    // apply the new value
    // for toggling, we simply write LOW or HIGH
    digitalWrite(leds[ledNumber].pin, leds[ledNumber].value == 0 ? LOW : HIGH);
    if (millis() - starttime > 300) // if delay lapsed
    {
      starttime = 0;    // reset start time so next call will toggle the leds (again)
    }
  }
}

  /*
    toggle a single LED idientified by ledNumber
    ledNumber: index for LED to toggle
  */
  void toggleLed(int ledNumber)
  {
    static unsigned long starttime = 0;  // variable to remember start time of delay

    if (starttime == 0)  // if delay not started
    {
      // set the new state of the LED
      leds[ledNumber].value = !leds[ledNumber].value;
      // apply the new state
      digitalWrite(leds[ledNumber].pin, leds[ledNumber].value);
      starttime = millis();    // set the start time
    }
    if (millis() - starttime > 300) // if delay lapsed
    {
      starttime = 0;    // reset start time so next call will toggle the leds (again)
    }
  }

  /*
    toggle all LEDs
  */
  void toggleLeds()
  {
    static unsigned long starttime = 0;  // variable to remember start time of delay

    if (starttime == 0)  // if delay not started
    {
      // toggle all LEDs
      ledsState = !ledsState; //toggle state
      for (byte i = 0; i < sizeof(LedPins); i++)
      {
        // toggle led i
        toggleLed(i);
        Serial.println("Proof positive, the function is being called!");
      }
      starttime = millis();    // set the start time
    }

    if (millis() - starttime > 300) // if delay lapsed
    {
      starttime = 0;    // reset start time so next call will toggle the leds (again)
    }
  }

  unsigned long irSignals() {//unsinged long to hold the 32-bit ;)
    IRdecode My_Decoder;
    if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
      IRdecodeHash My_Hash_Decoder;    //decoders are only needed here

      My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
      My_Decoder.decode();
      Serial.print("real decode type:");
      Serial.print(Pnames(My_Decoder.decode_type));
      Serial.print(" value: 0x");
      Serial.println(My_Decoder.value, HEX);
      My_Hash_Decoder.decode();
      Serial.print("Hash decode: 0x");
      Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
      My_Receiver.resume(); // Turn on the IR receiver for more singnals
      return My_Hash_Decoder.hash; //Yes, new hash is:
      //WE exit NOW so next return is only executed when the if is not executed

    }
    return 0; //No new IR


  }

I'm done...I said it 2x