New version of an old neopixel sketch not working for me

I have a sketch I wrote 8 years for an Arduino Nano but it works (or not) the same on an Uno. It runs one Nanopixel through a rainbow and the other nanopixel simulates a red heartbeat. Recently I rebuilt the sketch to use the rainbow() function, but while it does a great job, is what I originally wanted and makes the sketch substantially smaller, the heartbeat() function (which runs fine when run independently) won't run.
the new code is:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define NUM_LEDS 2

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, 3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel altpixel = Adafruit_NeoPixel(NUM_LEDS, 5, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.setBrightness(100);
  altpixel.setBrightness(100);
  strip.begin();
  altpixel.begin();
}

void loop() {
  heartbeat();
  rainbow(50);
}
//this part should continuously blink pin 5 but doesn't yet
void heartbeat() {
  altpixel.setPixelColor(0, altpixel.Color(255, 0, 0));  // set pixel 5 to red
  altpixel.show();
  delay(50);

  altpixel.setPixelColor(0, altpixel.Color(0, 0, 0));  // set pixel 5 to black
  altpixel.show();
  delay(200);

  altpixel.setPixelColor(0, altpixel.Color(255, 0, 0));  // set pixel 5 to red
  altpixel.show();
  delay(50);

  altpixel.setPixelColor(0, altpixel.Color(0, 0, 0));  // set pixel 5 to black
  altpixel.show();
  delay(700);
}
void rainbow(int wait) {
  for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) {
    for (int i = 0; i < strip.numPixels(); i++) {
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show();
    delay(wait);
  }
}

where the rainbow is connected to pin 3 and the heartbeat is pin 5.

the old code, while massive, does what I want except the rainbow transition isn't smooth

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif

#define PIN 3

#define ALTPIN 5


#define NUM_LEDS 2

#define BRIGHTNESS 100

#define BRIGHTNESS2 100

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

Adafruit_NeoPixel altpixel = Adafruit_NeoPixel(NUM_LEDS, ALTPIN, NEO_GRB + NEO_KHZ800);


int gamma[] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
  2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
  5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
  10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
  17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
  25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
  37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
  51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
  69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
  90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114,
  115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142,
  144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
  177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
  215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255
};


void setup() {
  //Serial.begin(115200);

  strip.setBrightness(BRIGHTNESS);
  altpixel.setBrightness(BRIGHTNESS2);
  strip.begin();
  altpixel.begin();
  //  strip.show();
  //  altpixel.show();
}

void loop() {

  colorWipe2(strip.Color(255, 0, 0), 3000);  //red

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 32, 0), 3000);  //red2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 64, 0), 3000);  //redorange

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 96, 0), 3000);  //redorange2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 128, 0), 3000);  //orange

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);


  colorWipe2(strip.Color(255, 160, 0), 3000);  //orange2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 192, 0), 3000);  //yelloworange

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 224, 0), 3000);  //yelloworange2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 255, 0), 3000);  //yellow

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(191, 255, 0), 3000);  //yellow2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(128, 255, 0), 3000);  //yellowgreen

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(64, 255, 0), 3000);  //yellowgreen2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(0, 255, 0), 3000);  //green

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(0, 255, 128), 3000);  //green2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(0, 255, 224), 3000);  //aqua

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(0, 128, 224), 3000);  //aqua2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(0, 0, 255), 3000);  //blue

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(32, 0, 255), 3000);  //blue2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(64, 0, 255), 3000);  //purple

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(64, 0, 192), 3000);  //purple2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(64, 0, 128), 3000);  //indigo

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(128, 0, 192), 3000);  //indigo2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 0, 255), 3000);  //purpleb

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(192, 0, 255), 3000);  //purpleb2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(128, 0, 255), 3000);  //violet

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 0, 192), 3000);  //violet2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);


  colorWipe2(strip.Color(255, 0, 128), 3000);  //violetred

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);

  colorWipe2(strip.Color(255, 0, 64), 3000);  //violetred2

  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 70);
  colorWipe(altpixel.Color(255, 0, 0), 50);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
  colorWipe(altpixel.Color(0, 0, 0), 3000);
}

void colorWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < altpixel.numPixels(); i++) {
    altpixel.setPixelColor(i, c);
    altpixel.show();
    delay(wait);
  }
}

void colorWipe2(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}



// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3, 0);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0, 0);
}

uint8_t red(uint32_t c) {
  return (c >> 8);
}
uint8_t green(uint32_t c) {
  return (c >> 16);
}
uint8_t blue(uint32_t c) {
  return (c);
}

Any thoughts? I feel like I'm missing something basic but it's eluding me. Thanks in advance :slight_smile:

Welcome to the forum

If you want help with your sketch you must post it.

Please post your sketch, using code tags when you do. This prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination

In my experience the easiest way to tidy up the code and add the code tags is as follows
Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

Hi, @btsculptor
Welcome to the forum.

Can you please post a copy of your code, using code tags?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Thanks for the info! I hit some key combo that posted it instead of a return. Once everything froze up here I went back and did the formatting changes you suggested. Hope I got it right this time :slight_smile:

