Timing Problem with Functions?

Hi,
I am using the Arduino Uno and expect a strange timing? problem.
First i wrote my code without functions and all was working fine. Now I've put some code into functions because i want to use more than one LED. But now my LED isn't blinking equally anymore when i am using the funtions below. It looks like a CPU overload or someting else. The LED is blinking 4-6 times correctly and than it "hangs" for a short time and blinks sometimes correctly again.

Are there any problems with my functions?

Sorry for my bad english...

Currently I am using the following sketch :

//IR Stuff
#include <IRremote.h> // Laden der Infrarot Library
const long ir_key1 = 16724175; // IR Code Taste 1
const int ir_pin = 12;
IRrecv ir_recv(ir_pin);
decode_results ir_results;

//LED1 Stuff
const int led1_pin = 9; // Rote LED
const int led1_intervall = 100;
int led1_onoff = LOW;
int led1_status = LOW;
unsigned long led1_time;

void setup() {
  // IR Stuff
  Serial.begin(9600);
  ir_recv.enableIRIn(); // Start the IR Receiver
  
  // LED Stuff
  pinMode(led1_pin, OUTPUT);
  led1_time = millis(); // Aktuelle Zeit in Variable speichern
}

void loop() {
  //Abfrage Tastendruck Fernbedienung
  if(ir_recv.decode(&ir_results)){
    //Serial.println(ir_results.value, DEC);
    switch(ir_results.value){
      case ir_key1:
      led1_onoff = !led1_onoff; break;
    }
    ir_recv.resume();
  }
  
  led1_status = blinkfunc(led1_pin,led1_time,led1_onoff,led1_status,led1_intervall);
  led1_time = resettimefunc(led1_time,led1_intervall);  
}
 
//LED Blink Funktion
int blinkfunc(int local_pin, unsigned long local_time, int local_onoff, int local_status, int local_intervall){
  if(local_onoff==HIGH){
    if((millis() - local_time) >= local_intervall){
      local_status = !local_status;
      digitalWrite(local_pin, local_status); // LED ein/ausschalten
    }
  }
  else{
    local_status = LOW;
    digitalWrite(local_pin, local_status); // LED ausschalten
  }
  return local_status;
}

//LED Zeitschleife zuruecksetzen wenn ueberschritten
unsigned long resettimefunc(unsigned long local_time, int local_intervall){
  if((millis() - local_time) >= local_intervall){
    local_time = millis();
  }
  return local_time;
}

Any ideas welcome.

Thank you,
Mag

That is a pretty good example of splitting small elements down into functions. I can't see anything wrong with your code style, other than putting break; on the same line as an active piece of code. Break belongs on its own line.

I think you've taken the approach a little too far. The second function does almost nothing that the main function doesn't do. You've found the obvious problem that a function can only return one thing but you need to update two variables: the LED status and the timer for that LED. But you're working with a microcontroller, so there's a few shortcuts available to you. The first is to know that you can read an output pin to find out what the current output is. So if you need to change an LED from on to off or off to on, you can:

digitalWrite(local_pin, !digitalRead(local_pin));

So in this way, you don't need to pass the value of led1_status and the main program can still find out if the LED is on or off by reading it for itself.

So why does it "hang"? Well, you're checking the timer in two different places. There will be a time difference between those two places. The technical term for this is "race condition." It depends on exactly when the timer clicks over, if it occurs in between those two checks. Try to write it so that it only checks in one place.

While not related to your issue, I don't like this:

int blinkfunc(int local_pin, unsigned long local_time, int local_onoff, int local_status, int local_intervall){

There is no reason not to use multiple lines for this statement:

int blinkfunc(int local_pin,
              unsigned long local_time,
              int local_onoff,
              int local_status,
              int local_intervall)
{

Doing so prevents the need to scroll code sideways as well as up and down.

How many pins do you have? If it is a standard Arduino, with less then 32,767 pins, a byte is more appropriate to help the pin number. How many states will the pin have? Again, if less then 32,767, use a byte.

Finally, onoff is a dumb name. The pin is on OR off, not both. That value probably should be a boolean. on would then be true. If the value is not true, then the pin is not on.

MorganS:
That is a pretty good example of splitting small elements down into functions.

From what I understand, this should be a compliment, so thank you! I really need some ;o)

MorganS:
I think you've taken the approach a little too far. The second function does almost nothing that the main function doesn't do. You've found the obvious problem that a function can only return one thing but you need to update two variables: the LED status and the timer for that LED. But you're working with a microcontroller, so there's a few shortcuts available to you. The first is to know that you can read an output pin to find out what the current output is. So if you need to change an LED from on to off or off to on, you can:

digitalWrite(local_pin, !digitalRead(local_pin));

So in this way, you don't need to pass the value of led1_status and the main program can still find out if the LED is on or off by reading it for itself.

You read my mind like a book. ;o)
Really great help! With that tip I could go without my status Variable at all, and I only need one Function!

