trouble with non-blocking function

thanks in advance for any help.

I am trying to write a program to pulse LEDs with PWM, but vary the duty cycle to brighten and dim them each independently. I have seen something in an advanced forum that used individal times, and maybe that is necessary, but I wanted to try my hand at this using various techniques from this and other forums.

I am using an Adafruit Metro 4 express (SAMD51) and yes tthe pins are PWM, they work properly with some versions of the code. One, the first function call runs over and over, I was trying to get it to end, and go one to the next function call.

Here is my code.

unsigned long StartMillis;
unsigned long CMillis;
const unsigned long fadePeriod = 100;  //fade period
int fadeLedPin[] = {2, 3, 4, 5, 6, 7};    //this LED will fade
int brightness = 0;  //initial brightness of LED
int increment = 17;  //amount to change PWM value at each change
int ledpin;
int led;
int x;
int count;
void setup()
{
 
 Serial.begin(115200);  //start Serial in case we need to print debugging info
 StartMillis = millis();  //start time of fading LED
}

void loop()
{
 // int count = 0;
 CMillis = millis();  //get the current time
 // Serial.println(count);
 fade(fadeLedPin[1]);  
 fade(fadeLedPin[0]);
 
}

void fade(int led)    //function to fade an LED
{
 if (CMillis - StartMillis >= fadePeriod) // && (count <= 15))  //test whether the period has elapsed
 {
   analogWrite(led, brightness);  //set the brightness of the LED
   brightness += increment;    
   // Serial.println(brightness);
   if (brightness >= 254) {
   brightness = 0;}
   return;
   // Serial.println(CMillis);
   StartMillis = CMillis;  //IMPORTANT to save the start time of the current LED state.
   // count = count + 1;
 }
}

a couple of things. The first, and kind of unrelated is that I tried to use a counter ( int count;) set it to zero (0), when I try to troubleshoot using Serial.println(count) the thing always starts at 10! I really don’t get that for sure!

I have two LEDs hooked up (pins 2, 3) and would just like the function to exit back to the loop with some kind of test, I tried a timer, a break, a continue, etc. If the function returns it is usually with brightness at max, and both LEDS on max.

Anyway, some help would be great for me, I am in lockdown, and programming is what I have been learning this wither season and it keeps my brain occupied.

Roger

Are pins 2 and 3 actually PWM capable pins on your Arduino board (you don't say which one it is)?

Also, please post code inside code tags so that it will

look like this

an auto-format your code using the IDE before posting so that it is easier to read. You can edit a previous post.

fade(fadeLedPin[1]);  
fade(fadeLedPin[0]);

Your fade function does not distinguish between one LED and the other. It only has one StartMillis and CMillis but you are expecting it to time 2 or more things with only 1 timer. Each thing you want to time needs its own timer.
Here is the code I occasionally post for debouncing buttons. While it is not what you want have a look at how I do timing using millis for 4 buttons independently inside the debounce function. Take what I have done there and adapt to what you are doing.

/* Simple button debounce for 4 buttons. Increments a count and sends the updated count to the serial monitor once per button press */
/* Tested on an Uno */
/* Connect simple push to make buttons between 0V and pin 2, 0V and pin 3, 0V and pin 4 and between 0V and pin 5 */

#define noOfButtons 4     //Exactly what it says; must be the same as the number of elements in buttonPins
#define bounceDelay 20    //Minimum delay before regarding a button as being pressed and debounced
#define minButtonPress 3  //Number of times the button has to be detected as pressed before the press is considered to be valid

const int buttonPins[] = {2, 3, 4, 5};      // Input pins to use, connect buttons between these pins and 0V
uint32_t previousMillis[noOfButtons];       // Timers to time out bounce duration for each button
uint8_t pressCount[noOfButtons];            // Counts the number of times the button is detected as pressed, when this count reaches minButtonPress button is regared as debounced 
uint8_t testCount[noOfButtons];             //Test count, incremented once per button press

void setup() {
  uint8_t i;
  uint32_t baudrate = 115200;
  Serial.begin(baudrate);
  Serial.println("");
  Serial.print("Serial port connected: ");
  Serial.println(baudrate);
  for (i = 0; i < noOfButtons; ++i) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    Serial.print("Testcount ");
    Serial.print(i);
    Serial.print(" = ");
    Serial.println(testCount[i]);
  }
}

void loop() {
  debounce();
  delay(10);     //Your other code goes here instead of this delay. DO NOT leave this delay here, it's ONLY for demonstration.
}

void debounce() {
  uint8_t i;
  uint32_t currentMillis = millis();
  for (i = 0; i < noOfButtons; ++i) {
    if (digitalRead(buttonPins[i])) {             //Input is high, button not pressed or in the middle of bouncing and happens to be high
        previousMillis[i] = currentMillis;        //Set previousMillis to millis to reset timeout
        pressCount[i] = 0;                        //Set the number of times the button has been detected as pressed to 0
      } else {
      if (currentMillis - previousMillis[i] > bounceDelay) {
        previousMillis[i] = currentMillis;        //Set previousMillis to millis to reset timeout
        ++pressCount[i];
        if (pressCount[i] == minButtonPress) {
          doStuff(i);                             //Button has been debounced. Call function to do whatever you want done.
        }
      }
    }
  }
}

