0

led code getting stuck in loop & cycling too fast
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

led code getting stuck in loop & cycling too fast

by dionnesimone on Thu Feb 28, 2019 12:49 am

I am running led lighting with the bluefruit in a pair of my shoes. I have successfully written to my microcontroller but am having difficulty fixing some issues. If anyone could help with the code, that would be amazing.

Problem 1: The speed that my rainbow cycles are running at are way too fast. I need to slow them down.

Problem 2: Once I have entered the rainbow portions of the code, I can not get back to the first 4 modes that are controlled with the color picker.

Problem 3: I would like my sparkle mode to light more than 1 pixel at a time.

The other modes are ok. I realize that the code in them is not the best, but are running satisfactorily.

Code: Select all | TOGGLE FULL SIZE
// BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE

#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__         
#include <avr/power.h>
#include <avr/sleep.h>
#endif

#define RX_PIN    1              // Connect this pin to BLE 'TXO' pin
#define CTS_PIN   3            // Connect this pin to BLE 'CTS' pin
#define LED_PIN   2            // Connect NeoPixels to this pin
#define NUM_LEDS 73       // Number of led lights
#define FPS      30               // Animation frames/second (ish)

SoftwareSerial    ser(RX_PIN, -0);
Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN);

void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  // MUST do this on 16 MHz Trinket for serial & NeoPixels!
  clock_prescale_set(clock_div_1);
#endif
  // Stop incoming data & init software serial
  pinMode(CTS_PIN, OUTPUT); digitalWrite(CTS_PIN, HIGH);
  pixels.setBrightness(25);                                // set LED brightness here
  ser.begin(9600);

  pixels.begin();       // NeoPixel init
  // Flash space is tight on Trinket/Gemma, so setBrightness() is avoided --
  // it adds ~200 bytes.  Instead the color picker input is 'manually' scaled.
}

uint8_t  buf[3],                  // Enough for RGB parse; expand if using sensors
         animMode = 1,            // Current animation mode
         animPos  = 0;            // Current animation position
uint32_t color    = 0x400000,     // Current animation color (red by default)
         prevTime = 0L;           // For animation timing