MorganS:
So why does it "hang"? Well, you're checking the timer in two different places. There will be a time difference between those two places. The technical term for this is "race condition." It depends on exactly when the timer clicks over, if it occurs in between those two checks. Try to write it so that it only checks in one place.

Yeah I thought that should be the problem in some case, but don't know how to handle this.
Thanks for your help!

PaulS:
While not related to your issue, I don't like this:

There is no reason not to use multiple lines for this statement:

prevents the need to scroll code sideways as well as up and down.

How many pins do you have? If it is a standard Arduino, with less then 32,767 pins, a byte is more appropriate to help the pin number. How many states will the pin have? Again, if less then 32,767, use a byte.

Finally, onoff is a dumb name. The pin is on OR off, not both. That value probably should be a boolean. on would then be true. If the value is not true, then the pin is not on.

Fine suggestions! Thank you. I've changed my code as you suggest. The Naming of Variables is a Philosophie Thing I think, but hey you're not wrong. So I take it ;o)

Thanks for your help so far!
Great forum!

My actual Sketch works fine:

//IR Stuff
#include <IRremote.h> //Load Infrarot Library
const long ir_key1 = 16724175; //IR Code Key 1
const long ir_key2 = 16718055; //IR Code Key 2
const long ir_key3 = 16743045; //IR Code Key 3
const int ir_pin = 12;
IRrecv ir_recv(ir_pin);
decode_results ir_results;

//LED1 Stuff
const int led1_pin = 9; //Red LED
const int led1_intervall = 100; //Blink Intervall
boolean led1_blink = LOW; //Blink on/off
unsigned long led1_time;

//LED2 Stuff
const int led2_pin = 10; //Green LED
const int led2_intervall = 500; //Blink Intervall
boolean led2_blink = LOW; //Blink on/off
unsigned long led2_time;

//HALO Stuff
const int halo_pin = 11; //White LED
const int halo_intervall = 1000; //Blink Intervall
boolean halo_blink = LOW; //Blink on/off
unsigned long halo_time;

void setup() {
  // IR Stuff
  Serial.begin(9600);
  ir_recv.enableIRIn(); // Start the IR Receiver
  
  // LED Stuff
  pinMode(led1_pin, OUTPUT);
  pinMode(led2_pin, OUTPUT);
  pinMode(halo_pin, OUTPUT);
  led1_time = millis(); //Safe actual Time in Var
  led2_time = millis(); //Safe actual Time in Var  
  halo_time = millis(); //Safe actual Time in Var
}

void loop() {
  //Check IR Controller for pressed Keys
  if(ir_recv.decode(&ir_results)){
    //Serial.println(ir_results.value, DEC);
    switch(ir_results.value){
      case ir_key1:
      led1_blink = !led1_blink; //Toggle LED Blink on/off
      break;
      case ir_key2:
      led2_blink = !led2_blink; //Toggle LED Blink on/off
      break;
      case ir_key3:
      halo_blink = !halo_blink; //Toggle LED Blink on/off
      break; 
    }
    ir_recv.resume(); //Check for next pressed Key
  }
  //Toggle Red LED Status if Blink is on and Blink Intervall is exceeded
  led1_time = blinkfunc(led1_pin, led1_time, led1_blink, led1_intervall);
  //Toggle Green LED Status if Blink is on and Blink Intervall is exceeded
  led2_time = blinkfunc(led2_pin, led2_time, led2_blink, led2_intervall);
  //Toggle White LED Status if Blink is on and Blink Intervall is exceeded
  halo_time = blinkfunc(halo_pin, halo_time, halo_blink, halo_intervall);
}
 
//LED Blink Function
unsigned long blinkfunc(int local_pin, 
                        unsigned long local_time, 
                        int local_blink, 
                        int local_intervall)
  {                        
  if(local_blink==HIGH){ //Check if Keypad was pressed for on/off
    if((millis() - local_time) >= local_intervall){ //Check if Intervall is exceeded
      local_time = millis(); //If LED Intervall is exceeded start new one.
      digitalWrite(local_pin, !digitalRead(local_pin)); //Toggle LED Status
    }
  }
  else{
    digitalWrite(local_pin, LOW); //Set LED to off
  }
  return local_time; //Return new Timer for checking next turn
}

Bye,
Mag

  {                        
  if(local_blink==HIGH){ //Check if Keypad was pressed for on/off
    if((millis() - local_time) >= local_intervall){ //Check if Intervall is exceeded

Now, if you could be consistent in your curly brace placement (always on a new line) and in your use of while space (" == ", not "==")... 8)

Magroll:
Any ideas welcome.

If you have problems with your "LED Blink Funktion" and the "LED Zeitschleife zuruecksetzen wenn ueberschritten", you could use the "Deutsch" forum section to ask questions in German language:
Arduino Forum Deutsch

I think you meant:

PaulS:
How many pins do you have? If it is a standard Arduino, with less then 32,767 256 pins, a byte is more appropriate to help the pin number. How many states will the pin have? Again, if less then 32,767 256, use a byte.

Not that this changes your advice in this situation (I don't see the ATgargantua9000 with 9001 pins for sale anywhere :wink: )