Multiple float in, out functions at once

Hello,
I am a beginner at using Arduino and I'm trying to achieve something relatively simple. I want to have three LED's phase in and out as a Sin wave. When LED 1 is at peak, LED 2 turns on and reaches its peak and then LED 3 does the same.

I have done some research and found that I could use the float, in out function as shown below:

const int Button = 2;
const int LED1 = 3;
const int LED2 = 5;
const int LED3 = 9;

int buttonState = 0;

void setup() 
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(Button, INPUT);
}

void loop() 

{
  noInterrupts();
  buttonState = digitalRead(Button);

  if(buttonState == HIGH)
  {
    float in, out;

// LED 1
    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out = sin(in) * 127.5 + 127.5;
      analogWrite(LED1,out);  
    }

// LED 2    
    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out = sin(in) * 127.5 + 127.5;
      analogWrite(LED2,out);
    }
    
// LED 3    
    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out = sin(in) * 127.5 + 127.5;
      analogWrite(LED3,out);
    }
  } 
  
  
  else
  {
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);    
  }

}

This almost works but LED 2 does not turn on until LED 1 is off. Same with LED 3. I have heard the millis function works with blinking but would it work here?
Thanks in advance!

You have written the code so that the 3 LEDs are processed sequentially rather than in parallel. You need something along the lines of

    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out1 = sin(in) * 127.5 + 127.5; // LED1
        analogWrite(LED1,out1);  
     out2 = <compute value for second LED>
       analogWrite(LED2,out2t);  
      out3 = <compute value for third LED>
      analogWrite(LED3,out3);  
    }

I will let you work out how to phase the 3 sin waves.

I have heard the millis function works with blinking but would it work here?

You appear to have misunderstood. Look at the blink without delay example, to see how millis() is used with respect to blinking, and you'll see that your question is misguided.

The ONLY thing that slows down your loops is the time it takes to calculate the sin() of the angle 12000+ times. You can't speed that up by calling millis().

Float math and even more sin() is heavy stuff for an 8-bit micro.

