The below code executes one fade after a button was pressed. Each press of the button will select the next fade and run it once. This is the simplest form and it might suite your needs. if it does not suite your needs you will have to give de detailed description.
The code is still blocking which means that during the one second that colorRGB() is running and the one second delay the button will not be read.
First an array of structs is implemented for the different colours. A struct is a type that can hold related items; e.g. a name and a phonenumber in a phonebook. In our case it can hold the three colours ref green and blue.
// struct with initial colours
struct COLOURS
{
const int red;
const int green;
const int blue;
};
And the array
// array with the different colours to fade
const COLOURS colours[] = {
{ 0, 255, 255 }, // red
{ 0, 230, 255 }, // orange
{ 0, 180, 255 }, // yellow
{ 255, 0, 255 }, // green
{ 255, 0, 0 }, // cyan
{ 255, 255, 0 }, //blue
{ 0, 255, 100 }, //purple
};
You can call a fade of a specific colour as shown below; e.g. orange
colorRGB(colours[1].red, colours[1].green, colours[1].blue);
Next the pins (I've adjusted them)
const uint8_t redPin = 3;
const uint8_t greenPin = 5;
const uint8_t bluePin = 6;
const uint8_t btnPin = 2;
And the previous colours
int prevRed, prevGreen, prevBlue;
The button needs to be connected between a pin and GND. In setup() you now configure the button to use the internal pull-up.
void setup()
{
Serial.begin(115200);
// button between pin and GND
pinMode(btnPin, INPUT_PULLUP);
}
There is a little more before we get to loop(). To know how many elements there are in an array we add the following to the beginning of the code
// macro to calculate the size of an array of any type (int, float, struct)
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
Because of the wiring of the button between pin and GND a press will result in LOW. To make the code easier to read and modify (if the button is wired differently) we add the following to the beginning of the code
// more readible code
#define ISPRESSED LOW
loop() consists of three sections
- variable declaration
- button handling
- execute a fade for a colour.
void loop()
{
// index which colour to fade
static uint8_t index = 0xFF;
// previous index
static uint8_t prevIndex = 0xFF;
// previous state of the button
static uint8_t prevBtnState = !ISPRESSED;
All those variables are static; the result is that, like global variables, will be remembered and that, like local variables, they will only be known inside the function (loop() in this case).
index is initialised with 0xFF (255) which indicates that it's currently not valid. prevIndex is used to check if index was changed (due to a button press).
prevBtnState is used to check if the state of the button changed.
The button handling below
uint8_t btnState = digitalRead(btnPin);
// if the button changed from not-pressed to pressed or vice versa
if (btnState != prevBtnState)
{
// remember the new button state
prevBtnState = btnState;
Serial.println(F("button changed"));
// if the button is now pressed
if (btnState == ISPRESSED)
{
// increment the index
index++;
// print the index
Serial.print(F("button pressed, index = "));
Serial.println(index);
}
}
I think that it's self explaining.
The last part is the fading based on the index.
// if the index is valid
if (index < NUMELEMENTS(colours))
{
Serial.println(F("valid index"));
// if the index changed
if (index != prevIndex)
{
Serial.print(F("prevIndex = "));
Serial.println(prevIndex);
Serial.print(F("index = "));
Serial.println(index);
// remember the new index
prevIndex = index;
Serial.print(F("executing fade "));
Serial.println(index);
colorRGB(colours[index].red, colours[index].green, colours[index].blue);
delay(1000);
}
}
// if the index is not valid
else
{
// set index back to 0xFF; next press will result in 0
index = 0xFF;
}
}
We first check if the index is valid; if the index is not valid it will be reset to 0xFF. If the index is valid we check if the index has changed. If it did not change nothing happens; the result is that a fade will only be executed once.
If it did change, it will be remembered and next colorRGB() will be called with the values of colour in the array indicated by the array (colorRGB(colours[index].red, colours[index].green, colours[index].blue);
).
Full code
// macro to calculate the size of an array of any type (int, float, struct)
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// more readible code
#define ISPRESSED LOW
// struct with initial colours
struct COLOURS
{
const int red;
const int green;
const int blue;
};
// array with the different colours to fade
const COLOURS colours[] = {
{ 0, 255, 255 }, // red
{ 0, 230, 255 }, // orange
{ 0, 180, 255 }, // yellow
{ 255, 0, 255 }, // green
{ 255, 0, 0 }, // cyan
{ 255, 255, 0 }, //blue
{ 0, 255, 100 }, //purple
};
const uint8_t redPin = 3;
const uint8_t greenPin = 5;
const uint8_t bluePin = 6;
const uint8_t btnPin = 2;
int prevRed, prevGreen, prevBlue;
void setup()
{
Serial.begin(115200);
// button between pin and GND
pinMode(btnPin, INPUT_PULLUP);
}
void loop()
{
// index which colour to fade
static uint8_t index = 0xFF;
// previous index
static uint8_t prevIndex = 0xFF;
// previous state of the button
static uint8_t prevBtnState = !ISPRESSED;
uint8_t btnState = digitalRead(btnPin);
// if the button changed from not-pressed to pressed or vice versa
if (btnState != prevBtnState)
{
// remember the new button state
prevBtnState = btnState;
Serial.println(F("button changed"));
// if the button is now pressed
if (btnState == ISPRESSED)
{
// increment the index
index++;
// print the index
Serial.print(F("button pressed, index = "));
Serial.println(index);
}
}
// if the index is valid
if (index < NUMELEMENTS(colours))
{
Serial.println(F("valid index"));
// if the index changed
if (index != prevIndex)
{
Serial.print(F("prevIndex = "));
Serial.println(prevIndex);
Serial.print(F("index = "));
Serial.println(index);
// remember the new index
prevIndex = index;
Serial.print(F("executing fade "));
Serial.println(index);
colorRGB(colours[index].red, colours[index].green, colours[index].blue);
delay(1000);
}
}
// if the index is not valid
else
{
// set index back to 0xFF; next press will result in 0
index = 0xFF;
}
}
void colorRGB(int red, int green, int blue)
{
red = constrain(red, 0, 255);
green = constrain(green, 0, 255);
blue = constrain(blue, 0, 255);
for (int i = 0; i < 1000; i++)
{
analogWrite(redPin, map(i, 0, 999, prevRed, red));
analogWrite(greenPin, map(i, 0, 999, prevGreen, green));
analogWrite(bluePin, map(i, 0, 999, prevBlue, blue));
delay(1);
}
prevRed = red;
prevGreen = green;
prevBlue = blue;
}
Notes:
- Because colourRGB() and delay(1000) result in blocking code for two seconds, there is no need for additional debouncing of the button.
- The code is long due to the serial print statements.
- When you see "button changed" without the following "button pressed, index = " it indicates that the fade was completed and you can press the button again.
- Lastly this is not perfect code. But your topic does not indicate that you have much understanding at this point so I kept it simple. As others indicated you should actually get rid of the delays but I'm a bit worried that you might not understand 90% what is needed. As mentioned in the beginning this might basically do what you need; if not, please provide an exact description.