More qusetions about "functions" and how they work.

It isn't that I really want a lot of posts but the "Theme" has changed and so a new post.

I have been "caught out" with either sending multiple variables to a function or trying to return multiple variables.
This has only recently happened where errors have happened and I am sure my older alarm clock sketch was "guilty" of doing that.
But as it works, I don't want to tempt fate.

Ok the dilemma:
I am reading a C++ for dummies book and it talks of "OOP" - Object Oriented Programming.
I think I have a grasp of that but when I try to apply it, things fall over.

Example:
On my NEOPIXEL clock - sketch in another thread in the showroom - The Hours are Red, the Minutes are Green and the seconds are Blue.

When two of the hands are at the same position, there is a "problem".

I want to write some code to AND the two colours together and display that colour for that position.

This would be with a "function" - I am guessing.
But to do that: The function would need BOTH colours to OR together.

Then, after the second hand has "moved on", it needs to restore the original colour to the LED one behind.
Again it would need BOTH colours to AND together to return the original colour.

I don't understand enough of the lingo' to be able to write something to do that.

Other than making the variables GLOBAL.

Please........

Anyone?

lost_and_confused:
... or trying to return multiple variables.

whilst you can send multiple variables, you may only return one...

int myFunction(int myInt, byte myByte, unsigned long, myTime, etc...);

but you can update global variables that your loop() or other functions may access...

Thanks.

I just upgraded to the new IDE (windoze) and it was giving me grief.

I thought part of that was to do with either multiple sends or returns to functions.

Anyway, I'll try to get more work done this weekend on learning more.

:slight_smile:

Look into class Adafruit_NeoPixel and its definition of method / function "Color".
The color is specified as 3 bytes of RGB values passed to the method.
To get a "composite" color you can set Color(255,255,0).
The RGB values can be anything between 0 and 255.
That is your OR function as you call it .
And these RGB values can be passed as variable bytes.

For example this is how the example code sets red color only

colorWipe(strip.Color(255, 0, 0), 20); // Red

you can assign
byte bRed = 125;

and write
colorWipe(strip.Color(bRed, 0, 0), 20); // shade of Red

Have fun coming up with rainbow of colors.

PS Function can modify multiple variables using struct(ure) type of variable.

Valcav,

Nearly.

I'll try to explain better now.

Forgetting that there are 60 LEDs......

An LED is set to RED (and that is to keep it easy for me too). When the Second hand moves onto that LED, I want a composite of the two colours.

So: Seconds are BLUE.

The RGB would be:
55,00,00

The other value is:
00,00,55

I "OR" those together and get:
55,00,55

Then when the second hand moves off that LED, I need to restore it to the original colour.
So I would AND the LED.
55,00,55 AND 55,00,00
Gives: 55,00,00.

But doing that in a NEAT way - as a function - is still a bit beyond me.

I think you are making more complicated that it is.
To set LED to red you code sends RGB = (255,0,0) , to set blue you send RGB (0,0,255).
Now if you set SAME LED using BOTH codes it will PHYSICALLY mix the colors.
The software does not care if you send TWO lines of code to sane LED "output"
Color(255,0,0);
Color(0,0,255);
or ONE line of code
Color(255,0,255); to same LED

PS Function can modify multiple variables using struct(ure) type of variable.

You can also pass an array into a function and alter their values. The power of C and C++, however, is the ability to use pointers when you need the function to change several values and give them back to you. The Bucket Analogy makes it easy to understand pointers. I'm going to take a few liberties along the way, but hopefully you'll see what a pointer is when we're done.

Defining a variable like:

int val;

creates a bucket named val and places that bucket somewhere in memory (usually SRAM). Let's say it ends up at memory address 1000. That memory address is often referred to as the lvalue of val. That is, the lvalue of a variable is where that variable "lives" in memory. Because val is an int, the size of the bucket is such that it can hold 2 bytes of information. When you look inside the bucket, you can see whatever numeric value has been assigned to val. This value is called the rvalue of val. Depending upon the point in the program where val is defined, it probably contains an rvalue that is some random bit pattern that just happened to exist at its lvalue (memory addresses 1000 and 1001).