But why do you want sin? For our eyes linear already looks more like sin() (okay, it's log) so making it even go faster around off i9s just weird.

Because this is actually intended to be used with electromagnets and I need them to phase in and out using a sine wave. For demonstration purposes I will be using LED's though.

Rather than compute sin values it may make sense to use a spreadsheet to calculate the values for a look-up-table and store the values in an array. Then the phasing can be managed by choosing the appropriate index into the table.

...R

Robin2:
Rather than compute sin values it may make sense to use a spreadsheet to calculate the values for a look-up-table and store the values in an array. Then the phasing can be managed by choosing the appropriate index into the table.

...R

This is interesting as I already have a spreadsheet with the values I require.

That is the graph I am trying to achieve (minus a smoothing circuit).

So your saying the Arduino would be able to grab the values from this spreadsheet instead of the float function?

So your saying the Arduino would be able to grab the values from this spreadsheet instead of the float function?

No. You need to export the data from the spreadsheet and copy and paste the data into the sketch, as initial values for a const array that you store in PROGMEM.

Your curves all show tangent discontinuities. Is that intentional?

PaulS:
No. You need to export the data from the spreadsheet and copy and paste the data into the sketch, as initial values for a const array that you store in PROGMEM.

Your curves all show tangent discontinuities. Is that intentional?

Yes it is intentional as -255 is actually the lowest point (i.e. off) of the LED, not 0. I will have a look into the method you are suggesting.

Thank you very much for you help!

Yeah, I would still suggest FadeLed but to use a gamma table with a sine :slight_smile:

You can generate the values in Excel or Python or something.

For 1/4th of a sine (because that's all you need) you can use the 101 steps table:

const flvar_t SineTable[101] PROGMEM = {
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40,
44, 48, 52, 56, 60, 63, 67, 71, 75, 79,
83, 86, 90, 94, 98, 101, 105, 109, 112, 116,
119, 123, 126, 130, 133, 137, 140, 143, 147, 150,
153, 156, 159, 163, 166, 169, 172, 175, 177, 180,
183, 186, 189, 191, 194, 196, 199, 201, 204, 206,
209, 211, 213, 215, 217, 219, 222, 223, 225, 227,
229, 231, 232, 234, 236, 237, 239, 240, 241, 243,
244, 245, 246, 247, 248, 249, 250, 250, 251, 252,
252, 253, 253, 254, 254, 254, 255, 255, 255, 255};

Made with the Python script:

import math

biggestStep = 100
resolutionMax = 255


for x in range(0, biggestStep + 1):
  print(int(round(math.sin(x / (2 * biggestStep) * math.pi) * resolutionMax, 0)), end = '')
  if x != biggestStep:
    print(', ', end = '')
  if (x % 10) == 0 and x != 0:
    print()

In which biggestStep is the biggest step possible (aka 100 in a 101 steps look up) and resolutionMax the full on step of the output.

septillion:
Yeah, I would still suggest FadeLed but to use a gamma table with a sine :slight_smile:

You can generate the values in Excel or Python or something.

For 1/4th of a sine (because that's all you need) you can use the 101 steps table:

const flvar_t SineTable[101] PROGMEM = {

0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40,
44, 48, 52, 56, 60, 63, 67, 71, 75, 79,
83, 86, 90, 94, 98, 101, 105, 109, 112, 116,
119, 123, 126, 130, 133, 137, 140, 143, 147, 150,
153, 156, 159, 163, 166, 169, 172, 175, 177, 180,
183, 186, 189, 191, 194, 196, 199, 201, 204, 206,
209, 211, 213, 215, 217, 219, 222, 223, 225, 227,
229, 231, 232, 234, 236, 237, 239, 240, 241, 243,
244, 245, 246, 247, 248, 249, 250, 250, 251, 252,
252, 253, 253, 254, 254, 254, 255, 255, 255, 255};




Made with the Python script:


import math

biggestStep = 100
resolutionMax = 255

for x in range(0, biggestStep + 1):
  print(int(round(math.sin(x / (2 * biggestStep) * math.pi) * resolutionMax, 0)), end = '')
  if x != biggestStep:
    print(', ', end = '')
  if (x % 10) == 0 and x != 0:
    print()



In which biggestStep is the biggest step possible (aka 100 in a 101 steps look up) and resolutionMax the full on step of the output.

Thanks for you help!

I am not 100% sure on what you mean however. I have never used Python before and I will be required to explain this to a group of people so I need to make sure I can explain what I have written.

So the values in your table are for a Sine wave, correct? Would I be able to insert my values I have already calculated?

Thanks again!

FadeLed uses by default a log lookup table with gamma 2,3. But you can make it anything you like, including sine. How you create that is up to you. I used Python as an easy way but you can use Excel as well. You could even calculate it by hand if you like. I used 101 steps (0 through 100 including as in percentage) but you can use a different number of steps. But going beyond 101 is pretty pointless for the 8-bit PWM of an Uno.

To see the sine, simply copy those values into Excel en plot it :slight_smile:

How to use the custom lookup table you can find in the documentation of FadeLed.

Write code to determine what the brightbness of each LED should be given the current time in millis(). Set the led's brightness each pass through the loop.

void loop() {
  analogWrite(led1, brightness_that_led1_should_be_right_now());
  analogWrite(led2, brightness_that_led2_should_be_right_now());
  analogWrite(led3, brightness_that_led3_should_be_right_now());
}

// a one-second sine wave

int brightness_that_led1_should_be_right_now() {

  float t = (millis() % 1000) / 1000.0;
  float s = sin(t * 2 * PI);
  float brite = ((s/2)+.05) * 255.9; // we never want the value to be exactly 256
  return (int) brite;
}

There's far better ways to organize the code, of course, but that's the basic idea. Think in thetms of "to make this sequence of things happen, what - at any time - does the code need to be doing right now?".

septillion:
FadeLed uses by default a log lookup table with gamma 2,3. But you can make it anything you like, including sine. How you create that is up to you. I used Python as an easy way but you can use Excel as well. You could even calculate it by hand if you like. I used 101 steps (0 through 100 including as in percentage) but you can use a different number of steps. But going beyond 101 is pretty pointless for the 8-bit PWM of an Uno.

To see the sine, simply copy those values into Excel en plot it :slight_smile:

How to use the custom lookup table you can find in the documentation of FadeLed.

I have been messing with your FadeLed library for a while now but I cant find the documentation that tells me how to use your custom lookup up table?

Mm, you're right. Not all documentation is updated is the latest release. I should make a new release!

But for now:

#include <FadeLed.h>

//101 step sine table 0 = 0 degree, 90 = 90 degree
const flvar_t SineTable[101] PROGMEM = {
  0,   4,   9,  13,  18,  22,  27,  31,  35,  40,
 44,  49,  53,  57,  62,  66,  70,  75,  79,  83,
 87,  91,  96, 100, 104, 108, 112, 116, 120, 124,
127, 131, 135, 139, 143, 146, 150, 153, 157, 160,
164, 167, 171, 174, 177, 180, 183, 186, 190, 192,
195, 198, 201, 204, 206, 209, 211, 214, 216, 219,
221, 223, 225, 227, 229, 231, 233, 235, 236, 238,
240, 241, 243, 244, 245, 246, 247, 248, 249, 250,
251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
255};

//Make FadeLed object with a sine lookup table of 101 (0 to 100 including)
FadeLed sine(5, SineTable, 90);

void setup(){
  sine.setTime(5000);
}

void loop(){
  FadeLed::update();

  if(sine.done()){
    if(sine.get()){
      sine.off();
    }
    else{
      sine.on();
    }
  }
}

Should fade up and down in sine motion. I did use a different sine table with only 90 steps. Now they correspond to degrees which is I think more useful.

septillion:
Mm, you're right. Not all documentation is updated is the latest release. I should make a new release!

But for now:

#include <FadeLed.h>

//101 step sine table 0 = 0 degree, 90 = 90 degree
const flvar_t SineTable[101] PROGMEM = {
0, 4, 9, 13, 18, 22, 27, 31, 35, 40,
44, 49, 53, 57, 62, 66, 70, 75, 79, 83,
87, 91, 96, 100, 104, 108, 112, 116, 120, 124,
127, 131, 135, 139, 143, 146, 150, 153, 157, 160,
164, 167, 171, 174, 177, 180, 183, 186, 190, 192,
195, 198, 201, 204, 206, 209, 211, 214, 216, 219,
221, 223, 225, 227, 229, 231, 233, 235, 236, 238,
240, 241, 243, 244, 245, 246, 247, 248, 249, 250,
251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
255};

//Make FadeLed object with a sine lookup table of 101 (0 to 100 including)
FadeLed sine(5, SineTable, 90);

void setup(){
sine.setTime(5000);
}

void loop(){
FadeLed::update();

if(sine.done()){
if(sine.get()){
sine.off();
}
else{
sine.on();
}
}
}



Should fade up and down in sine motion. I did use a different sine table with only 90 steps. Now they correspond to degrees which is I think more useful.

Hmm, when I ran this script I got the following error message:

Any ideas?

Next time, please copy text as text, not an image.

But damn, I really need to make a release! I will try to do that this evening. Sorry for that!

In the mean time, just download the latest "build" from GitHub and install it manually. You can install it over the version you have installed now. Once there is an update the library manager will let you know.

septillion:
Next time, please copy text as text, not an image.

But damn, I really need to make a release! I will try to do that this evening. Sorry for that!

In the mean time, just download the latest "build" from GitHub and install it manually. You can install it over the version you have installed now. Once there is an update the library manager will let you know.

Managed to get it to work for the most part. Just a few things to fix and then it should be perfect. Thanks again.

Hello,
I have been trying to achieve this for some time now but with no success.

My goal is to;

  1. Phase LED1 in a Sine wave from 0% to 100% back to 0%
  2. When LED1 reaches 50%, begin phasing LED2 in the same way as LED1
  3. When LED2 reaches 50%, begin phasing LED3 in the same way as LED1/2

Visually it should look something like this:

So far the best that I have managed is to get LED1 to complete a Sine wave then when it reaches 0% again, LED2 will start, then LED3. This is the code I used to achieve this:

const int Button = 2;
const int LED1 = 3;
const int LED2 = 5;
const int LED3 = 9;

int buttonState = 0;

unsigned long previousMillis = 0;
const long interval = 1000;

void setup() 
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(Button, INPUT);
}

void loop() 

{
  noInterrupts();
  buttonState = digitalRead(Button);

  if(buttonState == HIGH)
  {
    float in, out;

// LED 1
    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out = sin(in) * 127.5 + 127.5;
      analogWrite(LED1,out); 
    }

// LED 2   
    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out = sin(in) * 127.5 + 127.5;
      analogWrite(LED2,out);
    }
   
// LED 3   
    for (in = 4.712; in < 10.99557; in = in + 0.0005)
    {
      out = sin(in) * 127.5 + 127.5;
      analogWrite(LED3,out);
    }
  }
 
 
  else
  {
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);   
  }

}

