Stuck in a loop, problems troubleshooting!

Hey!

I recently posted a problem concerning arrays and matrixes using neopixels, and although that problem was solved, I’ve now run into some other problems.

I would like to display a core consisting of multiple pixels using an Adafruit neopixel strip array, with a “feathered” border around, i.e neopixels lighting up with half brightness. I am positive I’ve gotten lost in the code somewhere, but I’m having some trouble pinpointing exactly where.

The code is as follows:

#include <Adafruit_NeoPixel.h>

#define pixelPin 6
#define buttonPin 7

#define numPixels 80
#define stripLength 20

int feather[] = { -stripLength, -1, 1, stripLength};

int buttonState;
int prevState;

long fadeStamp;
int fadeSpeed = 50;

int currentPixel;

int hPixel;
int wPixel;
int fPixel;

int red;
int grn;
int blu;

int n = 0;
int m = 0;

int Width;
int Height;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixels, pixelPin, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show();
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}

void loop() {

  Width = 2; Height = 3;
  red = 0; grn = 255; blu = 0;
  
  buttonState = digitalRead(buttonPin);

  if (buttonState != prevState) {
    prevState = buttonState;
    fadeStamp = millis();
    if (buttonState == HIGH) {
      n = 0; m = 0;
      currentPixel = random(numPixels);
    }
  } else {
    if (buttonState == LOW) fadePixels();
    else allOn();
  }
  delay(20);
}

void allOn() {
  if (millis() - fadeStamp > 30) {
    fadeStamp = millis();
    if (++n >= 8) n = 8;
    if (++m >= 7) m = 7;

    for (int w = 0; w < Width; w++) {
      wPixel = currentPixel + (w * stripLength);
      
      for (int h = 0; h < Height; h++) {
        hPixel = wPixel + h;

        strip.setPixelColor(hPixel, FadeUp(n));

        for (int f = 0; f < (sizeof(feather) / sizeof(int)); f++) {
          fPixel = hPixel + feather[f];

          if (strip.getPixelColor(fPixel) == 0) {
            strip.setPixelColor(fPixel, FadeUp(m));
          }
        }
      }
    }
    strip.show();
  }
}

void fadePixels() {
  if (millis() - fadeStamp > fadeSpeed) {
    fadeStamp = millis();
    for (int i = 0; i < numPixels; i++) {
      strip.setPixelColor(i, FadeDown(strip.getPixelColor(i)));
    }
    strip.show();
  }
}

uint32_t FadeDown(uint32_t color) {
  uint32_t dimColor = strip.Color(
                        ((color >> 16) & 0xFF) >> 1,
                        ((color >> 8) & 0xFF) >> 1,
                        ((color & 0xFF) >> 1));
  return dimColor;
}

uint32_t FadeUp(uint32_t x) {

  uint32_t RED = (red ? (1 << x) - 1 : 0);
  uint32_t GRN = (grn ? (1 << x) - 1 : 0);
  uint32_t BLU = (blu ? (1 << x) - 1 : 0);

  uint32_t dimColor = strip.Color(RED, GRN, BLU);
  return dimColor;
}

The “core” dims up quite nicely, but the “feather” barely lights up.

Hopefully there’s an obvious error, say a loop that conflicts with something, but I’ve kinda worked myself blind on this one.

Any input is highly appreciated.

int buttonState;
int prevState;

What values will actually be stored in these variables? Do you really need to be able to store a range of values from -32768 to 32767 in order to hold 0 or 1?

int n = 0;
int m = 0;

One letter names are rarely meaningful. What do these names mean? Why are they global?

The “core” dims up quite nicely, but the “feather” barely lights up.

In what function? Why can’t I guess that from the names?

There are no comments in the code that describe what the code is supposed to be doing.

I suggest that you get rid of the button (actually switch) crap for now, and just make the effect work, with meaningfully named, properly debugged, adequately commented functions. Then, you can integrate that code into the main program, when you know that it all works.