void loop(void) {
  int      c;
  uint32_t t;

  // Animation happens at about 30 frames/sec.  Rendering frames takes less
  // than that, so the idle time is used to monitor incoming serial data.
  digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data!
  for (;;) {
    t = micros();                                // Current time
    if ((t - prevTime) >= (1000000L / FPS)) {    // 1/30 sec elapsed?
      prevTime = t;
      break;                                     // Yes, go update LEDs
    }                                            // otherwise...
    if ((c = ser.read()) == '!') {               // Received UART app input?
      while ((c = ser.read()) < 0);              // Yes, wait for command byte
      switch (c) {
        case 'B':                    // Button (Control Pad)
          if (readAndCheckCRC(255 - '!' - 'B', buf, 2) & (buf[1] == '1')) {
            buttonPress(buf[0]);      // Handle button-press message
          }
          break;
        case 'C':                   // Color Picker
          if (readAndCheckCRC(255 - '!' - 'C', buf, 3)) {
            // As mentioned earlier, setBrightness() was avoided to save space.
            // Instead, results from the color picker (in buf[]) are divided
            // by 4; essentially equivalent to setBrightness(64).  This is to
            // improve battery run time (NeoPixels are still plenty bright).
            color = pixels.Color(buf[0] / 4, buf[1] / 4, buf[2] / 4);
          }
          break;
        case 'Q':                   // Quaternion
          skipBytes(17);             // 4 floats + CRC (see note below re: parsing)
          break;
        case 'A':                   // Accelerometer
#if 0
          // The phone sensors are NOT used by this sketch, but this shows how
          // they might be read.  First, buf[] must be delared large enough for
          // the expected data packet (minus header & CRC) -- that's 16 bytes
          // for quaternions (above), or 12 bytes for most of the others.
          // Second, the first arg to readAndCheckCRC() must be modified to
          // match the data type (e.g. 'A' here for accelerometer).  Finally,
          // values can be directly type-converted to float by using a suitable
          // offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this
          // example because floating-point math uses lots of RAM and code
          // space, not suitable for the space-constrained Trinket/Gemma, but
          // maybe you're using a Pro Trinket, Teensy, etc.
          if (readAndCheckCRC(255 - '!' - 'A', buf, 12)) {
            float x = *(float *)(&buf[0]),
                  y = *(float *)(&buf[4]),
                  z = *(float *)(&buf[8]);
          }
          // In all likelihood, updates from the buttons and color picker
          // alone are infrequent enough that you could do without any mention
          // of the CTS pin in this code.  It's the extra sensors that really
          // start the firehose of data.
          break;
#endif
        case 'G':            // Gyroscope
        case 'M':            // Magnetometer
        case 'L':            // Location
          skipBytes(13);      // 3 floats + CRC
      }
    }
  }
  digitalWrite(CTS_PIN, HIGH);    // BLE STOP!

  // Show pixels calculated on *prior* pass; this ensures more uniform timing
  pixels.show();

  // Then calculate pixels for *next* frame...
  switch (animMode) {
   
    case 0:     // chasing mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + i) & 15) < 4) c = color;    //16 total pixels, 4 lit at a time
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 1:    // Sparkle mode
      pixels.setPixelColor(animPos, 0);          // Erase old dot
          animPos = random(NUM_LEDS);                // Pick a new one
             pixels.setPixelColor(animPos, color);      // and light it
      break;
     


    case 2:    //solid mode
      for(uint8_t i = 0; i < NUM_LEDS; i++) {
          uint32_t c = 0;
             if (((animPos) & 15) < 15) c = color;       // all pixels lit
                pixels.setPixelColor(   i, c);             
      }
      break;


     
    case 3:    //blinking mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + 1) & 15) < 2) c = color;   // all pixels lit
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 4:    // Up = rainbowCycle
      {
      uint16_t i, j;
         for(j=0; j<256; j++) { // cycles of all colors on wheel
            for(i=0; i< pixels.numPixels(); i++) {
               pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
      }
      pixels.show();
        }
       }   
      break;



    case 5:    // Down = theaterChaseRainbow
      {
      for(int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
         for(int q=0; q < 3; q++) {
            for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
              pixels.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      pixels.show();
     
        for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
            pixels.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
      break;

     
         
    case 6:    // left button - rainbow
      {
      uint16_t i, j;
        for(j=0; j<256; j++) {
           for(i=0; i<pixels.numPixels(); i++) {
             pixels.setPixelColor(i, Wheel((i+j) & 255));
    }
    pixels.show();
  }
}
      break;

     

     case 7:   // right button - rainbow sparkle mode
       {
       uint16_t i, j;
         for(j=0; j<256; j++) {
            for(i=0; i<pixels.numPixels(); i++) {
              if (random(pixels.numPixels()) == i)
                 pixels.setPixelColor(i,255, 255, 255);
                  else
                     pixels.setPixelColor(i, Wheel((i+j) & 255));
    }
    pixels.show();
  }
}
      break;
     
  }
}

boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
  for (int c;;) {
    while ((c = ser.read()) < 0);      // Wait for next byte
    if (!n--) return (c == sum);       // If CRC byte, we're done
    *buf++ = c;                        // Else store in buffer
    sum   -= c;                        // and accumulate sum
  }
}

void skipBytes(uint8_t n) {
  while (n--) {
    while (ser.read() < 0);
  }
}

void buttonPress(char c) {
  pixels.clear();         // Clear pixel data when switching modes (else residue)
  switch (c) {
    case '1':
      animMode = 0;       // Switch to chase mode
      break;
    case '2':
      animMode = 1;       // Switch to sparkle mode
      break;
    case '3':
      animMode = 2;       // Switch to solid mode
      break;
    case '4':
      animMode = 3;       // Switch to blinking mode
      break;
    case '5':           
      animMode = 4;       // Up = rainbowCycle
      break;
    case '6':             
      animMode = 5;        // Down = theaterChaseRainbow
      break;
    case '7':             
      animMode = 6;        // Left =
      break;
    case '8':             
      animMode = 7;        // Right = rainbowSparkle
      break;
  }
}

// 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 pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}



This shoe is running the simple buttoncycler code and is the pair I am trying to convert to BT.
https://www.instagram.com/p/BnNYhezArz3 ... _copy_link

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Thu Feb 28, 2019 3:53 am

Thank you admin for putting this in the right category. :-) Sorry about the mistake.

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by adafruit_support_bill on Thu Feb 28, 2019 7:07 am

Let's start with #2 first, since that will have the most impact on the structure of your code:
Problem 2: Once I have entered the rainbow portions of the code, I can not get back to the first 4 modes that are controlled with the color picker.

The rainbow patterns in your code consist of multiple nested 'for' loops. These take some time to complete. While they are executing, the code is not checking for bluetooth commands, so it is not responsive. You would need to send the command *precisely* at the time the pattern completes and before it starts again.

There are a few approaches to solving that problem. We have a series of guides on the subject. Part 3 deals specifically with Neopixels.

https://learn.adafruit.com/multi-taskin ... 1/overview
https://learn.adafruit.com/multi-taskin ... 2/overview
https://learn.adafruit.com/multi-taskin ... 3/overview

Following the method in the guide, you can easily address your "Problem 1" as well.

adafruit_support_bill
 
Posts: 74337
Joined: Sat Feb 07, 2009 10:11 am

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Thu Feb 28, 2019 1:15 pm

THANK YOU SO MUCH!! I will dive right in and try to get this sorted. I have to have the code corrected, components soldered and the shoe bed re-glued before midnight. lol

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Thu Feb 28, 2019 11:15 pm

Unfortunately I can't wrap my head around what I need to do to the code in time. I tried. I have to glue my shoes and clamp them in a few hours.

If anyone feels like helping a maker out in the next 3 hours with the loops and the timing, I would be eternally grateful. Once they are glued, I can't change the code and they have to be glued pretty soon.

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by oesterle on Fri Mar 01, 2019 12:04 am

Hi, Dionne!

OK, here's a modified version. I haven't tested it; only compiled to make sure there are no errors. Please hold on to your original version. Make sure you can reload your original version before trying this. No warranties on this code.

Untested code follows:
Code: Select all | TOGGLE FULL SIZE
// BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE

#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__         
#include <avr/power.h>
#include <avr/sleep.h>
#endif

#define RX_PIN    1              // Connect this pin to BLE 'TXO' pin
#define CTS_PIN   3            // Connect this pin to BLE 'CTS' pin
#define LED_PIN   2            // Connect NeoPixels to this pin
#define NUM_LEDS 73       // Number of led lights
#define FPS      30               // Animation frames/second (ish)

SoftwareSerial    ser(RX_PIN, -0);
Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN);