So my question is, what is the best way to achieve this?
Thanks!

What was wrong with what I told you here?

For three:

#include <FadeLed.h>

//91 step sine table 0 = 0 degree, 90 = 90 degree
const flvar_t SineTable[91] PROGMEM = {
  0,   4,   9,  13,  18,  22,  27,  31,  35,  40,
 44,  49,  53,  57,  62,  66,  70,  75,  79,  83,
 87,  91,  96, 100, 104, 108, 112, 116, 120, 124,
127, 131, 135, 139, 143, 146, 150, 153, 157, 160,
164, 167, 171, 174, 177, 180, 183, 186, 190, 192,
195, 198, 201, 204, 206, 209, 211, 214, 216, 219,
221, 223, 225, 227, 229, 231, 233, 235, 236, 238,
240, 241, 243, 244, 245, 246, 247, 248, 249, 250,
251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
255};

//Make FadeLed object with a sine lookup table of 91 (0 to 90 including)
FadeLed sines[3] = {{9, SineTable, 90}, {10, SineTable, 90}, {11, SineTable, 90}};
const byte NrSines = sizeof(sines)/sizeof(sines[0]);

void setup(){
  for(byte i = 0; i < NrSines; i++){
    sines[i].setTime(1000); //halve period, 0% to 90% or 90% to 0%
  }
  
  //start the first
  sines[0].on();
}