First thing I notice is the total lack of documentation (comments) in your code. Please add comments as to what function are supposed to do so that we have a bit of an idea.

Other point is long fadeStamp; you store the result of millis() in there which is an unsigned long. And next you use something like if (millis() - fadeStamp > 30). It can be the root cause of timing isues (if that is your problem). Check your code for more of those inconsistencies.

Alright, so I’ve changed a couple of the things you pointed out. Comments were lacking because I did a quick cleanup of the code before posting it, and never thought of adding them again, sorry about that.

As for timing issues, there are none what so ever, as far as I’ve noticed.

The button works fine, only reason it’s there is to activate/deactivate dimming, which is crucial to the further work on the code.

int n = 0;
int m = 0;

These are global because they are increased in the allOn() function, and reset in the loop(). In essence,

if (millis() - fadeStamp > 30) {    // refresh rate before next step in fade
    fadeStamp = millis();
    
    if (++coreInc >= 8) coreInc = 8;        // writing increments to core dimming
    if (++featherInc >= 7) featherInc = 7;  // writing increments to feather dimming

    for (uint16_t width = 0; width < Width; width++) {              // calculating core width
      uint8_t widthPixel = currentPixel + (width * stripLength);    // finding next pixel on parallel strip
      
      for (uint16_t height = 0; height < Height; height++) {        // calculating core height
        uint8_t corePixel = widthPixel + height;                    // finding next pixel on same strip

        strip.setPixelColor(corePixel, FadeUp(coreInc));            // writing to core pixels
  
        for (uint8_t feather = 0; feather < (sizeof(featherArray) / sizeof(int)); feather++) {   // establishing feather pixels
          uint8_t featherPixel = corePixel + featherArray[feather];                              // calculating feather pixels from each core pixel
          
          if (strip.getPixelColor(featherPixel) == 0) {             // is the potential feather pixel in use?
            strip.setPixelColor(featherPixel, FadeUp(featherInc));  // if no, write feather
          }
        }
      }
    }
    strip.show();    // show the active pixels
  }
}

everything in here works fine, both before and after looking at the inconsistencies, except for

for (uint8_t feather = 0; feather < (sizeof(featherArray) / sizeof(int)); feather++) {   // establishing feather pixels
          uint8_t featherPixel = corePixel + featherArray[feather];                              // calculating feather pixels from each core pixel
          
          if (strip.getPixelColor(featherPixel) == 0) {             // is the potential feather pixel in use?
            strip.setPixelColor(featherPixel, FadeUp(featherInc));  // if no, write feather
          }
        }

this part.

I’ve now changed some of the names, so I’m posting the whole edited script here as well:

#include <Adafruit_NeoPixel.h>

#define pixelPin 6
#define buttonPin 7

#define numPixels 80
#define stripLength 20

int featherArray[] = { -stripLength, -1, 1, stripLength};

boolean buttonState;
boolean prevState;

unsigned long fadeStamp;
uint16_t fadeSpeed = 50;

uint16_t currentPixel;

uint16_t red;
uint16_t grn;
uint16_t blu;

uint8_t coreInc = 0;
uint8_t featherInc = 0;

uint16_t Width;
uint16_t Height;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixels, pixelPin, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show();
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}

void loop() {

  Width = 2; Height = 3;        // writable to keep open for input
  red = 0; grn = 255; blu = 0;  // writable to keep open for input
  
  buttonState = digitalRead(buttonPin);

  if (buttonState != prevState) {    // reading button
    prevState = buttonState;
    fadeStamp = millis();
    if (buttonState) {
      coreInc = 0; featherInc = 0;       // on click, reset core- and feather increments,
      currentPixel = random(numPixels);  // and assign currentPixel a random value
    }
  } else {
    if (!buttonState) fadePixels();      // on release, fade all pixels down
    else allOn();                        // on hold, fade pixels up
  }
  delay(20);
}