Thanks! I think I got it right now but I'll go check the rules :slight_smile:

CTRL+<CR>

more than likely, yes - was trying to hit a return

I am running your code... what are you needing?

Here is a "event timing" simulation... imagine you assign color change or intensity change to an event timer. Your code could be down to a couple dozen lines long.

Also, here is my little color dot to see if you can use it.

Hi, @btsculptor

Please do not go back and edit/add information to old posts, this causes confusion to someone reading the thread from the start.

Always add new info in new posts.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Thanks - I'll have to look into event timing :slight_smile:

Gotcha :+1: :+1:t3:

Should I delete this post and start over?

No, just keep going. with this thread.

Tom... :smiley: :+1: :coffee: :australia:

I've been looking at the millis tutorials but I can't figure how to do the heartbeat (haven't started on the rainbow - it should be simpler.) I can get an led to blink or even two at different rates, but the parameters are either on for (y)(OnTime) and off for (x)(OffTime), and I need on for (50), off for (200), on for (50) and off for (750) so I need four parameters, or at least three. This is a flasher tutorial I found that I can mostly follow, but again, the options don't give me the variation I need. Unfortunately it's not just lose the delay() and plug in millis() - it's a whole different approach. Any help here? I do appreciate what you've told me so far :slight_smile:

class Flasher {
  // Class Member Variables
  // These are initialized at startup
  int ledPin;    // the number of the LED pin
  long OnTime;   // milliseconds of on-time
  long OffTime;  // milliseconds of off-time

  // These maintain the current state
  int ledState;                  // ledState used to set the LED
  unsigned long previousMillis;  // will store last time LED was updated

  // Constructor - creates a Flasher
  // and initializes the member variables and state
public:
  Flasher(int pin, long on, long off) {
    ledPin = pin;
    pinMode(ledPin, OUTPUT);

    OnTime = on;
    OffTime = off;

    ledState = LOW;
    previousMillis = 0;
  }

  void Update() {
    // check to see if it's time to change the state of the LED
    unsigned long currentMillis = millis();

    if ((ledState == HIGH) && (currentMillis - previousMillis >= OnTime)) {
      ledState = LOW;                  // Turn it off
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, ledState);  // Update the actual LED
    } else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime)) {
      ledState = HIGH;                 // turn it on
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, ledState);  // Update the actual LED
    }
  }
};


Flasher led1(12, 100, 400);
Flasher led2(13, 350, 350);

void setup() {
}

void loop() {
  led1.Update();
  led2.Update();
}

Just a thought...

Your code shows "pulse" timing starts 50ms before "fade" timing with 50ms RED, 70ms BLK/off, 50ms RED, about 1500ms BLK. Repeat.

 ----           ----
| 50 |   70    | 50 |                   about 1500           | about 1800ms
      ----------      ----------------------------------------
  ON     OFF      ON                      OFF

Your timing in post #15 would be...

 ----            ----
| 50 |   200    | 50 |          750          | total 1050ms
      ----------      -----------------------
  ON     OFF      ON            OFF

The "fade" timing shows each color change occurs 50ms after "pulse" starts, and displays twenty-eight colors by stepping one color element from one level to the next. Some levels use all 256 bits, some use 128, some 32. Steps are 64 bits, 32 bits, with a sprinkling of 128 bits.

