Keypad (4 toggle switches) + WS2812 (RGB) + Sound Seor

Hi everyone,

I’m am very new to Arduino coding and I have been enjoying the steep learning curve up until now..

I am currently building a fake control panel using WS2812 LED strip which is 80 pixels long broken up into with 8 columns by 10 rows. I am wanting the LED strip split into four sections (2 columns each) with a toggle switch below under each section (0-19, 20-39, 40-59, 60-79.)

The plan was to run a twinkle style animation on the panel with 5 or 6 standard colours until a switch is push up to the on position when the second 'RED alert' style animation would activate on that section of 20 lights until the switch was return to the off (low) position.

To add to my complications I have added a sound sensor so that when I am playing music the animation would speed up and slow down the animation.

So far I have worked out how to add a keypad and have assigned one of my themes to each of the four switches as a test, however the animation only seems to run manually when the switch is switched on and off and back on again. The switches each run their themes correctly but are all affected by my error.

So my questions are:

  1. How do I get the switches to switch between the two themes and for them to run correctly?
  2. Will I need to run 4 data pins out to control each section or can I tell it to only effect Pixels 0-19 say?
  3. is it an easy thing do adding speed up and down from a Sound Sensor?

I have attached my copied it below:


#include <arduino.h>
#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
#include <Keypad.h>
#define COLOUR_ORDER RGB //standard strips normally GRB - Double check Reds and Greens
#define CHIPSET WS2812
#define DATA_PIN    6
#define NUM_LEDS 80
#define VOLTS 5 //5v strip
#define MAX_AMPS 500 //milliamps 60mA PER PIXEL (4.8Amp max for 80x)
#define BRIGHTNESS (40) //0-255
#define NUM_COLOURS 5
#define NUM_REDCOLS 3


CRGB leds [NUM_LEDS] = {0}; //g_LEDs from DAVEGARAGE Frame buffer

//********************************************
//colour set up for ES TWINKLE EFFECT

static const CRGB ESTwinkle [NUM_COLOURS] =
{
  CRGB::Red,
  CRGB::Green,
  CRGB::White,
  CRGB::Blue,
  CRGB::Yellow
};

//********************************************
//colour set up for ES RED TWINKLE EFFECT

static const CRGB ESREDTwinkle [NUM_REDCOLS] =
{
  CRGB::Red,
  CRGB::Red,
  CRGB::Orange
};


//********************************************
//set up for Switches or Keypad

const byte ROWS = 2; //final panel many need to be expanded upto 4 Rows 
const byte COLS = 2; //final panel many need to be expanded upto 3 Cols
char keys [ROWS] [COLS] = {
  {'1','2'},
  {'3','4'}
};
byte rowPins [ROWS] = {2, 3};
byte colPins [COLS] = {4, 5};
Keypad keypad = Keypad (makeKeymap(keys), rowPins, colPins, ROWS, COLS); 

char key;

//********************************************

