How to make each color blink with a different frequency like slow or medium or fast?

So I made this circuit to change the RGB color with a button.
I want to make each color blink in a different frequency but I can't figure out how

here is the circuit:


and here is my code:

int red = 6;
int blue = 5;
int green = 3;
int button = 2;

int mode = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(red, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(green, OUTPUT);
  
  pinMode(button, INPUT_PULLUP);
  
}

void loop()
{
  if(digitalRead(button) == LOW)
  {
    mode = mode + 1;
    delay(400);
    
  }
  
  //off
  if(mode == 0)
  {
    analogWrite(red,0);
    analogWrite(green,0);
    analogWrite(blue,0);
  }
  
  //pink
  if(mode == 1)
  {
    analogWrite(red,255);
    analogWrite(green,105);
    analogWrite(blue,180); 
    
  }
  
  //green
  if (mode == 2)
  {
    analogWrite(red,0);
    analogWrite(green,255);
    analogWrite(blue,0);
  }
  
  //red
  if (mode == 3)
  {
    analogWrite(red,255);
    analogWrite(green,0);
    analogWrite(blue,0);
  }
  
  //light blue
  if (mode == 4)
  {
    analogWrite(red,173);
    analogWrite(green,216);
    analogWrite(blue,230);
  }
  
  //grey
  if (mode == 5)
  {
    analogWrite(red,128);
    analogWrite(green,128);
    analogWrite(blue,128);
  }
  
  //mauve
  if (mode == 6)
  {
    analogWrite(red,224);
    analogWrite(green,176);
    analogWrite(blue,255);
  }
  
  //switch off
  if(mode==7)
  {
    mode = 0;
  }
    Serial.println(digitalRead(button));
}

I would appreciate any help, because this is the final part of a project.

Have you tried to search on this site for a thing like "blink without delay"?

While you digest what Idahowalker said, you might also like to think about using state change detect on the button- it's one of the examples under "digital" in the ide.

Then you can take that sneaky delay(400) out, which I'm sure you put there to prevent a rapid zoom through the colours while you try to click the button for even a very short time. State change detect will fix that the "right" way, since it looks for the button to become pressed not just be pressed.

I looked up the blink without delay on Arduino IDE. Should I do the code for each color?
Because I have 6 colors the code will be so long.
But still I don't know how to use the blink without delay thing.

My thought is to use a digital pin for the cathode of the led rather than using the gnd pin, then blink that. Low on the pin would be on. You would just need to check that when the leds are all on, you have sufficient resistance on each of the 3 legs to limit the total current of all three together to 20mA or so, seeing as that would all be on one digital pin.

Then just set the blink interval in the if()'s that you already have for the value of mode.