void loop(){
  FadeLed::update();
  
  //if first is >50% (45 degree) and second is not fading and off
  if((sines[0].get() >= 45) && !sines[1].done() && (sines[1].get() == 0)){
    sines[1].on();
  }
  
  //if first is >50% (45 degree) and second is not fading and off
  if((sines[1].get() >= 45) && !sines[2].done() && (sines[2].get() == 0)){
    sines[2].on();
  }
  
  //if sin is 100% (90 degree), fade back down
  if(sines[0].done() && sines[0].get()){
    sines[0].off();
  }
  
  //if sin is 100% (90 degree), fade back down
  if(sines[1].done() && sines[1].get()){
    sines[1].off();
  }
  
  //if sin is 100% (90 degree), fade back down
  if(sines[2].done() && sines[2].get()){
    sines[2].off();
  }
}

Or with a handy loop:

#include <FadeLed.h>

//91 step sine table 0 = 0 degree, 90 = 90 degree
const flvar_t SineTable[91] PROGMEM = {
  0,   4,   9,  13,  18,  22,  27,  31,  35,  40,
 44,  49,  53,  57,  62,  66,  70,  75,  79,  83,
 87,  91,  96, 100, 104, 108, 112, 116, 120, 124,
127, 131, 135, 139, 143, 146, 150, 153, 157, 160,
164, 167, 171, 174, 177, 180, 183, 186, 190, 192,
195, 198, 201, 204, 206, 209, 211, 214, 216, 219,
221, 223, 225, 227, 229, 231, 233, 235, 236, 238,
240, 241, 243, 244, 245, 246, 247, 248, 249, 250,
251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
255};

//Make FadeLed object with a sine lookup table of 91 (0 to 90 including)
FadeLed sines[3] = {{9, SineTable, 90}, {10, SineTable, 90}, {11, SineTable, 90}};
const byte NrSines = sizeof(sines)/sizeof(sines[0]);

void setup(){
  for(byte i = 0; i < NrSines; i++){
    sines[i].setTime(1000); //halve period, 0% to 90% or 90% to 0%
  }
  
  //start the first
  sines[0].on();
}

void loop(){
  FadeLed::update();
  
  for(byte i = 0; i < NrSines; i++){
    //for all but last (who has no next)
    if(i < (NrSines - 1)){
      //if >50% (45 degree) and next is not fading and is off
      if((sines[i].get() >= 45) && !sines[i + 1].done() && (sines[i + 1].get() == 0)){
        sines[i + 1].on();
      }
    }
    
    //if sin is 100% (90 degree), fade back down
    if(sines[i].done() && sines[i].get()){
      sines[i].off();
    }
  }
}

Although I do apologize for not updating the release :confused: But the nightly should be fine :slight_smile: