paulsb
Published © LGPL

Lithophane RGB lamp - rechargeable

A base for a lithophane light but could be used with any type of shade. 5 modes; white, red, green, blue and colour changing.

IntermediateFull instructions provided119
Lithophane RGB lamp - rechargeable

Things used in this project

Hardware components

Arduino Pro Mini 328 - 3.3V/8MHz
SparkFun Arduino Pro Mini 328 - 3.3V/8MHz
×1
FT232RL USB to TTL Serial Converter Adapter 3.3V 5.5V Module Mini Port for Arduino
Required to programme the Pro Mini from the Arduino IDE
×1
TP4056 5V 1A TYPE C Micro USB Board Module
×1
5mm LED Light Emitting Diode Common Cathode 4Pin RGB
×1
ALLNICE Dark Blue 3 Pins 2 Position Mini Toggle Switch
×1
Gikfun 6x6x9mm Tact Tactile Push Button Momentary Micro Switch with Cap
×1
3.7V 1000mAh Lithium Rechargeable Battery
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Custom parts and enclosures

Light base

Base lid

Top disk

Top post

Schematics

Circuit

Breadboard

Code

Code for driving the LED

C/C++
// Paul Brace July 2021
// Light control for pictorial light base

// Define PWM pins for RGB connections and other settings
#define BLUE 5
#define GREEN 3
#define RED 6
#define MODE_BUTTON 2
#define delayTime 100 // Fading time between colours
#define onTime 10000   // Time each colour remains on

// 5 Control modes
enum mode {
  cmWhite,
  cmRed,
  cmGreen,
  cmBlue,
  cmChange
};

// Variables used to store current values of RGB settings 0-255
int redValue;
int greenValue;
int blueValue;

// LED will flash when true
bool flash = true;

// Used in interrupt to indicate that the mode button was pressed
volatile bool buttonPressed;
volatile unsigned long lastButtonPress;     // For debounce

mode currentMode;

void setup()
{
  // Define Pins usage
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  pinMode(MODE_BUTTON, INPUT_PULLUP);

  // Interrupt called when mode button is pressed so falling from HIGH to LOW
  attachInterrupt(digitalPinToInterrupt(MODE_BUTTON), changeMode, FALLING);

  // Start with Change mode
  currentMode = cmChange;
  buttonPressed = false;
  lastButtonPress = millis();
}



void loop(){

  switch (currentMode) {
    case cmWhite:
      WhiteLight();
      break;
    case cmRed:
      RedLight();
      break;
    case cmGreen:
      GreenLight();
      break;
    case cmBlue:
      BlueLight();
      break;
    case cmChange:
      ChangingColour();
      break;
  }
}

void WhiteLight(){
  redValue = 255;
  greenValue = 255;
  blueValue = 255;
  ShowColour();
  // -1 = pause for a long time
  pauseAndCheckButton(-1);
}

void RedLight(){
  redValue = 255;
  greenValue = 0;
  blueValue = 0;
  ShowColour();
  // -1 = pause for a long time
  pauseAndCheckButton(-1);
}

void GreenLight(){
  redValue = 0;
  greenValue = 255;
  blueValue = 0;
  ShowColour();
  // -1 = pause for a long time
  pauseAndCheckButton(-1);
}

void BlueLight(){
  redValue = 0;
  greenValue = 0;
  blueValue = 255;
  ShowColour();
  // -1 = pause for a long time
  pauseAndCheckButton(-1);
}

void ShowColour(){
  analogWrite(RED, redValue);
  analogWrite(GREEN, greenValue);
  analogWrite(BLUE, blueValue);
}

void ChangingColour(){

  // Reset values
  redValue = 0;
  greenValue = 0;
  blueValue = 0;

  if (flash) {
    // Flash red 3 times
    for (int i = 0; i < 3; i++){
      redValue = 255;
      greenValue = 0;
      ShowColour();
      delay(250);
      redValue = 0;
      greenValue = 255;
      ShowColour();
      delay(250);
    }
    flash = false;    // Reset so will not flash on next cycle
  }

  // Start with red
  redValue = 255;
  greenValue = 0;
  ShowColour();
  // pause and if a button was pressed exit from function
  if (pauseAndCheckButton(onTime))
    return;

  // Fades out red bring green full
  for (int i = 0; i < 255; i += 1) 
  {
    redValue -= 1;
    greenValue += 1;
    ShowColour();
    if (pauseAndCheckButton(delayTime))
      return;
    // Red and Green half on so pause
    if (redValue == 127){
      if (pauseAndCheckButton(onTime))
        return;
    }
  }

  // Green full on
  if (pauseAndCheckButton(onTime))
    return;

  // Fades out green bring blue full
  for (int i = 0; i < 255; i += 1) 
  {
    greenValue -= 1;
    blueValue += 1;
    ShowColour();
    if (pauseAndCheckButton(delayTime))
      return;
    // Green and Blue half on so pause
    if (greenValue == 127){
      if (pauseAndCheckButton(onTime))
        return;
    }
  }

  // Blue full on
  if (pauseAndCheckButton(onTime))
    return;
  
  // Fades in red
  for (int i = 0; i < 255; i += 1) 
  {
    redValue += 1;
    ShowColour();
    if (pauseAndCheckButton(delayTime))
      return;
    // Green and Blue half on so pause
    if (redValue == 127){
      if (pauseAndCheckButton(onTime))
        return;
    }
  }

  // Blue and red full on
  if (pauseAndCheckButton(onTime))
    return;
    
  // Fades in Green leaving Blue and red at 255 to change to white
  for (int i = 0; i < 255; i += 1) 
  {
    greenValue += 1;
    ShowColour();
    if (pauseAndCheckButton(delayTime))
      return;
  }

  // All full on
  if (pauseAndCheckButton(onTime))
    return;

  // Fades out blue and green to return to red
  for (int i = 0; i < 255; i += 1) 
  {
    blueValue -= 1;
    greenValue -= 1;
    ShowColour();
    if (pauseAndCheckButton(delayTime))
      return;
  }
}  

bool pauseAndCheckButton(int waitFor){
  // Record the start time
  unsigned long startTime = millis();
  // Set the period to wait and check for a button press
  unsigned long period;
  if (waitFor == -1)
    period = 3600000ul;   // Wait for 1 hour before looping again - just a random long time
  else
    period = (unsigned long)waitFor;
  // Repeat until time up
  while ((millis() - startTime) < period){
    // Check if button has been pressed
    if (buttonPressed){
      buttonPressed = false; // reset to capture next press
      flash = true;          // Set so will flash to indicate if changing colour mode selected
      switch (currentMode) {
        case cmChange:
          currentMode = cmWhite;
          break;
        case cmWhite:
          currentMode = cmRed;
          break;
        case cmRed:
          currentMode = cmGreen;
          break;
        case cmGreen:
          currentMode = cmBlue;
          break;
        case cmBlue:
          currentMode = cmChange;
          break;
      }
      //delay(250);  // To capture debounce
      return true; // true = button was pressed 
    }
    delay(25);     // Very short delay to reduce number of loops in time
  }
  return false;  // time reached and false = button was not pressed
}

void changeMode(){
  if ((millis() - lastButtonPress) > 500ul){
    lastButtonPress = millis();
    buttonPressed = true;
  }
}

Credits

paulsb

paulsb

4 projects • 28 followers

Comments