void allOn() {
  if (millis() - fadeStamp > 30) {    // refresh rate before next step in fade
    fadeStamp = millis();
    
    if (++coreInc >= 8) coreInc = 8;        // writing increments to core dimming
    if (++featherInc >= 7) featherInc = 7;  // writing increments to feather dimming

    for (uint16_t width = 0; width < Width; width++) {              // calculating core width
      uint8_t widthPixel = currentPixel + (width * stripLength);    // finding next pixel on parallel strip
      
      for (uint16_t height = 0; height < Height; height++) {        // calculating core height
        uint8_t corePixel = widthPixel + height;                    // finding next pixel on same strip

        strip.setPixelColor(corePixel, FadeUp(coreInc));            // writing to core pixels
  
        for (uint8_t feather = 0; feather < (sizeof(featherArray) / sizeof(int)); feather++) {   // establishing feather pixels
          uint8_t featherPixel = corePixel + featherArray[feather];                              // calculating feather pixels from each core pixel
          
          if (strip.getPixelColor(featherPixel) == 0) {             // is the potential feather pixel in use?
            strip.setPixelColor(featherPixel, FadeUp(featherInc));  // if no, write feather
          }
        }
      }
    }
    strip.show();    // show the active pixels
  }
}

void fadePixels() {    // start fade down snippet
  if (millis() - fadeStamp > fadeSpeed) {
    fadeStamp = millis();
    for (uint16_t i = 0; i < numPixels; i++) {    //include all pixels in the matrix
      strip.setPixelColor(i, FadeDown(strip.getPixelColor(i)));
    }
    strip.show();
  }
}

uint32_t FadeDown(uint32_t color) {    // fading down
  uint32_t RED = ((color >> 16) & 0xFF) >> 1;
  uint32_t GRN = ((color >> 8) & 0xFF) >> 1;
  uint32_t BLU = (color & 0xFF) >> 1;
  uint32_t dimColor = strip.Color(RED, GRN, BLU);
  return dimColor;
}

uint32_t FadeUp(uint32_t x) {      // fading up
  uint32_t RED = (red ? (1 << x) - 1 : 0);
  uint32_t GRN = (grn ? (1 << x) - 1 : 0);
  uint32_t BLU = (blu ? (1 << x) - 1 : 0);
  uint32_t dimColor = strip.Color(RED, GRN, BLU);
  return dimColor;
}

Hope this clarified some of the issues.

flaggermann:
I would like to display a core consisting of multiple pixels using an Adafruit neopixel strip array, with a "feathered" border around, i.e neopixels lighting up with half brightness. I am positive I've gotten lost in the code somewhere, but I'm having some trouble pinpointing exactly where.

can you describe again what you are trying to do?
You have a 20 pixel strip... Are trying to create a single max bright pixel and the rest of the pixels appear to fade towards zero?

Hard to understand.

Sorry, it's a matrix of neopixel strips, four strips in total, 20 pixels per strip. I want a "core" of say 2x3 pixels at full brightness, while the adjacent rows on all sides of the core light up at, say half brightness. As of right now, the core lights up just fine, but the "feather" rows, if you will, seem to cut the fading off too soon.

lit up like this:

- = Not Lit
h = Half brite
f = full brite

----------hh--------
--------hhffhh------
--------hhfhh-------
----------h---------

Yeah, sort of. Specifically, in this example, more like:

----hhh-------------
---hfffh------------
---hfffh------------
----hhh-------------

Also, removing this snippet,

if (strip.getPixelColor(featherPixel) == 0) {             // is the potential feather pixel in use?
  strip.setPixelColor(featherPixel, FadeUp(featherInc));  // if no, write feather
}

gets me this:

----hhh-------------
---hhhfh------------
---hhhhh------------
----hhh-------------

if that can point anyone in any direction...

flaggermann:
Yeah, sort of. Specifically, in this example, more like:

----hhh-------------