The statement:

val = 10;

assigns the value 10 into val. Stated differently: a 2-byte binary representation of 10 is transferred to the lvalue of val. This means the rvalue of val is now 10. Now consider:

int val;
val = 10;
myFunction(val);   // This is the "function call to myFunction()"
Serial.println(val);

// Probably a bunch of lines of code here...

void myFunction(int n) {
   n = n * 10;
}

The function call to myFunction() causes code to go to val's lvalue, peek inside and see the rvalue of 10, and copy that value (i.e., the rvalue of val) into a 2-byte temporary variable stored in a chunk of memory called the stack. Let's pretend the stack is at memory address 2000. When program control gets "into" myFunction(), it sees that there is a temporary variable named n sitting on the stack at memory address 2000. Code then multiplies that 2-byte value by 10, and places it back at memory address 2000. Program control returns back to the Serial.println() method call to display the value of val and the program display the value 10. The reason is because the work done in myFuncion() was done on a copy of val, not val itself.

But what it you want the function to actually change val? Lets make three changes to our program:

myFunction(&val);   // This is the "function call to myFunction()"
Serial.println(val);

// Probably a bunch of lines of code here...

void myFunction(int *n) {
 *n = *n * 10;

Note the ampersand (&) in front of val in the function call to myFunction(). All the amperand says is: Hey! Treat me differently. Don't send a copy of my rvalue, send my lvalue instead. This means that the value 1000 is sent to the function, not 10. Because we are passing the address of where val lives in memory to myFunction(), we need to tell it that it is receiving an lvalue (i.e., memory address) rather than a copy of the rvalue of some data. That's what the asterisk tells the myFunction() code in the expression "int *n" in the function's parameter list. Most programmers say "n is a pointer to an integer value" because its a lvalue, not an rvalue.

To use the pointer in an expression like:

 *n = *n * 10;

The asterisk causes code to be generated that goes to the lvalue is was given (i.e., 1000), fetch the 2 bytes found there (it knows it needs 2 bytes because of the int type specifier for the pointer n), which means it has the value 10, and then it multiplies that ravalue by 10 to get 100. However, the *n on the left side of the assignment says to go to memory address 1000 and place the new value of 100 into the 2 byte bucket found at that memory address. Control returns back to the Serial.println() method call.

However, now when Serial.println() fetches the value of val, it is 100 because it was permanently changed via the use of pointers in the myFunction() code. The processes of using a pointer to alter data is called indirection.

Now, if you wanted to have a function "return two values" which is impossible in C, could you instead pass the lvalues of those two variables to your function and use indirection in the function to permanently change those value? Think about it.

Wow!

That was great!

Thanks very much.

That may be a missing link for me to get more out of things.

What I am thinking of doing is making an array:

Can I have 2 dimensional arrays?

Like: time[60.4]?

That way I can have the "hour" in one array, "minute" in another, and "second" in the third.
The fourth would be a composite of the other three.

Then each cycle I can cycle the time[i.4] from 0 to 59 and show all the leds.

Here's hoping that can be done.

lost_and_confused:
Can I have 2 dimensional arrays?

Like: time[60.4]?

yes but not like that... try like this:

int ledPin[2][3] = {{1, 2, 3 }, {4, 16, 17}};

watch out if they get too big!

Vaclav:
I think you are making more complicated that it is.
To set LED to red you code sends RGB = (255,0,0) , to set blue you send RGB (0,0,255).
Now if you set SAME LED using BOTH codes it will PHYSICALLY mix the colors.
The software does not care if you send TWO lines of code to sane LED "output"
Color(255,0,0);
Color(0,0,255);
or ONE line of code
Color(255,0,255); to same LED

Ok, home and a bit more time to reply.

My code does that - basically.

  /*----------------  Draw SECOND HAND on clock ----------------*/
   strip.setPixelColor(second_led,SE_Colour);
//   strip.setPixelColor(second_led,SE_Colour+THIS_LED);
//   strip.setPixelColor(second_led-1,THIS_LED);
   if (new_minute == 1)
   {
     //new_minute = 0;
//     strip.setPixelColor(minute_led-1,MN_Colour/50);
   }
  /*----------------  Draw MINUTE HAND on clock ----------------*/
   //strip.setPixelColor(minute_led,MN_Colour);
   //  MN_Fade for fading.
   strip.setPixelColor(minute_led,MN_R,MN_G,MN_B);
   strip.setPixelColor(minute_led+1, MN_R,     (MN_G * (second_led*10/6)/100)      , MN_B);
   strip.setPixelColor(minute_led-1, MN_R,     (MN_G * (100-(second_led*10/6))/100)      , MN_B);
  /*----------------  Draw HOUR HAND on clock ----------------*/
   strip.setPixelColor(hour_led,HR_R,HR_G,HR_B);
   //strip.setPixelColor((hour_led-1)%LED_Loop,HR_R/HR_Fade,HR_G,HR_B/HR_Fade);
   //strip.setPixelColor((hour_led+1)%LED_Loop,HR_R/HR_Fade,HR_G,HR_B/HR_Fade);

The minute hand is a bit tricky, but look beyond that.

But as the three "hands" are R G and B, why is it then that when the hands pass one another they OVERWRITE one another, rather than "blend" with each other?

That is why I am asking the question/s.

check my sketch:
http://forum.arduino.cc/index.php?topic=265294.0

Anyway, I shall play with the idea and learn if nothing else.

Thanks again.

I shall put more work/effort into it soon I hope.

P.S.
Just looked at that again:
The software does not care if you send TWO lines of code to sane LED "output"
Color(255,0,0);
Color(0,0,255);
or ONE line of code

No, I can't see how that would be the same.
The first line sets Red to 255, 0, 0.
But the second line:
0,0,255, would wipe out the first 255 instance. Because it sets the value to zero.

If there was a "wild card" there I could believe it.
But in retrospect, I'm not sure.

Vaclav:
I think you are making more complicated that it is.
To set LED to red you code sends RGB = (255,0,0) , to set blue you send RGB (0,0,255).
Now if you set SAME LED using BOTH codes it will PHYSICALLY mix the colors.
The software does not care if you send TWO lines of code to sane LED "output"
Color(255,0,0);
Color(0,0,255);
or ONE line of code
Color(255,0,255); to same LED

Is sending 255, 0, 0 then 0, 0, 255 really the same as sending 255, 0, 255 ?

Surely sending 255, 0, 0 then 0, 0, 255 will leave the LED blue

UKHeliBob:

Vaclav:
I think you are making more complicated that it is.
To set LED to red you code sends RGB = (255,0,0) , to set blue you send RGB (0,0,255).
Now if you set SAME LED using BOTH codes it will PHYSICALLY mix the colors.
The software does not care if you send TWO lines of code to sane LED "output"
Color(255,0,0);
Color(0,0,255);
or ONE line of code
Color(255,0,255); to same LED

Is sending 255, 0, 0 then 0, 0, 255 really the same as sending 255, 0, 255 ?

Surely sending 255, 0, 0 then 0, 0, 255 will leave the LED blue

In theory yes, in practice it depends on how fast / often the code executes. I did not elaborate on that, my apology.
Maybe that is the OP "problem" with blending the colors and the overall code flow needs to be examined.
Does the display updates continually in main loop() or just changes only when necessary?

AFAIK constantly.

Dumb question: Have you looked at the sketch?

I am now working on a new approach:
Yes, is it WAY different. WAY WAY WAY!

H_R[60]
H_G[60]
H_B[60]

M_R[60]
M_G[60]
M_B[60]

S_R[60]
G_G[60]
S_B[60]

X_R[60]
X_G[60]
X_B[60]

X is for "digits". Be it 12, 3, 6, 9 or all 12, and may be alarms.

Each loop will set the H, M, and S values for what is going on.

Then it LOGIC ORs the R's G's and B's into the neopixel( ) string thingy and then strip.show();

I am "forced" to do it that way as I am not smart enough yet to do it with the RGB composite numbers as one set of parameters.