// Function to do whatever you want done once the button has been debounced.
// In this example it increments a counter and send the count to the serial monitor.
// Put your own functions here to do whatever you like.
void doStuff(uint8_t buttonNumber) {
  ++testCount[buttonNumber];
  Serial.print("Button ");
  Serial.print(buttonNumber);
  Serial.print(" testcount = ");
  Serial.println (testCount[buttonNumber]);
}

thank you Perry.

I am working through that code to try to better understand it, I am making progress.

I do have other questions though.

In my code,

void loop()
{
  CMillis = millis();  //get the current time
  fade(fadeLedPin[1]);  
  fade(fadeLedPin[0]);
  
}

void fade(int led)    //function to fade an LED
{
  if ((CMillis - StartMillis >= fadePeriod) && (pulsecount < 1))   {
    analogWrite(led, brightness);  //set the brightness of the LED

I thought that using ‘fade(fadeLedPin’ could pass the LED pin # to the function, and in the function call the ‘void fade(int led)’ used the proper pin passed in the alalogWrite command.

What I seem to be having a problem with is ending the function call, sending back to the ‘loop’ portion and passing the next ‘fadeLedPin’ back to the function.

Roger

if you would like to fade several LEDs, i suggest to use a very basic class for the LED and put all objects in one array, to have easy access to all your LEDs.

Something like that (PWM pins from an UNO)

/*
  pulse LED with PWM
  
  https://forum.arduino.cc/index.php?topic=675980
  by noiasca
*/

class PulseLed
{
  private :
    const byte ledPin;                       // has to be a GPIO with PWM
    uint8_t interval = 50;                   // the intervall in milliseconds for each change
    uint32_t previousMillis = 0;             // stores the last change
    uint8_t pwm = 0;                         // actual value of PWM 
    uint8_t start = 0;                       // range from (lowest PWM value)
    uint8_t end =  255;                      // range to (highest PWM value

  public :
    PulseLed ( byte ledPin) :
      ledPin(ledPin)
    {}

    void begin() {
      pinMode(ledPin, OUTPUT);
    }

    void setInterval(byte newInterval)
    {
      interval = newInterval;
    }

    void setRange( byte newStart, byte newEnd)
    {
      if (newEnd > newStart)
      {
        start = newStart;
        end = newEnd;
      }
    }

    void tick() {
      if (millis() - previousMillis > interval)
      {
        previousMillis = millis();
        if (pwm % 2)                       // odd - going upwards
        {
          if (pwm < end -1 ) pwm = pwm + 2;
          else pwm = pwm -1;               // turn direction to downwards
        }
        else                               // even - goint downwards
        {
          if (pwm > start) pwm = pwm - 2;
          else pwm = pwm + 1;              // turn direction to upwards
        }
        analogWrite(ledPin, pwm);
      }
    }
};



PulseLed pulseLed[] {3, 5, 6, 9, 10, 11};  // UNO PWM pins 3, 5, 6, 9, 10, 11
//PulseLed pulseLed[] {3};                // do tests with just one LED

void setup() {
  Serial.begin(115200);
  Serial.println(F("\nStart"));
  for (auto & i : pulseLed)
    i.begin();

  pulseLed[0].setRange(0, 255);          // set an individuall PWM range from ... to ...
  pulseLed[1].setRange(64, 128);         // this LED never goes off, lowest value 64
  pulseLed[1].setInterval(10);           // set the interval/speed of pulsing
  pulseLed[2].setInterval(20);
}

void loop() {
  for (auto & i : pulseLed)
    i.tick();                 // tick each led on
}

I added some setter to show the different fadings.
The basic idea is: let each “LED Object” controll it’s pwm rate. Just tick/run/call each LED object frequently. The object knows, if it is time to change anything.

well that sketch certainly allows varying PWM of separate pins 'simultaneously' so now I know it can be done.

A few questions about the sketch though. I am not familiar with 'auto'

for (auto & i : pulseLed)
    i.begin();

  pulseLed[0].setRange(0, 255);          // set an individuall PWM range from ... to ...
  pulseLed[1].setRange(0, 255);         // this LED never goes off, lowest value 64
  pulseLed[0].setInterval(10);           // set the interval/speed of pulsing
  pulseLed[1].setInterval(10);
}

void loop() {
  for (auto & i : pulseLed)
    i.tick();                 // tick each led on

tick I get is a call.

Roger

for (auto & i : pulseLed)
long story short:
it iterates through all indexes of pulseLed, assignes a reference called i ('cause of &) and the type is auto. So in this case the type of pulseLed. In the for loop you have access to the method .begin() of your referenced object or on any other (public) method of your class.

You could replace it by a for (byte = 0; i< numberOfPulseLeds; i++) and do a call
pulseLed[i].begin().

But than you have to either define a numberOfPulseLeds or calculate the size of it. Therefore, use the newer range based for.

You can google for “range based for c++” and you will find better explanations for shure.

.tick() is just the name of the method. You could name it “do” or “run” or “handle” if you like it better. It’s just the method which should be called over and over again during loop.
I like the idea of an analog clock: tick … tick … tick …

I thought that using 'fade(fadeLedPin);' could pass the LED pin # to the function

Yes, correct, it does. That isn' the problem with your original code. You original code tries to deal with timing 2 different LEDs with only one timer. I don't believe that's what you want. I believe you want to time the 2 LEDs independently. If that's not correct then my apologies for the misunderstanding.

Perry, Thanks, I see that. These examples give me lots of things to do and think about. I am certain I will make progress, and I know if I have any more questions, I will find great help here!

Roger Ayotte

++Karma; // You're new here, good to see someone who is new thinking about the advice they have been given and trying to make sense of it. Good luck :slight_smile:

well, I have managed to utilize your code (noiasca) but it is way more advanced than my stage of learning. I have tried to review some basic C++ information on classes etc. but with very marginal understanding, I really am a noob.

So, here is what I did.

/*
  pulse LED with PWM

  https://forum.arduino.cc/index.php?topic=675980
  by noiasca
*/

class PulseLed
{
  private :
    const byte ledPin;                       // has to be a GPIO with PWM
    uint8_t interval = 100;                   // the intervall in milliseconds for each change
    uint32_t previousMillis = 0;             // stores the last change
    uint8_t pwm = 0;                         // actual value of PWM
    uint8_t start = 0;                       // range from (lowest PWM value)
    uint8_t end =  255;                      // range to (highest PWM value

  public :
    PulseLed ( byte ledPin) :
      ledPin(ledPin)
    {}

    void begin() {
      pinMode(ledPin, OUTPUT);
    }

    void setInterval(byte newInterval)
    {
      interval = newInterval;
    }

    void setRange( byte newStart, byte newEnd)
    {
      if (newEnd > newStart)
      {
        start = newStart;
        end = newEnd;
      }
    }

    void tick() {
      if (millis() - previousMillis > interval)
      {
        previousMillis = millis();
        if (pwm % 2)                       // odd - going upwards
        {
          if (pwm < end - 1 ) pwm = pwm + 2;
          else pwm = pwm - 1;              // turn direction to downwards
        }
        else                               // even - goint downwards
        {
          if (pwm > start) pwm = pwm - 2;
          else pwm = pwm + 1;              // turn direction to upwards
        }
        analogWrite(ledPin, pwm);
      }
    }
};



PulseLed pulseLed[] {2, 3, 4, 5, 6, 7}; // UNO PWM pins 2,3,4,5,6,7
//PulseLed pulseLed[] {3};                // do tests with just one LED

void setup() {
  Serial.begin(9600);
  for (auto & i : pulseLed)
    i.begin();

  pulseLed[0].setRange(0, 255);          // set an individuall PWM range from ... to ...
  pulseLed[0].setInterval(10);           // set the interval/speed of pulsing
  pulseLed[1].setRange(0, 255);         
  pulseLed[1].setInterval(10);
  pulseLed[2].setRange(0, 255);         
  pulseLed[2].setInterval(10);          
  pulseLed[3].setRange(0, 255);         
  pulseLed[3].setInterval(10);
  pulseLed[4].setRange(0, 255);         
  pulseLed[4].setInterval(10);          
  pulseLed[5].setRange(0, 255);         
  pulseLed[5].setInterval(10);  
}

void loop() {
  [code]for (auto & i : pulseLed)
    i.tick();                 // tick each led on

and my six LEDs can use PWM with varying PWM starts and stops.  Here is what I do not seem to be able to do:

[code]for (auto & i : pulseLed)
    i.tick();                 // tick each led on

take this line, and instead of using a ‘for’ and iterating through the items, call each one individually, with the ability to:
a. limit the pulse to one cycle.
b. call each LED with ‘tick()’ for example.

I cannot figure out how to use the i.tick(); with instead of i, either PulseLed, or pulseLed or whatever. It would really make my day if you could help me move a little bit along. I have given much effort with not much in terms of results.
Thanks in advance,
Roger

b. call each LED with 'tick()' for example.

if you don't use the auto ranged based for you could just call the .tick() method for each single object:

pulseLed[0].tick(); 
pulseLed[1].tick(); 
pulseLed[2].tick(); 
pulseLed[3].tick(); 
pulseLed[4].tick(); 
pulseLed[5].tick();

but in the end there is no reason not to call the .tick() for each method. See next:

a. limit the pulse to one cycle.

in this case you need to modify the class.
-add a status variable and

  • act if you have reached the full cycle stop pulsing within the .tick method, like a finite state machine in the class
  • introduce methods to start/stop (to reset the status) again.

but before we go into that more deeply you have to specify

Q: When do you want to start pulsing?
A: Assumption: on program start

Q: When do want to stop pulsing?
A: Assumption: after one full iteration up and down

Q: When do want to restart pulsing?
A: ?

Please correct the assumptions and define the missing one.

PS: regarding your code duplicates

...
pulseLed[3].setRange(0, 255);
...

if want to have all LEDs pulsing the same range it's enough if you modify the default values in the class:

    uint8_t start = 0;                       // range from (lowest PWM value)
    uint8_t end =  255;                      // range to (highest PWM value

so you can delete your 5 lines of .setRange(0, 255);

thank you noiasca,

I thought I had tried ‘pulseLed[0].tick();’ but apparetnly not as it works. Now I can use timing, interrupts etc to control the pulses.

I understand the lack of need to use a long list of setups for the leds, but I did it so I could have the control to have them be the same or not.

as far as questions:

"Q: When do you want to start pulsing?
A: Assumption: on program start - yes, or a button push.

Q: When do want to stop pulsing?
A: Assumption: after one full iteration up and down -yes, for now I want one ‘pulse’ and then move on, wait for another condition to be satisfied for example.

Q: When do want to restart pulsing?
A: this will be conditional, for example after every LED has pulsed one time, start over.

What I am hoping to do is to have one LED begin pulsing, and before it is finished with its one cycle, begin the next, to kind of leave a ‘trail’ of LEDs.

I have enought to begin using wha tyou have given me, but one part of your code is really vexing me.

void tick() {
if (millis() - previousMillis > interval)
{
previousMillis = millis();
if (pwm % 2) // odd - going upwards
{
if (pwm < end - 1 ) pwm = pwm + 2;
else pwm = pwm - 1; // turn direction to downwards
}
else // even - goint downwards
{
if (pwm > start) pwm = pwm - 2;
else pwm = pwm + 1; // turn direction to upwards
}
analogWrite(ledPin, pwm);
}
}

I have tried to use this code in another sketch, but I am having trouble getting it to work, for some reasont millis() useage is not allowing me to stop at just one iteration. It is okay, just some more noodling on my part will get there.

Thanks again,

Roger Ayotte

as mentioned already, if you want to “stop” the pulsing,
define a separate status variable byte isRunning= true;
Set the status to true / false if needed.
modify the if and check this variable.

there is no reason to avoid “ticking” the LED. Just set isRunning to false.

e.g. switch toggle the pulsing for the the second pin:

/*
  by noiasca
  https://forum.arduino.cc/index.php?topic=675980
*/

class PulseLed
{
  private :
    const byte ledPin;                       // has to be a GPIO with PWM
    uint8_t interval = 50;
    uint32_t previousMillis = 0;
    uint8_t pwm = 0;
    uint8_t start = 0;
    uint8_t end =  255;
    uint8_t isRunning = true;

  public :
    PulseLed ( byte ledPin) :
      ledPin(ledPin)
    {}

    void begin() {
      pinMode(ledPin, OUTPUT);
    }

    void setInterval(byte newInterval)
    {
      interval = newInterval;
    }

    void setRange( byte newStart, byte newEnd)
    {
      if (newEnd > newStart)
      {
        start = newStart;
        end = newEnd;
      }
    }

    void setStatus(byte newStatus)
    {
      if (newStatus)
      {
        pwm = start;
        isRunning = true;
      }
      else
      {
        analogWrite(ledPin, 0);
        pwm = start;
        isRunning = false;
      }
    }

    void tick() {
      if (millis() - previousMillis > interval && isRunning)
      {
        previousMillis = millis();
        if (pwm % 2)                       // odd - going upwards
        {
          if (pwm < end - 1 ) pwm = pwm + 2;
          else pwm = pwm - 1;              // turn direction to downwards
        }
        else                               // even - goint downwards
        {
          if (pwm > start) pwm = pwm - 2;
          else pwm = pwm + 1;              // turn direction to upwards
        }
        analogWrite(ledPin, pwm);
        Serial.println(pwm);
      }
    }
};

PulseLed pulseLed[] {3, 5, 6, 9, 10, 11};  // UNO PWM pins 3, 5, 6, 9, 10, 11

const byte buttonPin = A1;

void checkButton()
{
  static byte previousButton = HIGH;
  byte button = !digitalRead(buttonPin);
  static byte toggle;
  if (button && !previousButton)
  {
    toggle = !toggle;
    pulseLed[1].setStatus(toggle);
  }
  previousButton = button;
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("\nStart"));
  for (auto & i : pulseLed)
    i.begin();

  pinMode(buttonPin, INPUT_PULLUP);

  pulseLed[0].setRange(0, 255);          // set an individuall PWM range from ... to
  pulseLed[1].setRange(64, 128);         // this led never goes off, lowes value 64
  pulseLed[2].setInterval(10);          // set the interval/speed of pulsing
  pulseLed[3].setInterval(20);
}

void loop() {
  for (auto & i : pulseLed)
    i.tick();                 // tick each led on

  checkButton();
}

This works as long as we do not read:

What I am hoping to do is to have one LED begin pulsing, and before it is finished with its one cycle, begin the next, to kind of leave a ‘trail’ of LEDs.

Unfortunately this is a complete new requirement, which changes nearly “everything”.

My code was based on “brighten and dim them each independently.”. You don’t want to pulse independently.
New requirement - new Program ;-(

Treat your LEDs (all your LEDs?) as one object.
Specify: how many LEDs do you have
how many trailing LEDs do you need
How to calculate the PWM of each trailing LED depending on the PWM of the “primary” LED.
If we are talking about “trailing” LEDs, do you also need some “heading” LEDs?

By the way, if you want to code some kind of KITT-LED/Scanner/How ever it is called … I guess you will find Arduino sketches. If you don’t want this effect, what does your effect differently?

thank you noiasca,

I am kind of disheartened to hear I may have to start over. Actually, I made some great progress.

  1. I have introduced a ‘pulsecount’ parameter into the class, and test for it during the tick();. It successfully controls the number of pulses for each LED. (I have 8)

  2. When I call pulseLed[0].tick; the LED pulses one time if I have set that number to 1.

What to do next was to use a timer to determine a time between tick calls. This was not as simple as it appeared. See my code, but what happens is that the first LED begins to brighten, the second starts to brighten, the first stops at near full brightness, the second LED continues to brighten and dim and then done.

Yes, I am tryin to do something like the 'Kitt" type of display, but those sketches I saw were very difficult for me to understand. I am not just trying to build a bunch of LEDs, but to learn a bit how to program using the Arduino IDE.

I was beginning to think that this was going to be a success, then I saw that if I wanted to have them pulse in sequence, I could do that, but they would have to finish the cycle before the next one started. I was overjoyed when I was able to start the two LED pulses at different times, but the darn first one stopped!

here is the code I have done

/*
  pulse LED with PWM

  https://forum.arduino.cc/index.php?topic=675980
  by noiasca
*/
uint32_t CMillis = 0; 
class PulseLed
{
  private :
    const byte ledPin;                       // has to be a GPIO with PWM
    uint8_t interval = 1000;                   // the intervall in milliseconds for each change
    uint32_t previousMillis = 0;             // stores the last change
    uint8_t pwm = 0;                         // actual value of PWM
    uint8_t start = 0;                       // range from (lowest PWM value)
    uint8_t end =  255;                      // range to (highest PWM value
    uint8_t pulsecount = 0;

  public :
    PulseLed ( byte ledPin) :
      ledPin(ledPin)
    {}

    void begin() 
    {
      pinMode(ledPin, OUTPUT);
    }

    void setInterval(byte newInterval)
    {
      interval = newInterval;
    }

    void setRange( byte newStart, byte newEnd)
    {
      if (newEnd > newStart)
      {
        start = newStart;
        end = newEnd;
      }
    }
    void setpulsecount(byte newpulsecount)
    {
      pulsecount = newpulsecount;
    }
    
  void tick() 
  {
      if ((millis() - previousMillis > interval) && (pulsecount != 0))
      {
        previousMillis = millis();
        if (pwm % 2)                       // odd - going upwards
        {
          if (pwm < end - 1 ) pwm = pwm + 2;
          else pwm = pwm - 1;              // turn direction to downwards
        }
        else                               // even - goint downwards
        {
          if (pwm > start) pwm = pwm - 2;
          else pwm = pwm + 1;              // turn direction to upwards
        }
        analogWrite(ledPin, pwm);
        if (pwm == 0)
        {
        pulsecount = pulsecount - 1;
        }
      }
  }
  
};



PulseLed pulseLed[] {2, 3, 4, 5, 6, 7}; // UNO PWM pins 2,3,4,5,6,7
//  PulseLed pulseLed[] {3};                // do tests with just one LED

void setup() {
  Serial.begin(9600);
  for (auto & i : pulseLed)
    i.begin();

  pulseLed[0].setRange(0, 255);   // set an individuall PWM range from ... to ...
  pulseLed[0].setInterval(10);    // set the interval/speed of pulsing
  pulseLed[0].setpulsecount(1);  // set number of times to pulse
  pulseLed[1].setRange(0, 255);         
  pulseLed[1].setInterval(10);
  pulseLed[1].setpulsecount(1);
  pulseLed[2].setRange(0, 255);         
  pulseLed[2].setInterval(10);          
  pulseLed[2].setpulsecount(1);
  pulseLed[3].setRange(0, 255);         
  pulseLed[3].setInterval(10);
  pulseLed[3].setpulsecount(1);
  pulseLed[4].setRange(0, 255);         
  pulseLed[4].setInterval(10);          
  pulseLed[4].setpulsecount(1);
  pulseLed[5].setRange(0, 255);         
  pulseLed[5].setInterval(10);
  pulseLed[5].setpulsecount(1);  
}

void loop()
{
if (millis() - CMillis <=1500)
{
pulseLed[0].tick();  
}
if (millis() - CMillis > 500)
{
pulseLed[1].tick();
}
}

I very much appreciate the help you have given me, I am learning a lot on this project, though in an unconventional way. I tried going through the C++ tutorials on-line throught the ‘class’ parts and I get lost on the ‘namespace’ and other things. The examples are nothing applicable, so I am trying to poke at this myself with help from the forum.

Roger Ayotte

don't be disappointed. You have jumped into OOP, you can pulse individual LEDs, you have made you first setter method - hey that's more than others do in months!

Save the sketch, you will need it some day for shure. But now start a new project.
Without looking to much on other projects, my (stepwise) approach would be:

a) make a simple bouncing LED (e.g. 1 out of 6)
b) I assume a full range PWM is not necessary, just declare 2 or 3 "trailing" LEDS with 80% 60% 40% PWM and just let them follow the 100% LED. I'm very confident that this is all you will need and can be done with some for loops. Be carefull at the beginning and the end of your boarders - but that should be more or less all i guess.

You see? Just turn you head 180 degrees and try a different approach:
don't "dim" one LED. Take over the control/the bouncing, switch it on for 100% and handle the -1, -2, +1, +2 LED with reduced PWM.

just google ... oh, this one:

yes I know it's for Neopixel, but that's more or less the same procedure I would do:
set the boundaries, bounce a "master" LED - give an reduced effect onto the trailing/heading LEDs.

Okay, thought I’d give an update. Partial success! And thank you noiasca!

So I have been able to get my eight LEDs to pulse, and sequence them such that they successively pulse, and the ‘next’ one starts before teh first one is completed.

here is the code.

/*
  pulse LED with PWM

  https://forum.arduino.cc/index.php?topic=675980
  by noiasca
*/
uint32_t CMillis = 0; 
class PulseLed
{
  private :
    const byte ledPin;                       // has to be a GPIO with PWM
    uint8_t interval = 2;                   // the intervall in milliseconds for each change
    uint32_t previousMillis = 0;             // stores the last change
    uint8_t pwm = 0;                         // actual value of PWM
    uint8_t start = 0;                       // range from (lowest PWM value)
    uint8_t end =  255;                      // range to (highest PWM value
    uint8_t pulsecount = 0;
    int y =0;
    bool dir = true;
  public :
    PulseLed ( byte ledPin) :
      ledPin(ledPin)
    {}

    void begin() 
    {
      pinMode(ledPin, OUTPUT);
    }
    void setInterval(byte newInterval)
    {
      interval = newInterval;
    }

    void setRange( byte newStart, byte newEnd)
    {
      if (newEnd > newStart)
      {
        start = newStart;
        end = newEnd;
      }
    }
    void setpulsecount(byte newpulsecount)
    {
      pulsecount = newpulsecount;
    }
    
  void tick() 
{
  if ((millis() - previousMillis > interval) && (pulsecount != 0))
  {
  previousMillis = millis();
  if  (y >= start && dir == true) 
    {
    if ((y <= end -1) && (dir == true)) y = y + 1;  
    else dir = false;
    }
    else 
    {
    if ((y > start) && (dir == false)) y = y - 1;
    else dir = true;
    }
    analogWrite(ledPin, y);
    if (y == start)
    {
    pulsecount = (pulsecount - 1);
    }
  }  
}
  
};

PulseLed pulseLed[] {2, 3, 4, 5, 6, 7}; 

void setup() 
{
  Serial.begin(9600);
  for (int i = 0; i < 6; i ++)
  {  
  pulseLed[i].setRange(0, 255);   // set an individuall PWM range from ... to ...
  pulseLed[i].setInterval(1);    // set the interval/speed of pulsing
  pulseLed[i].setpulsecount(1);  // set number of times to pulse
  }
CMillis = millis();
}

void loop()
{
pulseLed[0].tick();  
if (millis() - CMillis <= 500) {return;}
pulseLed[1].tick();  
if (millis() - CMillis <= 1000) {return;}
pulseLed[2].tick();  
if (millis() - CMillis <= 1500) {return;}
pulseLed[3].tick();  
if (millis() - CMillis <= 2000) {return;}
pulseLed[4].tick();  
if (millis() - CMillis <= 2500) {return;}
pulseLed[5].tick();  
}

Now that I have gotten this far, I am goint to try to reverse them and perhaps other stuff. I have really learned a lot going through this exercise.

My goal is to be able to design wearables for my many nieces and grand nieces and friends with young ones that like ‘bling’. Part of this of course is the ability to control the flashing and pulsing of various LEDs.

Again, thanks to all who have looked in on this project and contributed.

Roger Ayotte

Thank you for the update Roger, much appreciated.

Thank you noiasca, and Perry.

I guess I will try something fromt eh example you gave noiasca, but I have run into a programming issue I cannot figure out.

First here is the whole code.

/*
  pulse LED with PWM

  https://forum.arduino.cc/index.php?topic=675980
  by noiasca
*/
bool up = true;
int sequence[] = {0, 1, 2, 3, 4, 5};
int i;
int y = 0;
uint32_t CMillis = 0; 
class PulseLed
{
  private :
    const byte ledPin;                       // has to be a GPIO with PWM
    uint8_t interval = 2;                   // the intervall in milliseconds for each change
    uint32_t previousMillis = 0;             // stores the last change
    uint8_t pwm = 0;                         // actual value of PWM
    uint8_t start = 0;                       // range from (lowest PWM value)
    uint8_t end =  255;                      // range to (highest PWM value
    uint8_t pulsecount = 0;
       int y =0;
    bool dir = true;
  public :
    PulseLed ( byte ledPin) :
      ledPin(ledPin)
    {}

    void begin() 
    {
      pinMode(ledPin, OUTPUT);
    }
    void setInterval(byte newInterval)
    {
      interval = newInterval;
    }

    void setRange( byte newStart, byte newEnd)
    {
      if (newEnd > newStart)
      {
        start = newStart;
        end = newEnd;
      }
    }
    void setpulsecount(byte newpulsecount)
    {
      pulsecount = newpulsecount;
    }
    
  void tick() 
{
  if ((millis() - previousMillis > interval) && (pulsecount != 0))
  {
  previousMillis = millis();
  if  (y >= start && dir == true) 
    {
    if ((y <= end -1) && (dir == true)) y = y + 85;  
    else dir = false;
    }
    else 
    {
    if ((y > start) && (dir == false)) y = y - 1;
    else dir = true;
    }
    analogWrite(ledPin, y);
    if (y <= start)
    {
    pulsecount = (pulsecount - 1);
    }
  }  
}
  
};

PulseLed pulseLed[] {2, 3, 4, 5, 6, 7}; 

void setup() 
{
  Serial.begin(9600);
  for (int i = 0; i < 6; i ++)
  {  
  pulseLed[i].setRange(0, 255);   // set an individuall PWM range from ... to ...
  pulseLed[i].setInterval(1);    // set the interval/speed of pulsing
  pulseLed[i].setpulsecount(1);  // set number of times to pulse
  }
CMillis = millis();
}

void loop()
{
if (up == true) {int sequence[] = {5, 4, 3, 2, 1, 0};} this does not change the element sequence
// int sequence[] = {5, 4, 3, 2, 1, 0}; if uncommented, this will run in the 'reverse' sequence
// Serial.println(sequence[0]);
pulseLed[sequence[0]].tick();  
if (millis() - CMillis <= 50) {return;}
pulseLed[sequence[1]].tick();  
if (millis() - CMillis <= 100) {return;}
pulseLed[sequence[2]].tick();  
if (millis() - CMillis <= 150) {return;}
pulseLed[sequence[3]].tick();  
if (millis() - CMillis <= 200) {return;}
pulseLed[sequence[4]].tick();  
if (millis() - CMillis <= 250) {return;}
pulseLed[sequence[5]].tick();
if (millis() - CMillis <= 775) {return;}    

for (int i = 0; i < 6; i ++)  
{
pulseLed[i].setpulsecount(1);
}    
// int sequence[] = {0, 1, 2, 3, 4, 5};
//up = false;

CMillis = millis();
}

I solved the one issue with a timer and the use of an if statement with a {return} at the end. It works, I have NO idea why.

Second

I use an array from 0-5 to select the ledpin for the tick() call. What I was attempting to do was reverse the sequence of ledpin from 0->5 to 5->0. I initialize the array as sequence{0,1,2,3,4,5} and if it runs it will run with that order. If I reassign the array to sequence{5,4,3,2,1,0} it will run in reverse.

However! I do not seem to be able to re-assign the elements of sequence{} ising an if statement block. The if up==true statement will return true if tested, but the re-assignment does not happen.

I have been puzzled by theis. Is re-assigning an array in an if statement not allowed?
any insight will be appreciated. I am convinced that if I can solve these issues I will learn something.

I will also start over using your suggested technique noiasca, and let you know how it works!

void loop()
{
if (up == true) {int sequence[] = {5, 4, 3, 2, 1, 0};} this does not change the element sequence
// int sequence[] = {5, 4, 3, 2, 1, 0}; if uncommented, this will run in the 'reverse' sequence
// Serial.println(sequence[0]);
pulseLed[sequence[0]].tick();  
if (millis() - CMillis <= 50) {return;}
pulseLed[sequence[1]].tick();  
if (millis() - CMillis <= 100) {return;}
pulseLed[sequence[2]].tick();  
if (millis() - CMillis <= 150) {return;}
pulseLed[sequence[3]].tick();  
if (millis() - CMillis <= 200) {return;}
pulseLed[sequence[4]].tick();  
if (millis() - CMillis <= 250) {return;}
pulseLed[sequence[5]].tick();
if (millis() - CMillis <= 775) {return;}    

for (int i = 0; i < 6; i ++)  
{
pulseLed[i].setpulsecount(1);
}    
// int sequence[] = {0, 1, 2, 3, 4, 5};
//up = false;

CMillis = millis();
}

long story short: you can’t “reassign” an array in that way.

you “could” do

if you have this as global

int sequence = {0, 1, 2, 3, 4, 5};

assign each value:

sequence[0] = 5;
sequence[1] = 4;
sequence[2] = 3;
sequence[3] = 2;
sequence[4] = 1;
sequence[5] = 0;

but hey, that’s what for loops are made for.

edit1:
the following example picks up the idea of trailing LEDs and heading LEDs with different PWM.

// Larson scanner with PWM
// https://forum.arduino.cc/index.php?topic=675980

#define DEBUG_UART 1

const uint8_t ledPin[] = {3, 5, 6, 9, 10, 11};  // UNO PWM pins 3, 5, 6, 9, 10, 11
const uint8_t totalNoLeds = sizeof(ledPin);

void runPattern()
{
  static uint8_t  actual = totalNoLeds;
  static uint32_t previousMillis = 0;
  const uint16_t myIntervall = 200;
  static int8_t dir = 1;
  if (millis() - previousMillis >= myIntervall)
  {
    byte newPwm[totalNoLeds];
    memset(newPwm, 0, totalNoLeds);
    if (dir == 1)
    {
      if (actual >= totalNoLeds - 1)
        dir = -1;
    }
    else if (actual <= 0)
      dir = 1;
    actual += dir;
#if DEBUG_UART
    Serial.println();
    Serial.print(actual);
    Serial.print("\t");
#endif
    //if (actual >= 2) newPwm[actual -2] = 16;                // two LEDs before
    //if (actual + 2 < totalNoLeds) newPwm[actual + 2] = 16;  // two LEDs after current LED
    if (actual >= 1) newPwm[actual - 1] = 31;                 // one LED before current LED
    if (actual + 1 < totalNoLeds) newPwm[actual + 1] = 31;    // one LED after current LED
    newPwm[actual] = 255;
    for (byte i = 0; i < totalNoLeds; i++)
    {
      analogWrite(ledPin[i], newPwm[i]);
#if DEBUG_UART
    Serial.print(newPwm[i]);
    Serial.print("\t");
#endif
    }
    previousMillis = millis();
  }
}

void setup() {
#if DEBUG_UART
  Serial.begin(115200);
#endif
  for (uint8_t i = 0; i < totalNoLeds; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  runPattern();
  // do what ever you want unblocked here
}

now you could combine this with pulsing up the main LED (actual) and let the others follow the main trailing LED/heading LED follow it.

edit2:
after watching lit. hundreds of KITT Videos on youtube, my assumptions are:
the scanner should have 8 lamps
around 4 appear to be on.
when imitating the effect with LEDs it might be better if the “first” LED isn’t lighted ab 100%
so this is my final try

// Larson scanner with PWM
// https://forum.arduino.cc/index.php?topic=675980
// https://www.youtube.com/watch?v=sCTPbokUKBQ

#define DEBUG_UART 1

const uint8_t ledPin[] = {3, 5, 6, 9, 10, 11};  // UNO PWM pins 3, 5, 6, 9, 10, 11
const uint8_t totalNoLeds = sizeof(ledPin);

void runPattern()
{
  static uint8_t  actual = totalNoLeds;
  static uint32_t previousMillis = 0;
  const uint16_t myIntervall = 200;
  static int8_t dir = 1;
  if (millis() - previousMillis >= myIntervall)
  {
    byte newPwm[totalNoLeds];
    memset(newPwm, 0, totalNoLeds);
    if (dir == 1)
    {
      if (actual >= totalNoLeds - 1)
        dir = -1;
    }
    else if (actual <= 0)
      dir = 1;
    actual += dir;
#if DEBUG_UART
    Serial.println();
    Serial.print(actual);
    Serial.print("\t");
#endif
    //if (actual >= 2) newPwm[actual -2] = 16;                  // V1 two LEDs before
    //if (actual + 2 < totalNoLeds) newPwm[actual + 2] = 16;    // V1two LEDs after current LED
    //if (actual >= 1) newPwm[actual - 1] = 31;                 // V1 one LED before current LED
    //if (actual + 1 < totalNoLeds) newPwm[actual + 1] = 31;    // V2 one LED after current LED

    if (actual - 3 * dir < totalNoLeds ) newPwm[actual - 3 * dir] = 63;
    if (actual - 2 * dir < totalNoLeds ) newPwm[actual - 2 * dir] = 127;
    if (actual - 1 * dir < totalNoLeds ) newPwm[actual - 1 * dir] = 255;
    newPwm[actual] = 200;
    for (byte i = 0; i < totalNoLeds; i++)
    {
      analogWrite(ledPin[i], newPwm[i]);
#if DEBUG_UART
      Serial.print(newPwm[i]);
      Serial.print("\t");
#endif
    }
    previousMillis = millis();
  }
}

void setup() {
#if DEBUG_UART
  Serial.begin(115200);
#endif
  for (uint8_t i = 0; i < totalNoLeds; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  runPattern();
  // do what ever you want unblocked here
}