// PWM pins for Red, Green and Blue colors of RGB led.
const int rgbPins[] = {11, 10, 9};
// input pins for Red, Green and Blue button.
const int buttonPins[] = {4, 3, 2};
// the new status from 0.0 to 100.0, 50 = Green
float newStatus = 50.0;
// low pas filtered status of the project from 0.0 to 100.0
float filteredStatus = 50.0;
// from -0.5 to 0.5, value on the time axis of the pulse
float x = -0.5;
// A millis-timer of 40ms is used to update the PWM value for the RGB led
unsigned long previousMillis; // The PWM signal itself is about 500Hz for a Arduino Uno
const unsigned long interval = 40; // 40 ms interval for 25 Hz
void setup() {
// put your setup code here, to run once:
for( int i=0; i<3; i++){
pinMode(rgbPins[i], OUTPUT);
}
for( int i=0; i<3; i++){
pinMode(buttonPins[i], INPUT_PULLUP);
}
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
/*
* The buttons do not need any debounce in this specific sketch.
* They can be pressed long or short or multiple times.
*/
if (digitalRead(buttonPins[0]) == LOW) //Red button, active LOW
{
newStatus = 100.0;
}
if (digitalRead(buttonPins[1]) == LOW) //Green button, active LOW
{
newStatus = 50.0;
}
if (digitalRead(buttonPins[2]) == LOW) //Blue button, active LOW
{
newStatus = 0.0;
}
/*
* Millis timer to set the update rate of the PWM for RGB led,
* and to provide a constant interval to calculate the pulse.
*/
if( currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
/*
* Low pass filter.
* Lower percentage for slower filter, higher percentage for faster filter
*/
const float pct = 1.8; // percentage of new value added to filter
filteredStatus = (( 1.0 - (pct / 100.0)) * filteredStatus) + (pct / 100.0 * newStatus);
float r, g, b; // values 0...1
float f; // frequency of the pulse in Hz
/*
* Convert status (0...100) to hue and frequency
* 0 = blue = 0.5 Hz
* 50 = green = 1.0 Hz
* 100 = red = 3.0 Hz
*/
if( filteredStatus < 50.0)
{
r = 0.0;
g = filteredStatus / 50.0;
b = 1.0 - g;
f = 0.5 + (g / 2); // 0.5 to 1.0 for lower range
}
else
{
r = (filteredStatus - 50.0) / 50.0;
g = 1.0 - r;
b = 0.0;
f = 1.0 + (2 * r); // 1.0 to 3.0 for higher range
}
/*
* The standard deviation is:
* y = e ^ ( -0.5 * x * x )
* This sketch uses:
* y = expf ( -s * squaref ( x ) ) // s = steepness, -50 is normal, -150 is steep
* The 'y' will be used for the amplitude of the r, g, b values.
*/
float y = expf( -50.0 * squaref( x));
/*
* Increment 'x' for the time axis
* Keep 'x' between -0.5 and 0.5
*/
x += f * float( interval) / 1000.0; // divide interval by 1000 because it is in milliseconds
if( x >= 0.5)
{
x -= 1.0;
}
/*
* Multiply each color by the amplitude of the pulse.
* The minimal value is set to 1, because turning the led completely off didn't look good.
*/
int pwmR = (int)round(1.0 + (r * y * 254.0));
int pwmG = (int)round(1.0 + (g * y * 254.0));
int pwmB = (int)round(1.0 + (b * y * 254.0));
// Write the new PWM value to the PWM pins for the Red, Green and Blue led colors.
analogWrite(rgbPins[0], pwmR);
analogWrite(rgbPins[1], pwmG);
analogWrite(rgbPins[2], pwmB);
}
}