CUSTOM FUNCTIONS

This page is part of my Model Remodel series of articles and a subset of my Arduino section.

DISCLAIMER: If you choose to attempt any of these modifications, you assume all risks thereof. I just wanted to share my experiences here. Neither Fanhome, nor myself, are responsible for any damages that may occur.


Custom Functions

Why should we use Custom Functions?

As we add more and more code to an Arduino sketch, we will invariably run into situations where we use the same sections of code over and over again with only minor changes. These situations can be a perfect reason to utilize Custom Functions. These functions can not only shorten your sketch and save memory space, but they can also make managing your sketch easier.

If we look at the sketch we have been writing so far, we will find we have some repetitive code in there. As I highlighted below, the only difference between these two sections of code is the LEDPin and LED2Pin variables:

...
void loop() {
  // Check to see if an IR code is received
  if (IrReceiver.decode()) {
    // Check to see if the buttonDelay interval has passed
    if (millis() >= (lastPressed + buttonDelay)) {
      // Reset lastPressed time
      lastPressed = millis();
      // Check the received IR code
      switch (IrReceiver.decodedIRData.command) {
        // If the received IR Command= value is for Button 1
        case 0xC:
          //Change LED 1 State
          if (digitalRead(LEDPin)) {
            digitalWrite(LEDPin, LOW);
          } else {
            digitalWrite(LEDPin, HIGH);
          }
        break; 
        // If the received IR Command= value is for Button 2
        case 0x18:
          //Change LED 2 State
          if (digitalRead(LED2Pin)) {
            digitalWrite(LED2Pin, LOW);
          } else {
            digitalWrite(LED2Pin, HIGH);
          }
        break;
      }
    }
    // Resume receiving IR signals
    IrReceiver.resume();
  }
}

We can replace these two sections of code by calling a Custom Function. Functions are self-contained chunks of code that can be called (executed) by other code. The nice thing about these functions is that we can send them data, and if necessary, get data back. The format of a Custom Function is simple:

void functionName (parameters) {
  // Some code you want to run
}

The ‘void’ modifier means that this function will not return any values – it will just execute the code between the { and the }. While the ( and ) after the function name are required, the optional ‘parameters’ fields inside them are used to capture data sent to this function and declares them as local variables for use inside this function. Unlike the global variables we have been using up to this point that can be used anywhere in the sketch, once this function code completes these local variables are deleted.

Creating a Custom Function

If we wanted to use a Custom Function to replace the ‘LED state change’ code I highlighted above, we could create something like this. I named my function changeLEDState, but you could name it whatever you want:

void changeLEDState (byte Pin) {
  if (digitalRead(Pin)) {
    digitalWrite(Pin, LOW);
  } else {
    digitalWrite(Pin, HIGH);
  }
}

Here, I declared a byte local variable named Pin within the parameters field. When we call this function from our main code, we will send it the byte value of the LEDPin or LED2Pin global variable. Within this function, we can then use that value as the Pin local variable.

Calling a Custom Function

We can then replace the previous code inside the loop() function by calling this new function, as shown.

NOTE: Custom Functions like this one need to be placed outside the setup() and loop() functions, typically at the bottom of your sketch.

...
void loop() {
  // Check to see if an IR code is received
  if (IrReceiver.decode()) {
    // Check to see if the buttonDelay interval has passed
    if (millis() >= (lastPressed + buttonDelay)) {
      // Reset lastPressed time
      lastPressed = millis();
      // Check the received IR code
      switch (IrReceiver.decodedIRData.command) {
        // If the received IR Command= value is for Button 1
        case 0xC:
          //Change LED 1 State
          changeLEDState(LEDPin); 
        break; 
        // If the received IR Command= value is for Button 2
        case 0x18:
          //Change LED 2 State
          changeLEDState(LED2Pin);
        break;
      }
    }
    // Resume receiving IR signals
    IrReceiver.resume();
  }
}
// Custom Function to change LED state by pin number
void changeLEDState (byte Pin) {
  if (digitalRead(Pin)) {
    digitalWrite(Pin, LOW);
  } else {
    digitalWrite(Pin, HIGH);
  }
}

This is the beauty of functions. We could call this new changeLEDState function from many different places in our sketch and only need one line of code each time (instead of five). Just imagine if we had ten different LEDs to control with our previous code, without this function that would be 50 lines of code! There would be a heck of a lot of copy/pasting and tons of repetitive code which is just wasting memory space. This is what makes using Custom Functions a great solution to keep in mind.

Download my Sketch

To help others, I have shared this sketch via the Arduino Editor. Simply click the Open Code or Download buttons!

Returning a Value with a Function

I do want to explain what we should do if we wanted a Custom Function that did something and returned a value when finished. For example, let’s say we wanted to send two numbers to a Custom Function, have it add them together, and give the sum back to us. For this, we cannot use the ‘void’ modifier as need to declare what variable type of data the new function will return.

Here, I expect the returned data to be an integer so I changed the modifier from ‘void’ to int. I also plan to send integer values to this function, so I declared two integer local variables x and y inside the parameter field.

NOTE: Multiple parameters need to be separated by a comma:

int myDoublingFunction (int x, int y) {
  int result;
  result = x + y;
  return result;
}

Inside this function, I declared a local variable result to hold the sum of the two numbers, then assigned it to hold the sum of x + y. The return command is required for any functions that return data. In this case, I want it to return the value of the local variable result.

To use a ‘returning’ function like this in our main code, we have to assign the returned value to some global variable. For example, we could call this function like this:

void (){ 
  int sum = myDoublingFunction(2,3); // This function returns 5
}

This code would call our myDoublingFunction and send it the values of 2 and 3. The function itself would then assign these values to its local variables x and y, add them together, and return the value of x + y which is 5. This value of 5 would be assigned to the sum variable for use elsewhere in the code as needed.

While using Custom Functions is entirely optional in Arduino sketches, there will be situations where they are very helpful. For the most part, I create them anytime I find myself using the same chunks of code three or more times.

Next Arduino Page


BOOLEAN STATES – Tracking the states of the operations inside our Enterprise sketch