void setup() {

FastLED.addLeds<CHIPSET,DATA_PIN,COLOUR_ORDER>(leds,NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS,MAX_AMPS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();


}

void loop() {

  FastLED.clear(false);
  
  key = keypad.getKey();

if (key == '1') {
  for (int i=0; i<NUM_LEDS/2;i++)
{
  leds[random(NUM_LEDS)] = ESTwinkle[random(0, NUM_REDCOLS)];
  
}
  FastLED.show(BRIGHTNESS);
  delay(500);
  }

if (key == '2') {
  for (int i=0; i<NUM_LEDS/2;i++)
{
  leds[random(NUM_LEDS)] = ESREDTwinkle[random(0, NUM_REDCOLS)];
  
}
  FastLED.show(BRIGHTNESS);
  delay(500);
  }
  if (key == '3') {
  for (int i=0; i<NUM_LEDS/2;i++)
{
  leds[random(NUM_LEDS)] = ESTwinkle[random(0, NUM_REDCOLS)];
  
}
  FastLED.show(BRIGHTNESS);
  delay(500);
}
if (key == '4') {
  for (int i=0; i<NUM_LEDS/2;i++)
{
  leds[random(NUM_LEDS)] = ESREDTwinkle[random(0, NUM_REDCOLS)];
  
}
  FastLED.show(BRIGHTNESS);
  delay(500);
  }
}

Many thanks in advanced
Duncan

First you need to learn the do many things at once lesson or your buttons won't work all of the time because something else besides reading that pin is Hogging All The Cycles.

Learn to write code that Doesn't Fixate on one thing at a time.
This is key to automation rather than top to bottom batch-process IT code.

Still the best tutorial I know to start do-many-things-at-once.

It's a lot easier to learn with small examples. RESIST trying to use this on your project until you can show understanding: -- fyi, when I do this, my button is a jumper I ground on the USB port box on the board though I could ground it in a GND pinhole; it's my quick and oh so very dirty button --

Make led13 blink long and slow while watching the button to toggle the blink on and off at any instant. Then add a button and make one button blink faster and the other blink slower. Or 3 buttons for faster/slower/stop&start toggle. When you have FUN with it, it goes really well into long term memory and that's when to use what you know in bigger projects that teach you more.

Why are you using both of these :thinking: ?

You can use one data pin. Although it does not do what you want, the below demonstrates the idea.

In software, you can break your strip into 4 sections. In your style, you can add the following to your #defines

#define NUM_SECTIONS 4
#define SECTION_LENGTH (NUM_LEDS / NUM_SECTIONS)

Next you can create a for-loop for each section


  // first section
  for (uint8_t cnt = 0; cnt < SECTION_LENGTH; cnt++) {
    leds[cnt] = CRGB::Red;
  }

  // second section
  for (uint8_t cnt = SECTION_LENGTH; cnt < SECTION_LENGTH * 2; cnt++) {
    leds[cnt] = CRGB::Green;
  }

  // third section
  for (uint8_t cnt = SECTION_LENGTH * 2; cnt < SECTION_LENGTH * 3; cnt++) {
    leds[cnt] = CRGB::Blue;
  }

  // fourth section
  for (uint8_t cnt = SECTION_LENGTH * 3; cnt < SECTION_LENGTH * 4; cnt++) {
    leds[cnt] = CRGB::White;
  }

  FastLED.show(BRIGHTNESS);

Let's say that you want your complete strip to be orange except for when you press one of the buttons. You can first set the complete strip to the desired pattern and next overwrite one (or more) of the sections if a codition is met.

  // set full stripto desired pattern
  for (uint8_t cnt = 0; cnt < NUM_LEDS; cnt++) {
    leds[cnt] = CRGB::Orange;
  }

  key = keypad.getKey();

  // change first section if needed
  if (key == '1') {
    for (uint8_t cnt = 0; cnt < SECTION_LENGTH; cnt++) {
      leds[cnt] = CRGB::Red;
    }
  }

  // change second section if needed
  if (key == '2') {
    for (uint8_t cnt = SECTION_LENGTH; cnt < SECTION_LENGTH * 2; cnt++) {
      leds[cnt] = CRGB::Green;
    }
  }
  // change third section if needed
  if (key == '3') {
    for (uint8_t cnt = SECTION_LENGTH * 2; cnt < SECTION_LENGTH * 3; cnt++) {
      leds[cnt] = CRGB::Blue;
    }
  }

  // change fourth section if needed
  if (key == '4') {
    for (uint8_t cnt = SECTION_LENGTH * 3; cnt < SECTION_LENGTH * 4; cnt++) {
      leds[cnt] = CRGB::White;
    }
  }

  FastLED.show(BRIGHTNESS);

I had been playing around with both and prefer FastLED for sure. I must remember to delete Adafruit

Brilliant thank you the sections work! although I haven't yet worked out how to keep the Red lights on loop until the switch is lowered?

My code now looks like

#include <arduino.h>
#include <FastLED.h>
#include <Keypad.h>
#define COLOUR_ORDER RGB //standard strips normally GRB - Double check Reds and Greens
#define CHIPSET WS2812
#define DATA_PIN    6
#define NUM_LEDS 80
#define VOLTS 5 //5v strip
#define MAX_AMPS 500 //milliamps 60mA PER PIXEL (4.8Amp max for 80x)
#define BRIGHTNESS (50) //0-255
#define NUM_COLOURS 6
#define NUM_REDCOLS 3

//***********below is for creating 4 sections*******************

#define NUM_SECTIONS 4
#define SECTION_LENGTH (NUM_LEDS / NUM_SECTIONS)


CRGB leds [NUM_LEDS] = {0}; //wipe any data on strip

//********************************************
//colour set up for ES TWINKLE EFFECT

static const CRGB ESTwinkle [NUM_COLOURS] =
{
  CRGB::Red,
  CRGB::Orange,
  CRGB::Green,
  CRGB::Blue,
  CRGB::White,
  CRGB::Yellow
  
  };

//********************************************
//colour set up for ES RED TWINKLE EFFECT

static const CRGB ESREDTwinkle [NUM_REDCOLS] =
{
  CRGB::Red,
  CRGB::Red,
  CRGB::Orange
  
  };


//********************************************
//set up for Switches or Keypad

const byte ROWS = 2; //final panel many need to be expanded upto 4 Rows 
const byte COLS = 2; //final panel many need to be expanded upto 3 Cols
char keys [ROWS] [COLS] = {
  {'1','2'},
  {'3','4'}
};
byte rowPins [ROWS] = {2, 3};
byte colPins [COLS] = {4, 5};
Keypad keypad = Keypad (makeKeymap(keys), rowPins, colPins, ROWS, COLS); 

char key;

//********************************************

void setup() {

FastLED.addLeds<CHIPSET,DATA_PIN,COLOUR_ORDER>(leds,NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS,MAX_AMPS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();


}

void loop() {

  FastLED.clear(false);
  

  // set full stripto desired pattern
  for (uint8_t cnt = 0; cnt < NUM_LEDS/3; cnt++) {
    leds[random(NUM_LEDS)] = ESTwinkle[random(NUM_COLOURS)];
    delay(50);
  }

  key = keypad.getKey();

  // change first section if needed
 if (key == '1') {
    for (uint8_t cnt = 0; cnt < SECTION_LENGTH; cnt++) {
    leds[cnt] = CRGB::Red;
    delay(100);
    }
  }
   // change first section if needed
 if (key == '2') {
    for (uint8_t cnt = SECTION_LENGTH; cnt < SECTION_LENGTH * 2; cnt++) {
    leds[cnt] = CRGB::Red;
    delay(100);
    }
  }
   // change first section if needed
 if (key == '3') {
    for (uint8_t cnt = SECTION_LENGTH * 2; cnt < SECTION_LENGTH * 3; cnt++) {
    leds[cnt] = CRGB::Red;
    delay(100);
    }
  }
   // change first section if needed
 if (key == '4') {
    for (uint8_t cnt = SECTION_LENGTH * 3; cnt < SECTION_LENGTH * 4; cnt++) {
    leds[cnt] = CRGB::Red;
    delay(100);
    }
  }
FastLED.show(BRIGHTNESS);
}

You are 100% right the buttons don't work all of the time because of the animation cycles being processed..

I think I'm going to live with that until I can understand the code in the link you supplied :slight_smile:

Did you read the explanations?

Why the delay? It will not give you any visual delay, only slows the for-loops down. If you want a visual delay between the leds in a section, you will have to call the show() method after setting the colour of a led.

The Red sections would only flash up for a micro second until I added the delay() whilst bench testing.. I will give show() a try, cheers

The point was that you just as well could have used something like

if (key == '1') {
    for (uint8_t cnt = 0; cnt < SECTION_LENGTH; cnt++) {
    leds[cnt] = CRGB::Red;
    }
    delay(2000);
}

Or even better, add a delay before the FastLED.show(BRIGHTNESS);.

How about the cooking coffee, bacon and eggs example?

Every milli delayed cost 16000 cycles. I have cut and dry code techniques to change delays and loops into timers and state machines but Nick's code is smaller, simpler and more specific.

Undrstand the approach.

We put functions in void loop() to each run every time that void loop() runs, over and over until stopped.

When there is no blocking code, void loop() can average over 50 runs per milli. That's how often a few pins can be read and a bit done about it, response speed.

The functions or code in void loop() run what I call tasks.
.
A task to watch pins will on change, update a variable holding each pin status and nothing else. It may also software-debounce the button.
.
Another task that blinks led13 if a variable named blinkEnable is > 0
else if < 0 turns led13 off and sets blinkEnable to 0.
.
Another task that reads pinState and sets blinkEnable to 1 or -1.
.

The way to write Tasks, always runs even if just to check a trigger. Always runs again.

So depending on what happens to the button, the variables pinState and blinkEnable control the action instead of a big code structure. This example could be optimized smaller but I want to show an Input Task, an Output Task and a Process Task.

I do the "dirty real world work" of debouncing in the button handler Input Task.
If I switch to touch buttons or light sensor, I only have to change this one function.

I can add tasks, many tasks when there are 16M cycles/sec.

The post at this link shows how code with delay runs and the next post has the same but with timers .

Run both and see the delay code runs in sequence, timer code runs parallel.

This is not about complex code, it is about how to approach automation, an EE thing.

I think that simply reading the key as is done up till now will not work. You will have to make use of keypad events to determine when a key was pressed, held or released. Below example makes use of keypad events; it's meant to show how it works under the hood. It's a stripped down version of the original example that you can study as well. The below also demonstrates a simple "do two things at the same time" where the blinking of the led does not interfere with the keypad.

#include <Keypad.h>
//********************************************
//set up for Switches or Keypad

const byte ROWS = 2;  //final panel many need to be expanded upto 4 Rows
const byte COLS = 2;  //final panel many need to be expanded upto 3 Cols
char keys[ROWS][COLS] = {
  { '1', '2' },
  { '3', '4' }
};
byte rowPins[ROWS] = { 2, 3 };
byte colPins[COLS] = { 4, 5 };
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

//********************************************
// led pin for non-blocking blink
const uint8_t ledPin = 13;

//********************************************
// section to update based on switch; 0 indicates that no section needs to be updated.
int8_t section = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial)
    ;
  pinMode(ledPin, OUTPUT);               // Sets the digital pin as output.
  digitalWrite(ledPin, HIGH);            // Turn the LED on.
  keypad.addEventListener(keypadEvent);  // Add an event listener for this keypad
}