(That's a bit off the top of my head....)

Start with this tutorial: https://www.baldengineer.com/blink-without-delay-explained.html

No you only have three colours because you only have three LEDs.
Colours that involve more than one LED being on at a time can’t be mixed.

I don't understand, I researched it and I'm trying to comprehend what you guys mean. But I'm not figuring what should I change or how I should do it.

Have you digested and understood the Blink Without Delay example on its own yet, as suggested more than once above

As well as looking at the "Blink without delay" sketch, which is an Example in the IDE, you should take a look at the demonstration-code-for-several-things-at-the-same-time sketch, which is pinned towards the top of the Project Guidance section.

Here is a quote from Robin 2 about his sketch:

My sketch uses the concept in “blink without delay” to cause three LEDs to blink at different intervals, a fourth LED is controlled by a button and a servo sweeps back and forth at two different speeds. The idea is to demonstrate how different processes can be accommodated in the same general framework.

That sketch could easily be modified to suit your needs by removing the code relating to the 4th LED and Servo Motor.

I think though, @JohnLincoln, the OP wants to blink the resulting colour as made from the 3 leds, but I may have misunderstood their need. That's why I suggested a few posts back, to put the common cathode on an i/o pin and blink that.

This is a no whining zone :wink:

1 Like

How you doing? Here is my version of what you want to do written for a ESP32. You should be able to use the below as a model.

#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/queue.h"
////
int   btnMode     = GPIO_NUM_5;
int   mode        = 0;
//
QueueHandle_t xQ_GPIO_evt;
QueueHandle_t xQ_Message;
struct stu_message
{
  int OnTime = 1000 ;
  int valueRed = 0 ;
  int valueGreen = 0;
  int valueBlue = 0;
} x_message;
//
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
  BaseType_t xHigherPriorityTaskWoken;
  uint32_t gpio_num = (uint32_t) arg;
  xQueueSendFromISR( xQ_GPIO_evt, &gpio_num, NULL );
}
//
void setup()
{
  const int chRed   = 4;
  const int chBlue  = 6;
  const int chGreen = 2;
  //
  xQ_Message = xQueueCreate( 1, sizeof(stu_message) );
  xQ_GPIO_evt = xQueueCreate(1, sizeof(uint32_t));
  //
  ledcSetup( chRed, 12000, 8 ); // ledc: 4  => Group: 0, Channel: 4, Timer: 2, led frequency, resolution  bits // red led
  ledcAttachPin( GPIO_NUM_12, chRed );   // gpio number and channel
  ledcWrite( chRed, 0 ); // write to channel number 4
  //
  ledcSetup( chBlue, 12000, 8 ); // ledc: 6  => Group: 0, Channel: 6, Timer: 3 // blue led
  ledcAttachPin( GPIO_NUM_15, chBlue );   // gpio number and channel
  ledcWrite( chBlue, 0 ); // write to channel number 6
  //
  ledcSetup( chGreen, 12000, 8 ); // ledc: 2  => Group: 0, Channel: 2, Timer: 1, led frequency, resolution  bits // green led
  ledcAttachPin( GPIO_NUM_5, chGreen );   // gpio number and channel
  ledcWrite( chGreen, 0 ); // write to channel number 2
  ////
  // configure GPIO input mode
  gpio_config_t io_cfg = {}; // reinitialize the gpio configuration structure
  io_cfg.mode = GPIO_MODE_INPUT; // set gpio mode. GPIO_NUM_0 input from water level sensor
  io_cfg.pin_bit_mask = ( (1ULL << GPIO_NUM_5)  ); //bit mask of the pins to set, assign gpio number to be configured
  gpio_config(&io_cfg); // configure the gpio based upon the parameters as set in the configuration structure
  // configure GPIO interrupt mode
  io_cfg = {}; // reinitialize the gpio configuration structure
  io_cfg.intr_type = GPIO_INTR_POSEDGE; //interrupt of rising edge
  io_cfg.pin_bit_mask = ( (1ULL << GPIO_NUM_5)  );
  //set as input mode
  io_cfg.mode = GPIO_MODE_INPUT;
  //enable pull-up mode
  io_cfg.pull_up_en = GPIO_PULLUP_ENABLE;
  gpio_config(&io_cfg);
  //
  //hook isr handler for specific gpio pin
  gpio_isr_handler_add( GPIO_NUM_5, gpio_isr_handler, (void*) GPIO_NUM_5 );
  //
  xTaskCreatePinnedToCore( fModeSelect, "fModeSelect", 5000, NULL, 5, NULL, 0 ); //CORE0
  xTaskCreatePinnedToCore( fLightShow, "fLightShow", 5000, NULL, 4, NULL, 1 ); //CORE1
  xTaskCreatePinnedToCore( fFlash, "fFlash", 3000, NULL, 4, NULL, 0 ); //CORE1
} //void setup()
//
void fModeSelect( void * pvParameters )
{
  uint32_t io_num;
  for (;;)
  {
    if ( xQueueReceive(xQ_GPIO_evt, &io_num, portMAX_DELAY) == pdTRUE )
    {
      mode ++;
      if ( mode >= 7 )
      {
        mode = 0;
      }
    }
    vTaskDelete ( NULL );
  }
} // void fModeSelect( * pvParameters )
////
void fLightShow( void * pvParameters )
{
  for ( ;; )
  {
    switch (mode)
    {
      case 0:
        x_message.OnTime = 1000;
        x_message.valueRed = 0;
        x_message.valueGreen = 0;
        x_message.valueBlue = 0;
        xQueueOverwrite( xQ_Message, (void *) &x_message );
        break;
      case 1:
        x_message.OnTime = 900;
        x_message.valueRed = 255;
        x_message.valueGreen = 105;
        x_message.valueBlue = 180;
        break;
      case 2:
        x_message.OnTime = 800;
        x_message.valueRed = 0;
        x_message.valueGreen = 255;
        x_message.valueBlue = 0;
        break;
      case 3:
        x_message.OnTime = 700;
        x_message.valueRed = 255;
        x_message.valueGreen = 0;
        x_message.valueBlue = 0;
        break;
      case 4:
        x_message.OnTime = 600;
        x_message.valueRed = 173;
        x_message.valueGreen = 216;
        x_message.valueBlue = 230;
        break;
      case 5:
        x_message.OnTime = 500;
        x_message.valueRed = 128;
        x_message.valueGreen = 128;
        x_message.valueBlue = 128;
        break;
      case 6:
        x_message.OnTime = 400;
        x_message.valueRed = 224;
        x_message.valueGreen = 176;
        x_message.valueBlue = 225;
        break;        
      default:
        mode = 0;
        break;
    }
  }
  vTaskDelete ( NULL );
} //void fLightShow( void * pvParameters )
//
void fFlash( void * pvParameters  )
{
  struct stu_message px_message;
  const int chRed   = 4;
  const int chBlue  = 6;
  const int chGreen = 2;
  //
  ledcWrite ( chRed, 0 );
  ledcWrite ( chBlue, 0 );
  ledcWrite ( chGreen, 0 );
  for (;;)
  {
    xQueueReceive(xQ_Message, &px_message, 0); //if any new receive new
    ledcWrite ( chRed, px_message.valueRed ); // leds on
    ledcWrite ( chBlue, px_message.valueBlue );
    ledcWrite ( chGreen, px_message.valueGreen );
    if ( px_message.OnTime = 0 )
    {
      px_message.OnTime = 1000;
    }
    vTaskDelay( px_message.OnTime );
    ledcWrite ( chRed, 0 ); //leds off
    ledcWrite ( chBlue, 0 );
    ledcWrite ( chGreen, 0 );
  }
  vTaskDelete ( NULL );
} // void fFlash( int flashTIme )
////
void loop() {}

