Sine LED: An Alternative Way of Brightening and Dimming LEDs

I’m just getting back into the swing of using Arduino, and I just thought, why use some stupid direction reversing FOR loop to brighten an LED, when you can use a sine wave(which arguably makes it far more complex).
I just want to share this with beginners, so they can see some different ways to do things, because I don’t think many people will do this.
Sine waves are often used in coding to calculate a natural acceleration, using the positive half of the sin wave period of y=100sin(x/1.2733).
Enter this into the Desmos Graphing calculator.
I’m sure by this point you’ve realized how this works. After the first 1/2 cycle(I only allow the positive half of the cycle, pictured by entering y=100sin(x/1.2733){4>=x>=0}) I restrict the minimum Y value(PWM value) to 10 with y=100sin(x/1.2733){3.8>=x>=.13}*approximate)

Here is the code:

float x = 0;                          //initialize X as 0.0

void setup() {
  // Set pin 11 to pwm output
  pinMode(11, OUTPUT);
  Serial.begin(9600);              //For debugging over the COM interface
}

void loop() {
  // Brighten and dim the LED over ~4 seconds.
 for(x = 0; x < 5; x = x+.05)
 {
  if(x >= 3.8) //This if statement is the restriction on the X
  {               //
    x=.13;     //
  }              //      
  float y=100*sin(x/1.2733);// Updates the value of Y every cycle
  analogWrite(11,y);           // PWM outout of Half restricted sine wave.
  Serial.print(x);
  Serial.print(" ");
  Serial.println(y);
  delay(070);                   //I had to guess this through trial and error, it makes the cycle around 4                      // seconds
 }
}

Another way, that I only realized would be easier to write, and easier on the processor uses a full cycle, and is probably less convoluted, just use the same formula, but transformed up 110.(y=100sin(x/1.2733)+110) and rest to zero when x = 8. I’m not sure what the timing will be on this. *You will need to use map to make this work!

I hope you all enjoy this.

P.S. You can also sub in tangent and cosine for interesting results.

what about using abs for the full cyle

float y=100*abs(sin(x/1.2733));

you could implement it also without delay(). to cycle in 5 seconds over 180 degrees (5000 milliseconds)

uint32_t period = 5000L;   // the L forces Long ints 32 bit
uint32_t lastPrint = 0;

void setup() 
{
  pinMode(11, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  int time = millis() % period;              // returns a value between 0 and 4999;
  int degrees = (180L * time) / period;  // mapping to degrees
  y = 100 * sin(degrees);

  analogWrite(11, y);           // PWM outout

  if (millis() - lastPrint >= 500)  // output to display every 500ms
  {
    lastPrint += 500;
    Serial.print(time);
    Serial.print("\t");    // TAB char
    Serial.println(y);
  }
  // other code here
}

give it a try

robtillaart:
what about using abs for the full cyle

float y=100*abs(sin(x/1.2733));

you could implement it also without delay().
to cycle in 5 seconds over 180 degrees (5000 milliseconds)

uint32_t period = 5000L;   // the L forces Long ints 32 bit

uint32_t lastPrint = 0;

void setup()
{
  pinMode(11, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  int time = millis() % period;              // returns a value between 0 and 4999;
  int degrees = (180L * time) / period;  // mapping to degrees
  y = 100 * sin(degrees);

analogWrite(11, y);          // PWM outout

if (millis() - lastPrint >= 500)  // output to display every 500ms
  {
    lastPrint += 500;
    Serial.print(time);
    Serial.print("\t");    // TAB char
    Serial.println(y);
  }
  // other code here
}



give it a try

A problem I realized today, is that the sin() function on the Arduino uses radians. So, y=100sin(πx/3.5)+110(π/4 is for 9 units I want 8) is the correct format, which gives you a cycle of 8 units. That also explains why I had to use some obscure decimal value in the denominator. To continue to use degrees, just use y=100sin(degrees*πx/180)+110. Here is my improved code.

float x = 0;
const float pi=3.14159;

void setup() {
 // Set pin 11 to pwm output
 pinMode(11, OUTPUT);
 Serial.begin(9600);
}

void loop() {
 // Brighten and dim  the LED over 8 seconds.
for(x = 0; x < 8; x=x+.125)
{
float y = (100*sin(pi*x/3.5)+110);
//float writeValue = map(y,10,210,10,100); Not scaled well
analogWrite(11, y);
Serial.print(x);
Serial.print("  ");
Serial.println(y);
//Serial.print("  ");
//Serial.println(writeValue);
delay(125);
}
}

you’re right, about the radians. Still the concept is still the same

uint32_t period = 5000L;   // the L forces Long ints 32 bit
uint32_t lastPrint = 0;

void setup() 
{
  pinMode(11, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  int time = millis() % period;              // returns a value between 0 and 4999;
  float angle = (PI * time) / period;        // mapping to degrees
  y = 100 * sin(angle);

  analogWrite(11, y);           // PWM outout

  if (millis() - lastPrint >= 500)  // output to display every 500ms
  {
    lastPrint += 500;
    Serial.print(time);
    Serial.print("\t");    // TAB char
    Serial.println(y);
  }
  // other code here
}

While it is certainly different what lighting effect is it supposed to achieve ? It will certainly not be an ease in/out in terms of perceived brightness.

Using float to calculate the next brightness step is also rather wasteful. As a sine wave is predictable and analogWrite only provides 8-bit on most Arduinos you could populate a lookuptable with the pre-calculated values for your sine wave and just read the next value from that lookup table.