void loop()
{
  // read keypad; we can ignore the key that was pressed, it's handled in the event handler
  keypad.getKey();

  // do a non-blocking blink
  blinkIt();
}

// Taking care of some special events.
void keypadEvent(KeypadEvent key)
{
  switch (keypad.getState())
  {
    case PRESSED:
      Serial.write(key);
      Serial.println(F(" pressed"));
      break;
    case RELEASED:
      Serial.write(key);
      Serial.println(F(" released"));
      break;
    case HOLD:
      Serial.write(key);
      Serial.println(F(" held"));
      break;
    case IDLE:
      Serial.println(F("Idle"));
      break;
  }
}

/*
  non-blocking blink  
*/
void blinkIt()
{
  // the start time for the delay
  static uint32_t delayStarttime;

  // if one second has lapsed
  if (millis() - delayStarttime > 1000)
  {
    // update the start time of the next delay
    delayStarttime = millis();
    // toggle the led
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

Now you can use the event handler to set or clear the section that you want to modify; the above code already contains a global variable section for that. We're only interested in the fact that a key is pressed and in the fact that a key is released.

// Taking care of some special events.
void keypadEvent(KeypadEvent key)
{
  switch (keypad.getState())
  {
    case PRESSED:
      Serial.write(key);
      Serial.println(F(" pressed"));
      // set the section based on the key that was pressed
      section = key - '0';
      break;
    case RELEASED:
      Serial.write(key);
      Serial.println(F(" released"));
      // clear the section
      section = 0;
      break;
    case HOLD:
      Serial.write(key);
      Serial.println(F(" held"));
      break;
    case IDLE:
      Serial.println(F("Idle"));
      break;
  }
}

The line section = key - '0'; converts the key character to an integer.

And in loop() you can call two functions that make use of the section variable..

void loop()
{
  // read keypad; we can ignore the key that was pressed, it's handled in the event handler
  keypad.getKey();

  // twinkle the strip
  bool rv = twinkle(section);
  // update section
  rv |= updateSection(section);
  // if one or more les changed colour, show
  if (rv == true)
  {
    FastLED.show();
  }
}

This makes use of two functions to update (but not show)

  1. the complete strip with the possible exception of a section
  2. a section of the strip if selected
/*
  twinkle; set colours for full strip, exclude section if needed
  In:
    section number (1..4) of section to exclude; 0 indicates nothing to exclude
  Returns:
    true if the colour setting of a led changed, else false
*/
bool twinkle(int8_t section)
{
  return false;
}

/*
  set colours for a specific section of the strip
  In:
    section number (1..4) of section to update; 0 indicates no section to update
  Returns:
    true if the colour setting of a led changed, else false
*/
bool updateSection(int8_t section)
{
  return false;
}

Both functions are non-blocking and return true if the colour of one or more leds were changed by the function, else they return false. The idea is to only call show once if te colour of a led was changed in either of the functions; which makes it slightly faster. They also take the section as an argument; 0 indicates that no section was selected on the keypad, 1..4 indicate that a section was selected on the keypad; there is no hardening so if you manage to select a section higher than 4 there is a good chance that the code will crash.

You will have to add a few constants at the beginning of the above code.

//*********** strip update intervals *******************
// rate at which strip is updated
const uint16_t twinkleInterval = 100;
// rate at which section is updated
const uint16_t sectionInterval = 50;

You will also need to add the CRGB and ESTwinkle arrays back and add the FastLED stuff in setup().

Now you can fill in the details. twinkle() will twinkle the strip and is based on your twinkle. It will exclude a section if one was selected.

/*
  twinkle; set colours for full strip, exclude section if needed
  In:
    section number (1..4) of section to exclude; 0 indicates nothing to exclude
  Returns:
    true if the colour setting of a led changed, else false
*/
bool twinkle(int8_t section)
{
  // start time of delay
  static uint32_t delayStarttime;

  // if it's time to twinkle again
  if (millis() - delayStarttime >= twinkleInterval)
  {
    // update start time of next delay
    delayStarttime = millis();

    // set the twinkle colours
    for (int8_t cnt = 0; cnt < NUM_LEDS; cnt++)
    {
      // random number for led to set
      int8_t ledIndex = random(NUM_LEDS);

      // if twinkle applies to full strip or if ledIndex outside selected section
      if (section == 0 || ledIndex < (section - 1) * SECTION_LENGTH || ledIndex >= section * SECTION_LENGTH)
      {
        // set the led with a random colour selection from the ESTwinkle array
        leds[ledIndex] = ESTwinkle[random(sizeof(ESTwinkle) / sizeof(ESTwinkle[0]))];
      }
    }
    // indicate that we need to show() the change
    return true;
  }

  // no show() needed
  return false;
}

updateSection() will have a single blue led running up and down in the selected section.

/*
  set colours for a specific section of the strip
  In:
    section number (1..4) of section to update; 0 indicates no section to update
  Returns:
    true if the colour setting of a led changed, else false
*/
bool updateSection(int8_t section)
{
  // start time of delay
  static uint32_t delayStarttime;
  // index of led to be updated
  static int8_t ledIndex;
  // direction (up = 1, down = -1)
  static int8_t direction = 1;

  // detection of change of section
  static int8_t prevSection = 0;

  // if section equals 0, there is no section to update
  if (section == 0)
  {
    // nothing to do
    return false;
  }

  // if it's not time to update the section yet
  if (millis() - delayStarttime < sectionInterval)
  {
    // nothing to do
    return false;
  }

  // set the start time of the next delay
  delayStarttime = millis();

  // if there was a change in section
  if (prevSection != section)
  {
    // reset ledIndex to 0
    ledIndex = 0;
    // reset direction to go up
    direction = 1;
    // clear the previous section
    if (prevSection != 0)
    {
      int8_t ledOffset = (prevSection - 1) * SECTION_LENGTH;
      for (int8_t cnt = ledOffset; cnt < ledOffset + SECTION_LENGTH; cnt++)
      {
        leds[cnt] = CRGB::Black;
      }
    }
  }

  // update the previous section to reflect the passed section
  prevSection = section;

  // first led to change depends on the section
  int8_t ledOffset = (section - 1) * SECTION_LENGTH;

  // clear all leds in section
  for (int8_t cnt = ledOffset; cnt < ledOffset + SECTION_LENGTH; cnt++)
  {
    leds[cnt] = CRGB::Black;
  }

  // set a led
  leds[ledOffset + ledIndex] = CRGB::Blue;

  // next led or previous led
  ledIndex += direction;

  // if begin or end of section
  if (ledIndex == 0 || ledIndex >= SECTION_LENGTH - 1)
  {
    // change the direction
    direction *= -1;
  }

  // indicate that we have to call show()
  return true;
}

I unfortunately don't have one setup to give complete code. The KeypadEvent was tested on a Leonardo and the FastLED part was tested on a Mega. I hope there are no missing variables but I think that you can figure it out.

Below the Mega code used to test; tailored to my setup. It uses serial input (characters 0..4. 1..4 select a section, 0 clears the selected section (like releasing your switch).

#include <FastLED.h>

#define COLOUR_ORDER GRB  //standard strips normally GRB - Double check Reds and Greens
#define CHIPSET WS2812B
#define DATA_PIN A1
#define NUM_LEDS 60
#define VOLTS 5          //5v strip
#define MAX_AMPS 500     //milliamps 60mA PER PIXEL (4.8Amp max for 80x)
#define BRIGHTNESS (50)  //0-255
#define NUM_COLOURS 6
#define NUM_REDCOLS 3

//*********** below is for creating 4 sections *******************
#define NUM_SECTIONS 4
#define SECTION_LENGTH (NUM_LEDS / NUM_SECTIONS)

CRGB leds[NUM_LEDS] = { 0 };  //wipe any data on strip

//*********** strip update intervals *******************
// rate at which strip is updated
const uint16_t twinkleInterval = 100;
// rate at which section is updated
const uint16_t sectionInterval = 50;

//********************************************
// section to update based on switch; 0 indicates that no section needs to be updated.
int8_t section = 0;

//********************************************
// led pin for non-blocking blink
const uint8_t ledPin = 13;

//********************************************
// array with twinkle colours
const CRGB ESTwinkle[] = {
  CRGB::Red,
  CRGB::Green,
  CRGB::White,
  CRGB::Blue,
  CRGB::Yellow
};

void setup()
{
  Serial.begin(115200);
  FastLED.addLeds<CHIPSET, DATA_PIN, COLOUR_ORDER>(leds, NUM_LEDS);
  FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS, MAX_AMPS);
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
  FastLED.show();

  pinMode(ledPin, OUTPUT);     // Sets the digital pin as output.
  digitalWrite(ledPin, HIGH);  // Turn the LED on.
}

void loop()
{
  if (Serial.available())
  {
    char ch = Serial.read();
    if (ch >= '0' && ch <= '4')
    {
      section = ch - '0';
      Serial.println(section);
    }
  }

  // twinkle the strip
  bool rv = twinkle(section);
  // update section
  rv |= updateSection(section);
  // if one or more leds changed colour, show
  if (rv == true)
  {
    FastLED.show();
  }

  blinkIt();
}

/*
  twinkle; set colours for full strip, exclude section if needed
  In:
    section number (1..4) of section to exclude; 0 indicates nothing to exclude
  Returns:
    true if the colour setting of a led changed, else false
*/
bool twinkle(int8_t section)
{
  // start time of delay
  static uint32_t delayStarttime;

  // if it's time to twinkle again
  if (millis() - delayStarttime >= twinkleInterval)
  {
    // update start time of next delay
    delayStarttime = millis();

    // set the twinkle colours
    for (int8_t cnt = 0; cnt < NUM_LEDS; cnt++)
    {
      // random number for led to set
      int8_t ledIndex = random(NUM_LEDS);

      // if twinkle applies to full strip or if ledIndex outside selected section
      if (section == 0 || ledIndex < (section - 1) * SECTION_LENGTH || ledIndex >= section * SECTION_LENGTH)
      {
        // set the led with a random colour selection from the ESTwinkle array
        leds[ledIndex] = ESTwinkle[random(sizeof(ESTwinkle) / sizeof(ESTwinkle[0]))];
      }
    }
    // indicate that we need to show() the change
    return true;
  }

  // no show() needed
  return false;
}

/*
  set colours for a specific section of the strip
  In:
    section number (1..4) of section to update; 0 indicates no section to update
  Returns:
    true if the colour setting of a led changed, else false
*/
bool updateSection(int8_t section)
{
  // start time of delay
  static uint32_t delayStarttime;
  // index of led to be updated
  static int8_t ledIndex;
  // direction (up = 1, down = -1)
  static int8_t direction = 1;

  // detection of change of section
  static int8_t prevSection = 0;

  // if section equals 0, there is no section to update
  if (section == 0)
  {
    // nothing to do
    return false;
  }

  // if it's not time to update the section yet
  if (millis() - delayStarttime < sectionInterval)
  {
    // nothing to do
    return false;
  }

  // set the start time of the next delay
  delayStarttime = millis();

  // if there was a change in section
  if (prevSection != section)
  {
    // reset ledIndex to 0
    ledIndex = 0;
    // reset direction to go up
    direction = 1;
    // clear the previous section
    if (prevSection != 0)
    {
      int8_t ledOffset = (prevSection - 1) * SECTION_LENGTH;
      for (int8_t cnt = ledOffset; cnt < ledOffset + SECTION_LENGTH; cnt++)
      {
        leds[cnt] = CRGB::Black;
      }
    }
  }

  // update the previous section to reflect the passed section
  prevSection = section;

  // first led to change depends on the section
  int8_t ledOffset = (section - 1) * SECTION_LENGTH;

  // clear all leds in section
  for (int8_t cnt = ledOffset; cnt < ledOffset + SECTION_LENGTH; cnt++)
  {
    leds[cnt] = CRGB::Black;
  }

  // set a led
  leds[ledOffset + ledIndex] = CRGB::Blue;

  // next led or previous led
  ledIndex += direction;

  // if begin or end of section
  if (ledIndex == 0 || ledIndex >= SECTION_LENGTH - 1)
  {
    // change the direction
    direction *= -1;
  }

  // indicate that we have to call show()
  return true;
}

/*
  non-blocking blink  
*/
void blinkIt()
{
  // the start time for the delay
  static uint32_t delayStarttime;

  // if one second has lapsed
  if (millis() - delayStarttime > 1000)
  {
    // update the start time of the next delay
    delayStarttime = millis();
    // toggle the led
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.