void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  // MUST do this on 16 MHz Trinket for serial & NeoPixels!
  clock_prescale_set(clock_div_1);
#endif
  // Stop incoming data & init software serial
  pinMode(CTS_PIN, OUTPUT); digitalWrite(CTS_PIN, HIGH);
  pixels.setBrightness(25);                                // set LED brightness here
  ser.begin(9600);

  pixels.begin();       // NeoPixel init
  // Flash space is tight on Trinket/Gemma, so setBrightness() is avoided --
  // it adds ~200 bytes.  Instead the color picker input is 'manually' scaled.
}

uint8_t  buf[3],                  // Enough for RGB parse; expand if using sensors
         animMode = 1,            // Current animation mode
         animPos  = 0;            // Current animation position
uint32_t color    = 0x400000,     // Current animation color (red by default)
         prevTime = 0L;           // For animation timing

uint8_t  animPosSet[5];
uint8_t  curJ = 0;

void loop(void) {
  int      c;
  uint32_t t;

  // Animation happens at about 30 frames/sec.  Rendering frames takes less
  // than that, so the idle time is used to monitor incoming serial data.
  digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data!
  for (;;) {
    t = micros();                                // Current time
    if ((t - prevTime) >= (1000000L / FPS)) {    // 1/30 sec elapsed?
      prevTime = t;
      break;                                     // Yes, go update LEDs
    }                                            // otherwise...
    if ((c = ser.read()) == '!') {               // Received UART app input?
      while ((c = ser.read()) < 0);              // Yes, wait for command byte
      switch (c) {
        case 'B':                    // Button (Control Pad)
          if (readAndCheckCRC(255 - '!' - 'B', buf, 2) & (buf[1] == '1')) {
            buttonPress(buf[0]);      // Handle button-press message
          }
          break;
        case 'C':                   // Color Picker
          if (readAndCheckCRC(255 - '!' - 'C', buf, 3)) {
            // As mentioned earlier, setBrightness() was avoided to save space.
            // Instead, results from the color picker (in buf[]) are divided
            // by 4; essentially equivalent to setBrightness(64).  This is to
            // improve battery run time (NeoPixels are still plenty bright).
            color = pixels.Color(buf[0] / 4, buf[1] / 4, buf[2] / 4);
          }
          break;
        case 'Q':                   // Quaternion
          skipBytes(17);             // 4 floats + CRC (see note below re: parsing)
          break;
        case 'A':                   // Accelerometer
#if 0
          // The phone sensors are NOT used by this sketch, but this shows how
          // they might be read.  First, buf[] must be delared large enough for
          // the expected data packet (minus header & CRC) -- that's 16 bytes
          // for quaternions (above), or 12 bytes for most of the others.
          // Second, the first arg to readAndCheckCRC() must be modified to
          // match the data type (e.g. 'A' here for accelerometer).  Finally,
          // values can be directly type-converted to float by using a suitable
          // offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this
          // example because floating-point math uses lots of RAM and code
          // space, not suitable for the space-constrained Trinket/Gemma, but
          // maybe you're using a Pro Trinket, Teensy, etc.
          if (readAndCheckCRC(255 - '!' - 'A', buf, 12)) {
            float x = *(float *)(&buf[0]),
                  y = *(float *)(&buf[4]),
                  z = *(float *)(&buf[8]);
          }
          // In all likelihood, updates from the buttons and color picker
          // alone are infrequent enough that you could do without any mention
          // of the CTS pin in this code.  It's the extra sensors that really
          // start the firehose of data.
          break;
#endif
        case 'G':            // Gyroscope
        case 'M':            // Magnetometer
        case 'L':            // Location
          skipBytes(13);      // 3 floats + CRC
      }
    }
  }
  digitalWrite(CTS_PIN, HIGH);    // BLE STOP!

  // Show pixels calculated on *prior* pass; this ensures more uniform timing
  pixels.show();

  // Then calculate pixels for *next* frame...
  switch (animMode) {
   
    case 0:     // chasing mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + i) & 15) < 4) c = color;    //16 total pixels, 4 lit at a time
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 1:    // Sparkle mode
//      pixels.setPixelColor(animPos, 0);          // Erase old dot
//          animPos = random(NUM_LEDS);                // Pick a new one
//             pixels.setPixelColor(animPos, color);      // and light it

      for (uint8_t i = 0; i < 5; i++) {
        pixels.setPixelColor(animPosSet[i], 0);
        animPosSet[i] = random(NUM_LEDS);
        pixels.setPixelColor(animPosSet[i], color);
      }
      pixels.show();
      break;
     


    case 2:    //solid mode
      for(uint8_t i = 0; i < NUM_LEDS; i++) {
          uint32_t c = 0;
             if (((animPos) & 15) < 15) c = color;       // all pixels lit
                pixels.setPixelColor(   i, c);             
      }
      break;


     
    case 3:    //blinking mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + 1) & 15) < 2) c = color;   // all pixels lit
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 4:    // Up = rainbowCycle
      {
      uint16_t i, j;
      j = curJ;
//         for(j=0; j<256; j++) { // cycles of all colors on wheel
            for(i=0; i< pixels.numPixels(); i++) {
               pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
      }
      pixels.show();
//        }
       }   
      break;



    case 5:    // Down = theaterChaseRainbow
      {
//      for(int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
        uint8_t j = curJ;
         for(int q=0; q < 3; q++) {
            for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
              pixels.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      pixels.show();
     
        for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
            pixels.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
//  }
}
      break;

     
         
    case 6:    // left button - rainbow
      {
      uint16_t i, j;
//        for(j=0; j<256; j++) {
          j = curJ;
         
           for(i=0; i<pixels.numPixels(); i++) {
             pixels.setPixelColor(i, Wheel((i+j) & 255));
     }
     pixels.show();
//  }
}
      break;

     

     case 7:   // right button - rainbow sparkle mode
       {
       uint16_t i, j;
//         for(j=0; j<256; j++) {
          j = curJ;
         
            for(i=0; i<pixels.numPixels(); i++) {
              if (random(pixels.numPixels()) == i)
                 pixels.setPixelColor(i,255, 255, 255);
                  else
                     pixels.setPixelColor(i, Wheel((i+j) & 255));
    }
    pixels.show();
  // }
}
      break;
     
  }

  curJ++;
}

boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
  for (int c;;) {
    while ((c = ser.read()) < 0);      // Wait for next byte
    if (!n--) return (c == sum);       // If CRC byte, we're done
    *buf++ = c;                        // Else store in buffer
    sum   -= c;                        // and accumulate sum
  }
}

