Not Working When Trying to Return 2 values from Function

I'm new but trying to learn.

Recently, I finished an WS2821B LED string sketch and am finding that C++ doesn't return more than 1 value from a function.

I'm looking for ideas on how to get the 'RunColors' function to return 2 values. The value Dir is deeded to determine direction of the LEDs

The sketch runs great, but when you un comment line 75 and comment out the lines below it, the sketch doesn't work. No compiler errors, just doesn't work.

I did place some Serial.print statements and it looks like nether the Pos or the Dir are advanced as anticipated in the function.

Again, I want to use line 75 RunColors(redPos, redDir); to execute the function and not use the rest of the lines of code below. Yes, I'll be adding very many other colors as needed and this will save a bunch of coding.

Please help with suggestions.

#include <FastLED.h>

#define LED_TYPE WS2812B   // Type of RGB LEDs
#define DATA_PIN      8    // LED data pin on the Arduino UNO
#define COLOR_ORDER RGB    // RGB -GRB // sequence of colors in data streem vs RGB GRB
#define NUM_LEDS    144    // 144 LEDs numbered [0 - 143]
#define BRIGHTNESS  160    // brightness range is 0=off to 255= bright
#define dt          100    // Delay Time


byte redDir     = 0;

// Define the array of RGB control data for each LED 

CRGB leds[NUM_LEDS];  
int LED_length = 3; 
int redPos     = LED_length;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
randomSeed(analogRead(0));
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
}

//  Function to set runner length
void SetColors(int Pos, int a, int b, int c){
leds[max(Pos - 1, 0)] = CRGB(a, b, c);
leds[Pos] = CRGB(a, b, c); 
leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(a, b, c);
return Pos; 
}

//  Function to clear colors
void ClearColors(int Pos){ 
  leds[max(Pos - 1, 0)] = CRGB(0,0,0);
leds[Pos] = CRGB(0,0,0);
leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(0, 0, 0);
return Pos;
}

//  Function to set colors (advance down LEDs)
void RunColors(int Pos, int Dir){ 
if (Dir == 0){  // if going forward
  Pos += random(1, 6);
  if (Pos >= NUM_LEDS){
    Pos = NUM_LEDS - 1;
    Dir = 1; // go in reverse
  }
}

if (Dir == 1){  // if going reverse
  Pos -= random(1, 6);
  if (Pos <= 0){
    Pos = 0;
    Dir = 0; // go forward
  }
}
return (Pos, Dir);
}

void loop() {

  // Sets Runners Colors
SetColors(redPos,       0, 255,   0);

FastLED.show();
delay(dt);

// Clears Colors
ClearColors(redPos);

FastLED.show();

//RunColors(redPos, redDir);

if (redDir == 0){  // if going forward
  redPos += random(1, 6);
  if (redPos >= NUM_LEDS){
    redPos = NUM_LEDS - 1;
    redDir = 1; // go in reverse
  }
}

if (redDir == 1){  // if going reverse
  redPos -= random(1, 6);
  if (redPos <= 0){
    redPos = 0;
    redDir = 0; // go forward
  }
}


}

    return (Pos, Dir);

You cannot return 2 variables from a function like that and you certainly cannot return even a single variable from a function declared void, such as your RunColors(). The word void here says to the compiler that the function does not return a value

You can, however, return a struct from a function and that struct can contain multiple variables

Another way of doing it is to pass parameters to functions by reference instead of by value. This gives the function "permission" to change the value of a variable

A void function returns nothing.

If your intent is to modify the values of the arguments passed to RunColors function, investigate passing by reference.

Yes, my intent is to modify the values to be passed to the rest of the program.

Please help a guy trying to learn; How do I set up a function or what ever C++ calls it to pass more than 1 value?

Here is a simple example of passing two variables by reference



void setup()
{
    Serial.begin(115200);
}

void loop()
{
    static int x = 0;
    static int y = 0;
    addSomething(x, y);
    Serial.println(x);
    Serial.println(y);
    Serial.println();
    delay(1000);
}

void addSomething(int& number1, int& number2)
{
    number1++;
    number2 += 2;
}

Note the & in the list of arguments in the function definition. This is what tells the compiler that it is allowed to change the value of the variable without the need to return it

Add some more variables to the example and experiment with the idea to see whether it meets your needs

You need to define the return type of the function instead of using void. A function in C++ can only return a single value, such as a number, a pointer, or a structure pointer. However, there is nothing in C++ that prevents you from returning a packed number. For example, a uint16_t can represent two uint8_t values packed together.

I tried using your example and got these errors. I guess I misunderstood your suggested example.

error: 'SetColors' was not declared in this scope
error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'.
And a bunch of other errors in the compile (see below).

#include <FastLED.h>

#define LED_TYPE WS2812B   // Type of RGB LEDs
#define DATA_PIN      8    // LED data pin on the Arduino UNO
#define COLOR_ORDER RGB    // RGB -GRB // sequence of colors in data streem vs RGB GRB
#define NUM_LEDS    144    // 144 LEDs numbered [0 - 143]
#define BRIGHTNESS  160    // brightness range is 0=off to 255= bright
#define dt          100    // Delay Time


byte redDir     = 0;

// Define the array of RGB control data for each LED 

CRGB leds[NUM_LEDS];  
int LED_length = 3; 
int redPos     = LED_length;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
randomSeed(analogRead(0));
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
}



void loop() {

  // Sets Runners Colors
SetColors(redPos,       0, 255,   0);

FastLED.show();
delay(dt);

// Clears Colors
ClearColors(redPos);

FastLED.show();

RunColors(redPos, redDir);

//  Function to set runner length
void SetColors(int Pos, int a, int b, int c){
leds[max(Pos - 1, 0)] = CRGB(a, b, c);
leds[Pos] = CRGB(a, b, c); 
leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(a, b, c);
return Pos; 
}

//  Function to clear colors
void ClearColors(int Pos){ 
  leds[max(Pos - 1, 0)] = CRGB(0,0,0);
leds[Pos] = CRGB(0,0,0);
leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(0, 0, 0);
return Pos;
}

//  Function to set colors (advance down LEDs)
void RunColors(int& Pos, int& Dir){ 
if (Dir == 0){  // if going forward
  Pos += random(1, 6);
  if (Pos >= NUM_LEDS){
    Pos = NUM_LEDS - 1;
    Dir = 1; // go in reverse
  }
}

if (Dir == 1){  // if going reverse
  Pos -= random(1, 6);
  if (Pos <= 0){
    Pos = 0;
    Dir = 0; // go forward
  }
}
return (Pos, Dir);
}
/*

if (redDir == 0){  // if going forward
  redPos += random(1, 6);
  if (redPos >= NUM_LEDS){
    redPos = NUM_LEDS - 1;
    redDir = 1; // go in reverse
  }
}

if (redDir == 1){  // if going reverse
  redPos -= random(1, 6);
  if (redPos <= 0){
    redPos = 0;
    redDir = 0; // go forward
  }
}
*/

}