Well, that is most helpful. :sunglasses:

Not! :crazy_face:

1 Like

This is my take on a blinking, button color switched, RGB led.

Only compiled, untested.

#include <Bounce2.h>

const uint8_t redPin = 6;
const uint8_t bluePin = 5;
const uint8_t greenPin = 3;
const uint8_t buttonPin = 2;

uint8_t colors[][3] = {
  {0, 0, 0},
  {255, 105, 180},
  {0, 255, 0},
  {255, 0, 0},
  {173, 216, 230},
  {128, 128, 128},
  {224, 176, 255},
};
const uint8_t definedColors = sizeof(colors) / sizeof(colors[0]);
const uint16_t blinkDuration = 200;
uint8_t mode;
bool ledOn;
Bounce button;

void setup() {
  Serial.begin(115200);
  button.attach(buttonPin, INPUT_PULLUP);
  pinMode(redPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(greenPin, OUTPUT);
}

void loop() {
  if (button.update() && button.fell()) {
    if (++mode >= definedColors) {
      mode = 0;
    }
   Serial.print(F("new mode is "));
   Serial.println(mode);
 }
  static uint32_t lastBlink;
  uint32_t topLoop = millis();
  if (topLoop - lastBlink > blinkDuration) {
    lastBlink = topLoop;
    setColor(ledOn ? 0 : mode);
    ledOn = not ledOn;
  }
}

void setColor(uint8_t sel) {
  analogWrite(redPin, colors[sel][0]);
  analogWrite(greenPin, colors[sel][1]);
  analogWrite(bluePin, colors[sel][2]);
}

This version should blink with different frequencies, as requested

#include <Bounce2.h>

const uint8_t redPin = 6;
const uint8_t bluePin = 5;
const uint8_t greenPin = 3;
const uint8_t buttonPin = 2;

uint8_t colors[][3] = {
  {0, 0, 0},
  {255, 105, 180},
  {0, 255, 0},
  {255, 0, 0},
  {173, 216, 230},
  {128, 128, 128},
  {224, 176, 255},
};
const uint8_t definedColors = sizeof(colors) / sizeof(colors[0]);
uint16_t blinkDurations[definedColors] = { 100, 100, 200, 300, 400, 500, 600,};
uint8_t mode;
bool ledOn;
Bounce button;

void setup() {
  Serial.begin(115200);
  button.attach(buttonPin, INPUT_PULLUP);
  pinMode(redPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(greenPin, OUTPUT);
}

void loop() {
  if (button.update() && button.fell()) {
    if (++mode >= definedColors) {
      mode = 0;
    }
   Serial.print(F("new mode is "));
   Serial.println(mode);
 }
  static uint32_t lastBlink;
  uint32_t topLoop = millis();
  if (topLoop - lastBlink > blinkDurations[mode]) {
    lastBlink = topLoop;
    setColor(ledOn ? 0 : mode);
    ledOn = not ledOn;
  }
}

void setColor(uint8_t sel) {
  analogWrite(redPin, colors[sel][0]);
  analogWrite(greenPin, colors[sel][1]);
  analogWrite(bluePin, colors[sel][2]);
}

Hello
This is my proposal for your project. You may add the desired colour sets and change the hardware pinning.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  https://forum.arduino.cc/t/how-to-make-each-color-blink-with-a-different-frequency-like-slow-or-medium-or-fast/920837
*/
#define ProjectName "How to make each color blink with a different frequency like slow or medium or fast"
// hardware settings
constexpr byte ButtonPin {A0};      // portPin o---|button|---GND
constexpr byte LedRedPin {3};       // portPin o---|220|---|LED|---GND
constexpr byte LedGreenPin {5};     // portPin o---|220|---|LED|---GND
constexpr byte LedBluePin {6};      // portPin o---|220|---|LED|---GND
// CONSTANT DEFINITION
// you may need to change these constants to your hardware and needs.
constexpr byte Input_[] {ButtonPin};
constexpr byte Output_[] {LedRedPin, LedGreenPin, LedBluePin};
enum {Button_};
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
// redValue ,greenValue ,blueValue 
#define RedValue   255,0,0
#define GreenValue 0,255,0
#define BlueValue  0,0,255

struct BLOCK {
  unsigned long duration;
  byte colour[3];
  bool control_;
  unsigned long stamp;
} blocks [] {
  {1000, {RedValue}, true, 0},
  {500, {GreenValue}, false, 0},
  {250, {BlueValue}, false, 0},
};
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  for (auto Input : Input_) pinMode(Input, INPUT_PULLUP);
  for (auto Output : Output_) pinMode(Output, OUTPUT);
  // check outputs
  for (auto Output : Output_) digitalWrite(Output, HIGH), delay(1000);
  for (auto Output : Output_) digitalWrite(Output, LOW), delay(1000);
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);

  static unsigned long buttonMillis = 0;
  constexpr unsigned long buttonDebounce {20};
  if (currentTime - buttonMillis >= buttonDebounce) {
    buttonMillis = currentTime;
    static bool buttonState = false;
    bool stateNew = !digitalRead(Input_[Button_]);
    if (buttonState != stateNew) {
      buttonState = stateNew;
      if (stateNew) {
        static int colourSelect = 0;
        for (auto &block : blocks) block.control_ = false;
        colourSelect++;
        colourSelect = colourSelect % (sizeof(blocks) / sizeof(blocks[0]));
        blocks[colourSelect].control_ = true;
      }
    }
  }
  for (auto &block : blocks) {
    if (currentTime - block.stamp >= block.duration && block.control_) {
      block.stamp = currentTime;
      static bool onOff = 1;
      int element = 0;
      for (auto colour : block.colour) {
        if (onOff) analogWrite(Output_[element++], colour); else analogWrite(Output_[element++], false);
      }
      onOff = !onOff;
    }
  }
}

Have a nice day and enjoy coding in C++.

I'm very keen to hear what the OP makes of the solutions put forward in #14, #16 and #17. While I'm all for learners being stretched, and I daresay those are good working solutions, just strikes me that none of them is really beginner territory which I think is where the OP is right now.

Of course, this is a very good example for a beginner learning the C++ programming language.
To program this task in C would be a waste of time.

If you only present beginner level code to beginners, how would they learn something?

Do you think the delay controlled or blocking examples in the IDE really help a beginner?