void skipBytes(uint8_t n) {
  while (n--) {
    while (ser.read() < 0);
  }
}

void buttonPress(char c) {
  pixels.clear();         // Clear pixel data when switching modes (else residue)
  switch (c) {
    case '1':
      animMode = 0;       // Switch to chase mode
      break;
    case '2':
      animMode = 1;       // Switch to sparkle mode
      break;
    case '3':
      animMode = 2;       // Switch to solid mode
      break;
    case '4':
      animMode = 3;       // Switch to blinking mode
      break;
    case '5':           
      animMode = 4;       // Up = rainbowCycle
      break;
    case '6':             
      animMode = 5;        // Down = theaterChaseRainbow
      break;
    case '7':             
      animMode = 6;        // Left =
      break;
    case '8':             
      animMode = 7;        // Right = rainbowSparkle
      break;
  }
}

// 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 pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


  • The sparkle code is intended to light 5 pixels at a time in this revision.
  • The various long color changing loops – for (int j = …) – are replaced by a global curJ which is incremented once per call to loop().

Best of luck with your glam shoes. I like the build! Let us know of your progress.

Cheers,

Eric

oesterle
 
Posts: 647
Joined: Tue Sep 17, 2013 11:32 pm

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Fri Mar 01, 2019 12:23 am

oesterle, You are absolutely amazing!!!!!!!!!! <3 <3 <3 Thank you so much. I'll post some images. I am headed to Tempe, AZ for innings music festival. You have made me so stinking happy. (warranties not needed. I can always revert. I will study your changes to see where my brain was fritzing. ) I'll be able to glue before 1 am! I might even get some sleep before the flight because of your generosity.

I also have a pair of flats and stiletto heels that I am gonna put the code into. I will be sure to let you see those as well.



oesterle wrote: Hi, Dionne!

OK, here's a modified version. I haven't tested it; only compiled to make sure there are no errors. Please hold on to your original version. Make sure you can reload your original version before trying this. No warranties on this code.

Untested code follows:
Code: Select all | TOGGLE FULL SIZE
// BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE

#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__         
#include <avr/power.h>
#include <avr/sleep.h>
#endif

#define RX_PIN    1              // Connect this pin to BLE 'TXO' pin
#define CTS_PIN   3            // Connect this pin to BLE 'CTS' pin
#define LED_PIN   2            // Connect NeoPixels to this pin
#define NUM_LEDS 73       // Number of led lights
#define FPS      30               // Animation frames/second (ish)

