Search code examples
arduinoesp32neopixel

Frustrating Arduino Question - Loops and Cases


I'm using the Arduino IDE to program an ESP32, I'm having a bit of a frustrating problem. I'm using a neopixel ring (adafruit clone).

I've used the adafruit neopixel demo snippets and they work fine. Now I'm trying to hack it apart.

What I would like to do is listen to the serial port, and then change the pattern of the neopixel ring depending on the result. Please see code below - excuse the mess... i've been busy bodging copy and pasting :)

#include <Adafruit_NeoPixel.h>
#define LED_PIN    4
#define LED_COUNT 16
String inputString = "";
String controlstring = "";
int ledrange = 0;
bool stringComplete = false;

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);
  strip.begin();
  strip.setBrightness(20);
  strip.show(); // Initialize all pixels to 'off'
 // rainbow();
}

void loop() {
  switch (ledrange){
    case 0:
      Serial.println("firing case 0");
      rainbow();
      break;
    case 1:
      Serial.println("firing case 1");
      colorWipe(strip.Color(  0,   0, 255), 50); // Blue
      break; 
  }
}

void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow() {
  // Hue of first pixel runs 5 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
  // means we'll make 5*65536/256 = 1280 passes through this loop:
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
    // strip.rainbow() can take a single argument (first pixel hue) or
    // optionally a few extras: number of rainbow repetitions (default 1),
    // saturation and value (brightness) (both 0-255, similar to the
    // ColorHSV() function, default 255), and a true/false flag for whether
    // to apply gamma correction to provide 'truer' colors (default true).
    strip.rainbow(firstPixelHue);
    // Above line is equivalent to:
    // strip.rainbow(firstPixelHue, 1, 255, 255, true);
    strip.show(); // Update strip with new contents
    delay(10);  // Pause for a moment
  }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
 
void serialEvent() {
  inputString = "";
  ledrange = 0;
  while (Serial.available()) {
       char inChar = (char)Serial.read();
       inputString += inChar;
    
        if (inChar == '\n') {
     stringComplete = true;
      controlstring = inputString;
     
      ledrange = inputString.toInt();
      Serial.println(ledrange);
    }
   }
}

It does kind of work.... I say kind of because it's not really working that well at all. It is very slow to switch, mainly when it's running the rainbow animation. It also sometimes misses a switch.... I believe this is probably because the animation is looping, there is a delay in there.

I'm not too familiar with arduino... the setup and loop is new to me. What I wanted ideally was an event handler to listen to the serial port, but it appears that I have to poll it continuously? Is this true? Even this serialevent() appears to run every time after the main loop.

If I used micropython instead does this work in a more similar way to programming .net apps in visual studio - my comfort area... well relatively speaking.

Thanks

Andrew


Solution

  • Following my comment - here's an example of what you could do to improve the code timing.

    I'm using classes to group any variables you need for each pattern together.

    You could even derive these from a common class with doLoop() as a virtual function to make the loop() code simpler, but I've tried not to change your original code too much.

    The colour sweep is quite quick, so I've left that as a loop - but you could change that to be similar to the rainbow code.

    Hopefully this will give you an idea of the sort of thing you need to do when running responsive arduino code.

    #include <Adafruit_NeoPixel.h>
    #define LED_PIN    4
    #define LED_COUNT 16
    String inputString = "";
    String controlstring = "";
    int ledrange = 0;
    bool stringComplete = false;
    
    Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
    
    class Rainbow {
      
      private:
        long firstPixelHue = 0 ; 
      
      public: 
        void doLoop() {
          strip.rainbow(firstPixelHue);
          strip.show();
          
          firstPixelHue += 256;
          if ( firstPixelHue >= 5*65536 ) {
            firstPixelHue = 0 ;
          }
          delay(10); 
        }
    }; 
    
    class ColorWipe {
      private:
         uint32_t color ;
         int wait ;
      
      public:
      
         ColorWipe(uint32_t color_p, int wait_p) : color(color_p), wait(wait_p) {
         }
      
      void doLoop() {
        // Clear leds before the sweep. 
        strip.fill(0);
        strip.show();
        delay(wait); 
        // This loop is quite quick, so let it run to completion each time. 
        for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
          strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
          strip.show();                          //  Update strip to match
          delay(wait);                           //  Pause for a moment
        }
      }
    }; 
    
    ColorWipe colorWipePattern(strip.Color(0,0,255), 50); 
    Rainbow rainbowPattern ;
    
    void setup() {
      Serial.begin(115200);
      strip.begin();
      strip.setBrightness(20);
      strip.show(); // Initialize all pixels to 'off'
     // rainbow();
    }
    
    void loop() {
    
      switch (ledrange){
        case 0:
          Serial.println("firing case 0");
          rainbowPattern.doLoop() ;
          break;
        case 1:
          Serial.println("firing case 1");
          colorWipePattern.doLoop() ;
          break; 
      }
    }
    
    uint32_t Wheel(byte WheelPos) {
      WheelPos = 255 - WheelPos;
      if(WheelPos < 85) {
        return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
      }
      if(WheelPos < 170) {
        WheelPos -= 85;
        return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
      }
      WheelPos -= 170;
      return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
    }
     
    void serialEvent() {
      inputString = "";
      ledrange = 0;
      while (Serial.available()) {
           char inChar = (char)Serial.read();
           inputString += inChar;
        
            if (inChar == '\n') {
         stringComplete = true;
          controlstring = inputString;
         
          ledrange = inputString.toInt();
          Serial.println(ledrange);
        }
       }
    }