C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino: In function 'void loop()':
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:31:1: error: 'SetColors' was not declared in this scope
 SetColors(redPos,       0, 255,   0);
 ^~~~~~~~~
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:31:1: note: suggested alternative: 'HeatColor'
 SetColors(redPos,       0, 255,   0);
 ^~~~~~~~~
 HeatColor
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:37:1: error: 'ClearColors' was not declared in this scope
 ClearColors(redPos);
 ^~~~~~~~~~~
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:37:1: note: suggested alternative: 'HeatColor'
 ClearColors(redPos);
 ^~~~~~~~~~~
 HeatColor
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:41:1: error: 'RunColors' was not declared in this scope
 RunColors(redPos, redDir);
 ^~~~~~~~~
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:44:45: error: a function-definition is not allowed here before '{' token
 void SetColors(int Pos, int a, int b, int c){
                                             ^
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:52:26: error: a function-definition is not allowed here before '{' token
 void ClearColors(int Pos){
                          ^
C:\Users\bill\AppData\Local\Temp\.arduinoIDE-unsaved2025025-14428-zz2w38.ftg\sketch_jan25a\sketch_jan25a.ino:60:35: error: a function-definition is not allowed here before '{' token
 void RunColors(int& Pos, int& Dir){
                                   ^

exit status 1

Compilation error: 'SetColors' was not declared in this scope

Please show me an example. I have not used uint16_t or uint8_t values. Will they allow numbers up to and greater than 256?

The closing brace at the end of loop() is in the wrong place in your sketch, you have return statements on void functions and the wrong data type for redDir in the RunColors() function definition

The following corrected sketch compiles but I have no idea whether it does what you want

#include <FastLED.h>

#define LED_TYPE WS2812B  // Type of RGB LEDs
#define DATA_PIN 8        // LED data pin on the Arduino UNO
#define COLOR_ORDER RGB   // RGB -GRB // sequence of colors in data streem vs RGB GRB
#define NUM_LEDS 144      // 144 LEDs numbered [0 - 143]
#define BRIGHTNESS 160    // brightness range is 0=off to 255= bright
#define dt 100            // Delay Time

byte redDir = 0;

// Define the array of RGB control data for each LED

CRGB leds[NUM_LEDS];
int LED_length = 3;
int redPos = LED_length;

void setup()
{
    // put your setup code here, to run once:
    Serial.begin(9600);
    randomSeed(analogRead(0));
    FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
}

void loop()
{
    // Sets Runners Colors
    SetColors(redPos, 0, 255, 0);

    FastLED.show();
    delay(dt);

    // Clears Colors
    ClearColors(redPos);

    FastLED.show();

    RunColors(redPos, redDir);
}

//  Function to set runner length
void SetColors(int Pos, int a, int b, int c)
{
    leds[max(Pos - 1, 0)] = CRGB(a, b, c);
    leds[Pos] = CRGB(a, b, c);
    leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(a, b, c);
    //    return Pos;
}

//  Function to clear colors
void ClearColors(int Pos)
{
    leds[max(Pos - 1, 0)] = CRGB(0, 0, 0);
    leds[Pos] = CRGB(0, 0, 0);
    leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(0, 0, 0);
    //   return Pos;
}

//  Function to set colors (advance down LEDs)
void RunColors(int& Pos, byte& Dir)
{
    if (Dir == 0)
    {  // if going forward
        Pos += random(1, 6);
        if (Pos >= NUM_LEDS)
        {
            Pos = NUM_LEDS - 1;
            Dir = 1;  // go in reverse
        }
    }

    if (Dir == 1)
    {  // if going reverse
        Pos -= random(1, 6);
        if (Pos <= 0)
        {
            Pos = 0;
            Dir = 0;  // go forward
        }
    }
    //   return (Pos, Dir);
}

Thanks UKHeliBob!

I guess I got some wrong information and tried using int and not void because it was said void doesn't return anything. Pulse moving stuff around , I see where I got my brackets out of align despite an honest attempt to keep them right.

To answer your question, YES! it does work. Thanks for saying that I was so close (not in those words).

Thanks again.

//  Function to set runner length
int SetColors(int Pos, int a, int b, int c){
  leds[max(Pos - 1, 0)] = CRGB(a, b, c);
  leds[Pos] = CRGB(a, b, c); 
  leds[min(Pos + 1, NUM_LEDS - 1)] = CRGB(a, b, c);
  return Pos; 
}

Notice how I replaced void with int. This states the function will return an integer value. In this case, the value contained in Pos.

void is so misunderstood on this forum.

If you're going to have a bunch of colors, would it work like this

struct Color {
  static constexpr int NUM_LEDS = 50;
  int pos;
  bool forward;
  void run() {
    if (forward) {
      pos += random(1, 6);
      if (pos >= NUM_LEDS) {
        pos = NUM_LEDS - 1;
        forward = false;
      }
    } else {
      pos -= random(1, 6);
      if (pos <= 0) {
        pos = 0;
        forward = true;
      }
    }
  }
} red, blue, green, periwinkle;

void loop() {
  red.run();
  blue.run();
  Serial.println(blue.pos);
}

You could even have an array of Color.

Here is a quick example from the internet: To combine two bytes into an integer, you can use bit shifting: int result = (byte1 << 8) | byte2; This shifts the first byte to the left by 8 bits and combines it with the second byte using the bitwise OR operator.

You can combine two 16 bit int into a 32 bit int. The limit is your compiler's limit. On larger cores I hage used 64 bit int.

Please show an example of how, on the other side of the function, you pick it apart to use.

If this

int result = (byte1 << 8) | byte2;

is what is returned, you can get the original bytes

   byte oneByte = result & 0xff;
   byte theOtherByte = result >> 8;

Read about shifting >> and <<, read about bitwise logical operators & (AND) and | (OR).

Here

https://docs.arduino.cc/learn/programming/bit-math/

and here

a7

You can see the bits inside the packed bytes by printing with the BIN argument...

byte byte1 = 29, byte2 = 19;

void setup() {
  Serial.begin(115200);

  int result = (byte1 << 8) | byte2; // shift-left byte1 eight bits then OR with byte2 
  Serial.print("packed result = ");
  Serial.println(result, BIN); // <-- see the bits inside the bytes

  byte2 = result & 0xff; // truncate high byte
  byte1 = result >> 8; // shift-right high byte (low byte goes to carry and bit bucket)

  Serial.print("byte1 = ");
  Serial.print(byte1);
  Serial.print(" = ");
  Serial.println(byte1, BIN);

  Serial.print("byte2 = ");
  Serial.print(byte2);
  Serial.print(" = ");
  Serial.println(byte2, BIN);
}

void loop() {}

results

packed result = 1110100010011
byte1 = 29 = 11101
byte2 = 19 = 10011

At this point I think you should take a bit of time and read the Arduino Cookbook, everything you have asked is explained in it. It will be one of the best investments you can make in the Arduino world.

1 Like

Given that you can return a struct of uint8_t, or pass in the address of an array, or pass by reference to modify variable in the calling function directly, I can't see any upside to doing that.

Simplest solution.

Make the output variables of the function, GLOBAL.

Or have I missed something here?

Tom.... :smiley: :+1: :coffee: :australia:

I had suggested (a bit tersely, in post #12) that instead of having a function take two (or more) values, and return two (or more) values; if those values are related, they can be part of a struct or class. Then a member function can act upon those values without having to take or return anything.

If you're going to have a bunch of colors: their RGB values, position, direction, etc., would all part of the struct, with as many separate instances as you need. You could even have an array of them, with each one corresponding to an LED or whatever.

Then you can congratulate yourself for coming up with a reason to do your own object-oriented programming.