---hfffh------------
---hfffh------------
----hhh-------------

Always centered vertically?

You want to move (that looks like an eye or a target) horizontally?

Man, communicating an idea is friggin hard! Sorry, it's all so clear to me.

I want to move it across, along and diagonally over the strips, so no, it's not always centered.

everything in here works fine, both before and after looking at the inconsistencies, except for

A decent explanation of what that code does, and how that differs from what you want is in order.

There are no Serial.print() statements, so one can only assume that the loop iterates the proper number of times. Personally, I'm not willing to make that assumption.

We can only assume that the correct value if computed for featherPixel. Personally, I'm not willing to make that assumption.

I think you can see where this is going. You have the hardware. We don't. You can see what the hardware is actually doing. We can't. You know what you want the hardware to do. We don't. Only you are going to be able to debug the code unless you share a lot more information (that you don't necessarily have now).

flaggermann:
Man, communicating an idea is friggin hard! Sorry, it’s all so clear to me.

I want to move it across, along and diagonally over the strips, so no, it’s not always centered.

you can work with this:

it fills an array with what I think you want. It rolls over from top/bottom and left/right, not sure if you wanted that.

#define NUM_COLUMNS 20
#define NUM_ROWS 4

byte myPixels [NUM_ROWS][NUM_COLUMNS] = {0};

byte randomColumn = 0;
byte randomRow = 0;
byte index = 0;

void setup()
{
    Serial.begin(9600);
    Serial.println("*");;
    delay(1000);
}

void loop()
{
  //random placement
  //randomColumn = random(NUM_COLUMNS);
  //randomRow = random(NUM_ROWS);
  
  //top left to lower right placement
  randomColumn = index;
  randomRow = map(index++,0,NUM_COLUMNS,1,NUM_ROWS);
  if(index >= NUM_COLUMNS) index = 0;
  
  makeTarget(randomColumn, randomRow);
  printMatrix();
  Serial.println("*");
  delay(1000);
}

void makeTarget(byte column, byte row)
{
  for(byte j = 0; j < NUM_ROWS; j++)  // clear the entire array
  {
    for(byte i = 0; i < NUM_COLUMNS; i++)
    {
      myPixels[j][i] = 0;
    }
  }
  byte newPixelColumn = 0;
  for(byte j = 0; j < 5; j++)
  {
    myPixels[row][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn] = (j==0||j==4)? 1 : 2;
    if(row > 0) myPixels[row - 1][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn] = (j==0||j==4)? 0 : 1;
    else myPixels[3][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn] = (j==0||j==4)? 0 : 1;
    if(row < 2) myPixels[row + 2][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn] = (j==0||j==4)? 0 : 1;
    else if(row == 3) myPixels[1][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn] = (j==0||j==4)? 0 : 1;
    else myPixels[0][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn] = (j==0||j==4)? 0 : 1;
    myPixels[row + 1 < NUM_ROWS ? row + 1 : 0][(column + j <= NUM_COLUMNS-1)? (column + j) : newPixelColumn++] = (j==0||j==4)? 1 : 2;
  }         
}

void printMatrix(void)
{
  for(byte j = 0; j < NUM_ROWS; j++)
  {
    for(byte i = 0; i < NUM_COLUMNS; i++)
    {
      Serial.print(myPixels[j][i]);
    }
    Serial.println();
  }
}

see if it does what you want on the serial monitor…

BulldogLowell:
see if it does what you want on the serial monitor...

BulldogLowell, thank you so much for all your time and goodwill!!
Your script did do exactly what I wanted, but it deemed harder to implement with the rest of my script than actually rewriting my own, which I ended up doing anyhow and realized what I had done wrong, so now it's all good. It seems the 'feather pixels' only wrote to 'empty' pixels, so after the first step of the dimming up, since the pixel was no longer blank, the dimming would logically stop. I've just been really busy lately, and completely forgot to post here.

Just came back now to thank you basically.