The start of each "fade" should start when "pulse" starts (every 1050ms). The time to fade (step from one level to the next (MIN>>MAX or MAX>>MIN) should be 1050ms, so 256 steps would want to make one step every 3.9ms.

Your code can be "simulated" using this chart of eight stages of color change. Only one color changes at a time.

MIN = minimum value. Usually zero, some colors appear dimmer than others.
MAX = maximum value. Usually 255, some colors appear brighter than others.
INC = the counter will increase from MIN to MAX
DEC = the counter will decrease from MAX to MIN

START                 END
COLOR   RED GRN BLU   COLOR
- ---   --- --- ---   -----
0 BLK > MIN MIN MIN > BLK black
1 BLK > INC MIN MIN > RED red
2 RED > MAX INC MIN > YEL yellow
3 YEL > DEC MAX MIN > GRN green
4 GRN > MIN MAX INC > CYN cyan
5 CYN > MIN DEC MAX > BLU blue
6 BLU > INC MIN MAX > MAG magenta
7 MAG > MAX MIN DEC > RED repeat

When the timer says "change color",

  • keep track of the step number (within MIN/MAX)
  • set steps flag if at MIN/MAX (and reset step counter, change stage counter)
  • set the level of the two static colors (MIN or MAX)
  • show the color

(here it is in a simulation, but using blocking code, not an open counter: minRGB - Wokwi ESP32, STM32, Arduino Simulator)

Post #17 has a "blocking" routine to fade colors through the rainbow.

I removed the for() loop from Post #17 and put a counter so it can be used with "event timing" ... I still use a delay() to slow the color change, BUT I can not see where I must slow the "in-color" increase/decrease of a single color value). This can be dropped into the wokwi in Post #17.

I was using digital pins, not PWM... corrected...

int pin[] = {3, 5, 6}; // r, g, b array of PWM pins
int inColor = 20; // in-color delay to slow transition
int step = 0, stage = 0, stages = 6; // steps per color, stage of color
int minimum = 0, maximum = 255; // counters
int increas, decreas;

void setup() {
  for (int i = 0; i < 3; i++ ) {
    pinMode(pin[i], OUTPUT); // configure r, g, b pins to OUTPUT
  }
}

void loop() {
  if (increas++ == maximum) { // increment step until counter is max
    increas = minimum; // reset step counter
    if (stage++ == stages) // increment stage until stage is max
      stage = 1; // reset stage
  }

  decreas = maximum - increas;

  switch (stage) {
    case 0: setColor(increas, minimum, minimum); break; // blk to red - one time
    case 1: setColor(maximum, increas, minimum); break; // red to yel
    case 2: setColor(decreas, maximum, minimum); break; // yel to grn
    case 3: setColor(minimum, maximum, increas); break; // grn to cyn
    case 4: setColor(minimum, decreas, maximum); break; // cyn to blu
    case 5: setColor(increas, minimum, maximum); break; // blu to mag
    case 6: setColor(maximum, minimum, decreas); break; // mag to red
    default: break;
  }
}

void setColor(int val1, int val2, int val3) {
  delay(inColor); // use this when running stand-alone, without a timing call
  analogWrite(pin[0], val1);
  analogWrite(pin[1], val2);
  analogWrite(pin[2], val3);
}

@btsculptor
Adapt this to your Adafruit functions, call it every 3.9ms, and remove the stand-alone delay().

If you want to think in timelines like that instead of segments, you could set up a non-blocking sequencer through the 1000 ms and act on the changes:

int scheduledChange() {
  static int counter = 0;
  // timekeeping
  auto now = millis();
  const typeof(now) interval = 1;
  static typeof(now) last = - interval;
  if (now - last >= interval) { // one-shot per interval
    last = now;
    switch (counter) {
      case 0 ... 24: fadeIn(); break;
      case 25 ... 50: fadeOut(); break;
      case 250: turnOn(); break;
      case 300: turnOff(); break;
      default:
        ;
    }
    if (++counter > 1000) {
      counter = 0;
    }
  }
  return (counter);
}

This non-blocking routine triggers every millisecond, and does interesting things only on the specified counts.

I feel your pain. Timing in a bourne shell...

  1. start a timer (timer = millis(); )
  2. compare to one of the four timing edges (50, 50+200, 50+200+50, 50+200+50+750)
  3. also compare "have I done this state already?" flag
  4. change the "pulse" state ("high to low" or "low to high")
  5. if all four states have been visited, pulse is done, reset the "visited" flag
  6. goto 1.

Very true.

  1. Every 3.9ms (3900us = 1050 pulse / 256 bits per color)
  2. change one bit of one color,
  3. keep track of steps (0 to 255),
  4. change direction (255 to 0),
  5. change color,
  6. go to 1

Continue learning new methods, as difficult as they seem... one moment they will make sense. I also recognize reference material does not cover your particular need... and translating them into your needs is a chore (worth the misery). For these reasons, and more, I want you to have this example simulation. I hope you can understand and incorporate the methods in future projects. Always have fun. Never give up.

thanks - unfortunately these don't work with neopixels :frowning:

I've spent a lot of time redoing the heartbeat to compile without errors, but it still doesn't blink:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
//#define NUM_LEDS 2
class Heartbeat {

  Adafruit_NeoPixel Heartbeat = Adafruit_NeoPixel(5, NEO_GRB + NEO_KHZ800);
  unsigned long currentMillis = millis();
  unsigned long previousMillis = millis();
  int ledState;  // ledState used to set the LED

public:
  Heartbeat() {
  }

  void Update() {      // check to see if it's time to change the state of the LED
    int ledPin = 5;    // the number of the LED pin
    int State0 = 50;   // milliseconds of on-time
    int State1 = 200;  // milliseconds of off-time
    int State2 = 50;   // milliseconds of on-time
    int State3 = 750;  // milliseconds of off-time

    previousMillis = 0;
    if ((ledState == State0) && (currentMillis - previousMillis >= 50)) {
      (0, Heartbeat.Color(255, 0, 0));  // Turn it r
      previousMillis = currentMillis;   // Remember the time
      digitalWrite(ledPin, State1);     // Update the actual LED

    } else if ((ledState == State1) && (currentMillis - previousMillis >= 200)) {
      (0, Heartbeat.Color(0, 0, 0));   // turn it b
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, State2);    // Update the actual LED

    } else if ((ledState == State2) && (currentMillis - previousMillis >= 50)) {
      (0, Heartbeat.Color(255, 0, 0));  // turn it r
      previousMillis = currentMillis;   // Remember the time
      digitalWrite(ledPin, State3);     // Update the actual LED

    } else if ((ledState == State3) && (currentMillis - previousMillis >= 200)) {
      (0, Heartbeat.Color(0, 0, 0));   // turn it b
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, State0);    // Update the actual LED  }
    };
  };
};

//Heartbeat led1(5, State0);

void setup() {
}

void loop() {
  //ledPin.Update();
  //led2.Update();
}