SoftwareSerial    ser(RX_PIN, -0);
Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN);

void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  // MUST do this on 16 MHz Trinket for serial & NeoPixels!
  clock_prescale_set(clock_div_1);
#endif
  // Stop incoming data & init software serial
  pinMode(CTS_PIN, OUTPUT); digitalWrite(CTS_PIN, HIGH);
  pixels.setBrightness(25);                                // set LED brightness here
  ser.begin(9600);

  pixels.begin();       // NeoPixel init
  // Flash space is tight on Trinket/Gemma, so setBrightness() is avoided --
  // it adds ~200 bytes.  Instead the color picker input is 'manually' scaled.
}

uint8_t  buf[3],                  // Enough for RGB parse; expand if using sensors
         animMode = 1,            // Current animation mode
         animPos  = 0;            // Current animation position
uint32_t color    = 0x400000,     // Current animation color (red by default)
         prevTime = 0L;           // For animation timing

uint8_t  animPosSet[5];
uint8_t  curJ = 0;

void loop(void) {
  int      c;
  uint32_t t;

  // Animation happens at about 30 frames/sec.  Rendering frames takes less
  // than that, so the idle time is used to monitor incoming serial data.
  digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data!
  for (;;) {
    t = micros();                                // Current time
    if ((t - prevTime) >= (1000000L / FPS)) {    // 1/30 sec elapsed?
      prevTime = t;
      break;                                     // Yes, go update LEDs
    }                                            // otherwise...
    if ((c = ser.read()) == '!') {               // Received UART app input?
      while ((c = ser.read()) < 0);              // Yes, wait for command byte
      switch (c) {
        case 'B':                    // Button (Control Pad)
          if (readAndCheckCRC(255 - '!' - 'B', buf, 2) & (buf[1] == '1')) {
            buttonPress(buf[0]);      // Handle button-press message
          }
          break;
        case 'C':                   // Color Picker
          if (readAndCheckCRC(255 - '!' - 'C', buf, 3)) {
            // As mentioned earlier, setBrightness() was avoided to save space.
            // Instead, results from the color picker (in buf[]) are divided
            // by 4; essentially equivalent to setBrightness(64).  This is to
            // improve battery run time (NeoPixels are still plenty bright).
            color = pixels.Color(buf[0] / 4, buf[1] / 4, buf[2] / 4);
          }
          break;
        case 'Q':                   // Quaternion
          skipBytes(17);             // 4 floats + CRC (see note below re: parsing)
          break;
        case 'A':                   // Accelerometer
#if 0
          // The phone sensors are NOT used by this sketch, but this shows how
          // they might be read.  First, buf[] must be delared large enough for
          // the expected data packet (minus header & CRC) -- that's 16 bytes
          // for quaternions (above), or 12 bytes for most of the others.
          // Second, the first arg to readAndCheckCRC() must be modified to
          // match the data type (e.g. 'A' here for accelerometer).  Finally,
          // values can be directly type-converted to float by using a suitable
          // offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this
          // example because floating-point math uses lots of RAM and code
          // space, not suitable for the space-constrained Trinket/Gemma, but
          // maybe you're using a Pro Trinket, Teensy, etc.
          if (readAndCheckCRC(255 - '!' - 'A', buf, 12)) {
            float x = *(float *)(&buf[0]),
                  y = *(float *)(&buf[4]),
                  z = *(float *)(&buf[8]);
          }
          // In all likelihood, updates from the buttons and color picker
          // alone are infrequent enough that you could do without any mention
          // of the CTS pin in this code.  It's the extra sensors that really
          // start the firehose of data.
          break;
#endif
        case 'G':            // Gyroscope
        case 'M':            // Magnetometer
        case 'L':            // Location
          skipBytes(13);      // 3 floats + CRC
      }
    }
  }
  digitalWrite(CTS_PIN, HIGH);    // BLE STOP!

  // Show pixels calculated on *prior* pass; this ensures more uniform timing
  pixels.show();

  // Then calculate pixels for *next* frame...
  switch (animMode) {
   
    case 0:     // chasing mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + i) & 15) < 4) c = color;    //16 total pixels, 4 lit at a time
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 1:    // Sparkle mode
//      pixels.setPixelColor(animPos, 0);          // Erase old dot
//          animPos = random(NUM_LEDS);                // Pick a new one
//             pixels.setPixelColor(animPos, color);      // and light it

      for (uint8_t i = 0; i < 5; i++) {
        pixels.setPixelColor(animPosSet[i], 0);
        animPosSet[i] = random(NUM_LEDS);
        pixels.setPixelColor(animPosSet[i], color);
      }
      pixels.show();
      break;
     


    case 2:    //solid mode
      for(uint8_t i = 0; i < NUM_LEDS; i++) {
          uint32_t c = 0;
             if (((animPos) & 15) < 15) c = color;       // all pixels lit
                pixels.setPixelColor(   i, c);             
      }
      break;


     
    case 3:    //blinking mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + 1) & 15) < 2) c = color;   // all pixels lit
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 4:    // Up = rainbowCycle
      {
      uint16_t i, j;
      j = curJ;
//         for(j=0; j<256; j++) { // cycles of all colors on wheel
            for(i=0; i< pixels.numPixels(); i++) {
               pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
      }
      pixels.show();
//        }
       }   
      break;



    case 5:    // Down = theaterChaseRainbow
      {
//      for(int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
        uint8_t j = curJ;
         for(int q=0; q < 3; q++) {
            for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
              pixels.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      pixels.show();
     
        for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
            pixels.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
//  }
}
      break;

     
         
    case 6:    // left button - rainbow
      {
      uint16_t i, j;
//        for(j=0; j<256; j++) {
          j = curJ;
         
           for(i=0; i<pixels.numPixels(); i++) {
             pixels.setPixelColor(i, Wheel((i+j) & 255));
     }
     pixels.show();
//  }
}
      break;

     

     case 7:   // right button - rainbow sparkle mode
       {
       uint16_t i, j;
//         for(j=0; j<256; j++) {
          j = curJ;
         
            for(i=0; i<pixels.numPixels(); i++) {
              if (random(pixels.numPixels()) == i)
                 pixels.setPixelColor(i,255, 255, 255);
                  else
                     pixels.setPixelColor(i, Wheel((i+j) & 255));
    }
    pixels.show();
  // }
}
      break;
     
  }

  curJ++;
}

boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
  for (int c;;) {
    while ((c = ser.read()) < 0);      // Wait for next byte
    if (!n--) return (c == sum);       // If CRC byte, we're done
    *buf++ = c;                        // Else store in buffer
    sum   -= c;                        // and accumulate sum
  }
}

