// rgbLed.ino
//
// Version 1, 10 August 2021, by Koepel
// Version 2, 12 August 2021, by Koepel
// Changed a few variable names.
// Removed Serial.begin.
// More comments.
//
// Click on the buttons to change the status of the project.
// Instead of showing the status on a LCD display, a soft pulsating RGB led
// shows the status.
// For example:
// Green pulse with 1 Hz : The project is running fine and busy
// Red fast pulsating led : Error state
// Blue slow pulsating led : Waiting for input
//
// The RGB led is a Common Cathode type (common leg to GND).
// The Arduino pins to the led must be PWM pins.
//
const int rgbPins[] = { 11, 10, 9}; // PWM pins for Red, Green and Blue colors of RGB led.
const int buttonPins[] = { 4, 3, 2}; // input pins for Red, Green and Blue button.
float newStatus = 50.0; // the new status from 0.0 to 100.0, 50 = Green
float filteredStatus = 50.0; // low pas filtered status of the project from 0.0 to 100.0
float x = -0.5; // from -0.5 to 0.5, value on the time axis of the pulse
// A millis-timer of 40ms is used to update the PWM value for the RGB led
// The PWM signal itself is about 500Hz for a Arduino Uno
unsigned long previousMillis;
const unsigned long interval = 40; // 40 ms interval for 25 Hz
void setup()
{
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()
{
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);
}
}