#include <stdexcept>
#include <ESP32Servo.h>
#define R_PIN 16
#define G_PIN 17
#define B_PIN 18
#define POT_PIN 2
#define SERVO_PIN 4
// a helper struct of the RGBLed library for handling rgb values
struct RGBValue {
float r, g, b;
RGBValue(float r, float g, float b) : r(r), g(g), b(b) {}
RGBValue map(float (*f)(float)) {
return {f(r), f(g), f(b)};
}
RGBValue operator+(RGBValue other) {
return {this->r + other.r, this->g + other.g, this->b + other.b};
}
RGBValue operator-(RGBValue other) {
return {this->r - other.r, this->g - other.g, this->b - other.b};
}
RGBValue operator*(float x) {
return {r*x, g*x, b*x};
}
RGBValue operator/(float x) {
return {r/x, g/x, b/x};
}
void operator+=(RGBValue other) {
this->r += other.r;
this->g += other.g;
this->b += other.b;
}
void operator-=(RGBValue other) {
this->r -= other.r;
this->g -= other.g;
this->b -= other.b;
}
void operator*=(float x) {
r *= x;
g *= x;
b *= x;
}
void operator/=(float x) {
r /= x;
g /= x;
b /= x;
}
};
// pin values for the RGBLed library
struct RGBPins {
uint8_t r, g, b;
};
// the RGBLed library
class RGBLed {
private:
// internal variables
RGBPins pins;
uint32_t frequency = 1000;
uint8_t resolution = 10;
bool initialized = false;
// sets the duty cycle for [pin] accourding to [percentage]
void write_individual(uint8_t pin, float percentage) {
// max value for given resolution
uint32_t max_value = ( ((uint32_t)1) << (resolution - 1) ) - 1;
// corresponding duty cycle for given percentage
uint32_t duty_cycle = (uint32_t) (max_value * percentage);
// logs the value being written to the Serial terminal
Serial.print("Setting the duty cycle ");
Serial.print(duty_cycle);
Serial.print(" to pin ");
Serial.println(pin);
// writes the duty cycle to given pin
ledcWrite(pin, duty_cycle);
}
public:
// constructor with only the pins given by struct
RGBLed(RGBPins pins)
: pins(pins) {}
// constructor with only the pins given individually
RGBLed(uint8_t r, uint8_t g, uint8_t b)
: pins({r, g, b}) {}
// constructor with pins given by struct and pwm configuration
RGBLed(RGBPins pins, uint32_t frequency, uint8_t resolution)
: pins(pins), frequency(frequency), resolution(resolution) {}
// constructor with pins given individually and pwm configuration
RGBLed(uint8_t r, uint8_t g, uint8_t b, uint32_t frequency, uint8_t resolution)
: pins({r, g, b}), frequency(frequency), resolution(resolution) {}
// initializes the library
bool initialize() {
// return false if already initialized
if (initialized) return false;
bool success = true;
// attaches each pin to the ledc library
success = success && ledcAttach(pins.r, frequency, resolution);
success = success && ledcAttach(pins.g, frequency, resolution);
success = success && ledcAttach(pins.b, frequency, resolution);
// sets the initialized flag and returns if attached successfully
initialized = success;
return success;
}
// writes the given percentage values to the LED
void write(float r, float g, float b) {
// can only write if the library was initialized
if (!initialized) throw std::runtime_error("Cannot write to LED without initializing the library first.");
// percentage values need to be between 0 and 1 (inclusive)
if (r < 0 || r > 1) throw std::runtime_error("Value of r should be between 0 and 1 (inclusive).");
if (g < 0 || g > 1) throw std::runtime_error("Value of g should be between 0 and 1 (inclusive).");
if (b < 0 || b > 1) throw std::runtime_error("Value of b should be between 0 and 1 (inclusive).");
// writes each value to the corresponding pin
write_individual(pins.r, r);
write_individual(pins.g, g);
write_individual(pins.b, b);
}
// writes the given percentage values from struct to the LED
void write(RGBValue value) {
write(value.r, value.g, value.b);
}
// destructor
~RGBLed() {
// detaches the LED pins from the ledc library
ledcDetach(pins.r);
ledcDetach(pins.g);
ledcDetach(pins.b);
}
};
// defines the RGB led using the RGBLed library
RGBLed rgb_led(R_PIN, G_PIN, B_PIN);
// initial value of the rgb led
RGBValue value(0, 0, 0);
// increment value of the rgb led
RGBValue increment(0.1, 0.2, 0.3);
// the servo instance from the ESP32Servo library
Servo servo;
// delay time to wait between refreshes
uint16_t delay_time = 100;
void setup() {
// initializes the serial communication
Serial.begin(115200);
Serial.println("Serial communication started.");
// initializes the RGBLed library
if (!rgb_led.initialize()) {
Serial.println("An error occurred while trying to initialize the RGBLed library.");
abort();
} else {
Serial.println("RGBLed library initialized successfully.");
}
// prints the increment values and refresh rate to the Serial terminal
Serial.print("The increments are set to r=");
Serial.print(increment.r * 100, 0);
Serial.print(", g=");
Serial.print(increment.g * 100, 0);
Serial.print(", b=");
Serial.print(increment.b * 100, 0);
Serial.print(" [%/s], which are being applied every ");
Serial.print(delay_time);
Serial.println("ms.");
// initializes the ESP32Servo library
servo.attach(SERVO_PIN);
Serial.println("ESP32Servo library initialized successfully.");
}
void loop() {
// rgb values are incremented each iteration
value += increment * (delay_time / 1000.0);
// their values are reset if over 1
value = value.map([](float x) { return x > 1 ? 0 : x; });
// sends the values to the RGBLed library
rgb_led.write(value);
// delays before next iteration
delay(delay_time);
}