void skipBytes(uint8_t n) {
  while (n--) {
    while (ser.read() < 0);
  }
}

void buttonPress(char c) {
  pixels.clear();         // Clear pixel data when switching modes (else residue)
  switch (c) {
    case '1':
      animMode = 0;       // Switch to chase mode
      break;
    case '2':
      animMode = 1;       // Switch to sparkle mode
      break;
    case '3':
      animMode = 2;       // Switch to solid mode
      break;
    case '4':
      animMode = 3;       // Switch to blinking mode
      break;
    case '5':           
      animMode = 4;       // Up = rainbowCycle
      break;
    case '6':             
      animMode = 5;        // Down = theaterChaseRainbow
      break;
    case '7':             
      animMode = 6;        // Left =
      break;
    case '8':             
      animMode = 7;        // Right = rainbowSparkle
      break;
  }
}

// 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 pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


  • The sparkle code is intended to light 5 pixels at a time in this revision.
  • The various long color changing loops – for (int j = …) – are replaced by a global curJ which is incremented once per call to loop().

Best of luck with your glam shoes. I like the build! Let us know of your progress.

Cheers,

Eric

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by oesterle on Fri Mar 01, 2019 12:33 am

Glad I could help. Please test every mode before gluing. Last minute changes are risky. This is a quick-and-dirty hack.

Cheers!

oesterle
 
Posts: 647
Joined: Tue Sep 17, 2013 11:32 pm

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Fri Mar 01, 2019 2:09 am

Unfortunately it didn't work so I had to revert back to my last version. ;-(

I still very much appreciated the help.

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Mon Sep 09, 2019 12:10 pm

I am digging back into my shoe code. I've switched from using the Bluefruit friend to using the flora Bluefruit. The code gets stuck in the loop when I activate a rainbow mode.

I want to use either the rx or tx pin as an external interrupt when a button on the controller pad is pressed. I am assuming that CHANGE will be the state my interrupt will be looking for.

I am having trouble knowing where to place my interrupts because all the examples I've found are using a wired button.

If anyone could help, I would be so very grateful.

Code: Select all | TOGGLE FULL SIZE
// Bluetooth shoes tinylilly --

// Works in conjunction with Bluefruit LE Connect app on iOS or Android --
// pick colors or use buttons to select modes.
// if space is VERY tight...helps to use Arduino IDE
// 1.6.4 or later; produces slightly smaller code than the 1.0.X releases.

// BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE

#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__         
#endif

#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"

#define RX_PIN    2            // Connect this pin to BLE 'TX' pin
#define TX_PIN    1            // Connect this pin to BLE 'RX' pin 2
#define LED_PIN   3            // Connect NeoPixels to this pin
#define NUM_LEDS 73            // Number of led lights
#define FPS      30            // Animation frames/second (ish)
#define CTS_PIN  -1            // Connect this pin to BLE 'CTS' pin
#define RTS_PIN  -1
#define BLUEFRUIT_UART_MODE_PIN -1


SoftwareSerial    ser(RX_PIN, -0);
Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN);

void setup()
{
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
             // MUST do this on 16 MHz Trinket for serial & NeoPixels!
  clock_prescale_set(clock_div_1);
#endif

            // Stop incoming data & init software serial
 
  pinMode(CTS_PIN, OUTPUT);
    digitalWrite(CTS_PIN, HIGH);

  //pinMode(interruptPin, INPUT);
  //interrupts();
  //attachInterrupt(digitalPinToInterrupt(RX_PIN, Update, CHANGE); 
  //void Update();
  //pixels.Update(animMode);
  //detachInterrupt();
   
  pixels.setBrightness(25);
  ser.begin(9600);
  pixels.begin();       // NeoPixel init
 
}

uint8_t  buf[3],                  // Enough for RGB parse; expand if using sensors
         animMode = 1,            // Current animation mode
         animPos  = 0;            // Current animation position
uint32_t color    = 0x400000,     // Red default
         prevTime = 0L;           // For animation timing

void loop(void) {
  int      c;
  uint32_t t;

          // Animation happens at about 30 frames/sec.  Rendering frames takes less
         // than that, so the idle time is used to monitor incoming serial data.
 
  digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data!
 
  for (;;) {
    t = micros();                                // Current time
    if ((t - prevTime) >= (1000000L / FPS)) {    // 1/30 sec elapsed?
      prevTime = t;
      break;                                     // Yes, go update LEDs
    }                                            // otherwise...
    if ((c = ser.read()) == '!') {               // Received UART app input?
      while ((c = ser.read()) < 0);              // Yes, wait for command byte
     
      switch (c) {
        case 'B':                    // Button (Control Pad)
          if (readAndCheckCRC(255 - '!' - 'B', buf, 2) & (buf[1] == '1')) {
            buttonPress(buf[0]);      // Handle button-press message
          }
          break;
         
        case 'C':                   // Color Picker
          if (readAndCheckCRC(255 - '!' - 'C', buf, 3)) {
            // As mentioned earlier, setBrightness() was avoided to save space.
            color = pixels.Color(buf[0] / 4, buf[1] / 4, buf[2] / 4);
          }
          break;
         
        case 'Q':                   // Quaternion
          skipBytes(17);             // 4 floats + CRC (see note below re: parsing)
          break;
         
        case 'A':                   // Accelerometer
#if 0
          // The phone sensors are NOT used by this sketch, but this shows how
          // they might be read.  First, buf[] must be delared large enough for
          // the expected data packet (minus header & CRC) -- that's 16 bytes
          // for quaternions (above), or 12 bytes for most of the others.
          // Second, the first arg to readAndCheckCRC() must be modified to
          // match the data type (e.g. 'A' here for accelerometer).  Finally,
          // values can be directly type-converted to float by using a suitable
          // offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this
          // example because floating-point math uses lots of RAM and code
          // space, not suitable for the space-constrained Trinket/Gemma, but
          // maybe you're using a Pro Trinket, Teensy, etc.
         
          if (readAndCheckCRC(255 - '!' - 'A', buf, 12)) {
            float x = *(float *)(&buf[0]),
                  y = *(float *)(&buf[4]),
                  z = *(float *)(&buf[8]);
          }
         
          // In all likelihood, updates from the buttons and color picker
          // alone are infrequent enough that you could do without any mention
          // of the CTS pin in this code.  It's the extra sensors that really
          // start the firehose of data.
         
          break;
         
#endif
        case 'G':            // Gyroscope
        case 'M':            // Magnetometer
        case 'L':            // Location
          skipBytes(13);      // 3 floats + CRC
      }
    }
  }
 
  digitalWrite(CTS_PIN, HIGH);    // BLE STOP!

  // Show pixels calculated on *prior* pass; this ensures more uniform timing
  pixels.show();

  // Then calculate pixels for *next* frame...
  switch (animMode) {
   
    case 0:     // chasing mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + i) & 15) < 4) c = color;    //16 total pixels, 4 lit at a time
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 1:    // Sparkle mode
      pixels.setPixelColor(animPos, 0);          // Erase old dot
          animPos = random(NUM_LEDS);                // Pick a new one
             pixels.setPixelColor(animPos, color);      // and light it
      break;
     


    case 2:    //solid mode
      for(uint8_t i = 0; i < NUM_LEDS; i++) {
          uint32_t c = 0;
             if (((animPos) & 15) < 15) c = color;       // all pixels lit
                pixels.setPixelColor(   i, c);             
      }
      break;


     
    case 3:    //blinking mode
      for(uint8_t i = 0; i < NUM_LEDS / 1; i++) {
          uint32_t c = 0;
             if (((animPos + 1) & 15) < 2) c = color;   // all pixels lit
                pixels.setPixelColor(   i, c);
      }
      animPos++;
      break;


     
    case 4:    // Up = rainbowCycle
      {
      uint16_t i, j;
         for(j=0; j<256; j++) { // cycles of all colors on wheel
            for(i=0; i< pixels.numPixels(); i++) {
               pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
      }
      pixels.show();
        }
       }
      break;



    case 5:    // Down = theaterChaseRainbow
     {
      for(int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
         for(int q=0; q < 3; q++) {
            for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
              pixels.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      pixels.show();
     
        for(uint16_t i=0; i < pixels.numPixels(); i=i+3) {
            pixels.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
     
      break;

     
         
    case 6:    // left button - rainbow
      {
      uint16_t i, j;
        for(j=0; j<256; j++) {
           for(i=0; i<pixels.numPixels(); i++) {
             pixels.setPixelColor(i, Wheel((i+j) & 255));
    }
    pixels.show();
  }
}
     
      break;

     

     case 7:   // right button - rainbow sparkle mode
       {
       uint16_t i, j;
         for(j=0; j<256; j++) {
            for(i=0; i<pixels.numPixels(); i++) {
              if (random(pixels.numPixels()) == i)
                 pixels.setPixelColor(i,255, 255, 255);
                  else
                     pixels.setPixelColor(i, Wheel((i+j) & 255));
    }
    pixels.show();
  }
}
     
      break;
     
  }
}

boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
  for (int c;;) {
    while ((c = ser.read()) < 0);      // Wait for next byte
    if (!n--) return (c == sum);       // If CRC byte, we're done
    *buf++ = c;                        // Else store in buffer
    sum   -= c;                        // and accumulate sum
  }
}

void skipBytes(uint8_t n) {
  while (n--) {
    while (ser.read() < 0);
  }
}

void buttonPress(char c) {
  pixels.clear();         // Clear pixel data when switching modes (else residue)
  switch (c) {
    case '1':
      animMode = 0;       // Switch to chase mode
      break;
    case '2':
      animMode = 1;       // Switch to sparkle mode
      break;
    case '3':
      animMode = 2;       // Switch to solid mode
      break;
    case '4':
      animMode = 3;       // Switch to blinking mode
      break;
    case '5':           
      animMode = 4;       // Up = rainbowCycle
      break;
    case '6':             
      animMode = 5;        // Down = theaterChaseRainbow
      break;
    case '7':             
      animMode = 6;        // Left =
      break;
    case '8':             
      animMode = 7;        // Right = rainbowSparkle
      break;
  }
}

             // 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 pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by adafruit_support_bill on Mon Sep 09, 2019 12:42 pm

"CHANGE" will interrupt whenever the state changes - either from low to high or from high to low. That will give you 2 interrupts per button press.

If you want to cause a single interrupt whenever a button is pressed:
* wire the button between the interrupt pin and GND.
* Enable internal pullups for the pin via "pinmode"
* Attach to the interrupt using "FALLING" mode.

Note that interrupts are disabled during calls to pixels.show();

adafruit_support_bill
 
Posts: 74337
Joined: Sat Feb 07, 2009 10:11 am

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Mon Sep 09, 2019 1:48 pm

I understand why there will be 2 interrupts with CHANGE. Thanks. :-)

I think I understand the input pullups. again thank you! :-)

I don't understand the button wire to ground. If I were adding an additional momentary switch button, I understand doing this.

Could you elaborate for me? If I use my pin 2 that is assigned as my RX_PIN on my micro controller, and is my TX_PIN on my flora Bluefruit, how would my wiring be edited?

adafruit_support_bill wrote:"CHANGE" will interrupt whenever the state changes - either from low to high or from high to low. That will give you 2 interrupts per button press.

If you want to cause a single interrupt whenever a button is pressed:
* wire the button between the interrupt pin and GND.
* Enable internal pullups for the pin via "pinmode"
* Attach to the interrupt using "FALLING" mode.

Note that interrupts are disabled during calls to pixels.show();

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by adafruit_support_bill on Mon Sep 09, 2019 2:01 pm

If you are attempting to trigger it via the Bluefruit, the Bluefruit is sending serial data at 8 bits per character. So there will be a whole lot of changes when you press the button.

adafruit_support_bill
 
Posts: 74337
Joined: Sat Feb 07, 2009 10:11 am

Re: led code getting stuck in loop & cycling too fast

by dionnesimone on Mon Sep 09, 2019 2:23 pm

I can see what you are saying about numerous changes but don't know what to do to solve this issue.

adafruit_support_bill wrote:If you are attempting to trigger it via the Bluefruit, the Bluefruit is sending serial data at 8 bits per character. So there will be a whole lot of changes when you press the button.

dionnesimone
 
Posts: 25
Joined: Wed Feb 27, 2019 9:37 pm

Re: led code getting stuck in loop & cycling too fast

by adafruit_support_bill on Mon Sep 09, 2019 2:58 pm

One approach you can try is to just set a boolean flag in your interrupt handler and check for the flag in your main loop. When you detect the flag in your loop, do what you need to do then reset it.

It won't matter if the flag gets set a dozen times before the loop comes around. It will just do what it needs to do then reset it.

adafruit_support_bill
 
Posts: 74337
Joined: Sat Feb 07, 2009 10:11 am

Please be positive and constructive with your questions and comments.