Project For Disabled child

Hi Everyone

I am a newbie and have little understand of Arduino but I think its achievable what I want to do.

I want a FastLED effect to activate when a button pushed and then for it to stop after a few seconds and then if the button push again for it to repeat the same effect.

I don't even know where to start. I have installed all the libraries and I can get the WS2811 to run an effect but I don't know how to run if a pin goes high and carry on going when I let go of the button.

This project is for a disabled child as I want it LEDS to do something when button pushed but then stop so they have to push the button again.

I am hoping this is simple enough to do but I only started learning Arduino a few weeks ago

Thanks in advance

Mark

but I don't know how to run if a pin goes high and carry on going when I let go of the button.

When the button is pressed set a Boolean variable to true, call it say running. Also make a note of the time this happened by using the millis() function to record the time now.

Then if the variable running is true run the pattern.

Then test if the time now minus the time you started is greater than the time interval you want the display to run then set this running variable to false.

You make use iPod the if structure, look it up on the reference page in the help menu.

Any bits you don’t understand then ask about them.

check the examples:

  1. Digital | Button
  2. Digital | BlinkWithoutDelay

and the strandtest of the neopixel library.

You might end up with something like following.
I'm not using the fastled, but the Adafruit library

// Switch on one Pixel in a random color for a predefined time

#include <Adafruit_NeoPixel.h>

const int buttonPin = 2;              // a button connected from this pin to GND
const int ledPin = 6;                 // the pin where the pixels are connected
const byte ledCount = 1;              // How many NeoPixels are attached to the Arduino?
const unsigned long durance = 1000;   // on time in milliseconds
unsigned long lastMillis;             // stores the timestamp when the button gets pressed
bool isOn = false;                    // stores if the pixel is currently on (... if the effect runs)

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);   // if you don't have external resistors use the internal pullups with reversed logic
  strip.begin();                      // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();                       // Turn OFF all pixels ASAP
  strip.setBrightness(50);            // Set BRIGHTNESS to about 1/5 (max = 255)
  randomSeed(analogRead(0));          // recommended if you use random function
  Serial.begin(115200);               // for debug purposes we need the serial monitor
  Serial.println(F("wait for button press"));
}

void loop() {
  if (!digitalRead(buttonPin) && !isOn)                             // check for button press to GND (inversed - therefore the !)
  {
    Serial.println(F("Switch on by button press"));
    strip.setPixelColor(0, random(256), random(256), random(128));  // Random colors with less blue or any other pattern. You will need a slightly different logic if the pattern should change during the "showtime"
    strip.show();
    isOn = true;
    lastMillis = millis();
  }

  if (millis() - lastMillis >= durance && isOn )
  {
    Serial.println(F("Switch off by time"));
    strip.setPixelColor(0, 0);
    strip.show();
    isOn = false;
  }
}

thanks for the code.. Sorry for delay replying. Its been a busy week for me.

I have managed to work out what is what and get it to work.

I want to be able to set an effect running from a library where about would I put this in the sketch?

Many thanks

I want to be able to set an effect running from a library where about would I put this in the sketch?

If you just want to set off an effect then you put the code for the effect at the end of the sketch and call it in the loop function.

However, if you want this effect to be interruptible like the code in reply #2, then the effect has to be rewritten to be capable of using that technique.

This means removing all delays, or at least delays longer than about 100mS, and "unrolling" any for loop structures. This example shows how these effects are unrolled. The effects are all the basic ones you get in the Adafruit examples, so look at them and compare them to how I have implemented it here.

// StrandTest from AdaFruit implemented as a state machine
// pattern change by push button
// By Mike Cook Jan 2016
// Fade function added Sept 2017

#define PINforControl   4 // pin connected to the small NeoPixels strip
#define NUMPIXELS1      64 // number of LEDs on strip

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS1, PINforControl, NEO_GRB + NEO_KHZ800);

unsigned long patternInterval = 20 ; // time between steps in the pattern
unsigned long lastUpdate = 0 ; // for millis() when last update occurred
unsigned long intervals [] = { 20, 20, 50, 100, 30 } ; // speed for each pattern - add here when adding more cases 
int fadeStep = 0; // state variable for fade function
int numberOfCases = 4; // how many case statements or patterns you have
const byte button = 3; // pin to connect button switch to between pin and ground

void setup() {
  strip.begin(); // This initialises the NeoPixel library.
  wipe(); // wipes the LED buffers
  pinMode(button, INPUT_PULLUP); // change pattern button
}

void loop() {
  static int pattern = 4, lastReading; // start with the fade function
  int reading = digitalRead(button);
  if(lastReading == HIGH && reading == LOW){
    pattern++ ; // change pattern number
    fadeStep = 0; // reset the fade state variable
    if(pattern > numberOfCases) pattern = 0; // wrap round if too big
    patternInterval = intervals[pattern]; // set speed for this pattern
    wipe(); // clear out the buffer
    delay(50); // debounce delay
  }
  lastReading = reading; // save for next time

if(millis() - lastUpdate > patternInterval) updatePattern(pattern);
}

void  updatePattern(int pat){ // call the pattern currently being created
  switch(pat) {
    case 0:
        rainbow();
        break;
    case 1:
        rainbowCycle();
        break;
    case 2:
        theaterChaseRainbow();
        break;
    case 3:
         colorWipe(strip.Color(255, 0, 0)); // red
         break; 
         
    case 4:
         fade(0,255, 0,64, 0,0, 400); // fade from black to orange and back
         break;                  
  } 
}

void fade(int redStartValue, int redEndValue, int greenStartValue, int greenEndValue, int blueStartValue, int blueEndValue, int totalSteps) {
static float redIncrement, greenIncrement, blueIncrement;
static float red, green, blue;
static boolean fadeUp = false;

if (fadeStep == 0){ // first step is to initialise the initial colour and increments
  red = redStartValue;
  green = greenStartValue;
  blue = blueStartValue;
  fadeUp = false;

  redIncrement = (float)(redEndValue - redStartValue) / (float)totalSteps;
  greenIncrement = (float)(greenEndValue - greenStartValue) / (float)totalSteps;
  blueIncrement = (float)(blueEndValue - blueStartValue) / (float)totalSteps;
  fadeStep = 1; // next time the function is called start the fade
}
else { // all other steps make a new colour and display it
  // make new colour
  red += redIncrement;
  green +=  greenIncrement;
  blue += blueIncrement;
 
  // set up the pixel buffer
  for (int i = 0; i < strip.numPixels(); i++) {
  strip.setPixelColor(i, strip.Color((int)red,(int)green,(int)blue));
  }
 // now display it
  strip.show();
fadeStep += 1; // go on to next step
if(fadeStep >= totalSteps) { // finished fade
  if(fadeUp){ // finished fade up and back
     fadeStep = 0;
     return; // so next call re-calabrates the increments 
  }
  // now fade back
  fadeUp = true;
  redIncrement = -redIncrement;
  greenIncrement = -greenIncrement;
  blueIncrement = -blueIncrement;
  fadeStep = 1; // don't calculate the increments again but start at first change
}
 }
}

void rainbow() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
     j++;
  if(j >= 256) j=0;
  lastUpdate = millis(); // time for next change to the display
 
}
void rainbowCycle() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
  j++;
  if(j >= 256*5) j=0;
  lastUpdate = millis(); // time for next change to the display
}

void theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j=0, q = 0;
  static boolean on = true;
     if(on){
            for (int i=0; i < strip.numPixels(); i=i+3) {
                strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
             }
     }
      else {
           for (int i=0; i < strip.numPixels(); i=i+3) {
               strip.setPixelColor(i+q, 0);        //turn every third pixel off
                 }
      }
     on = !on; // toggel pixelse on or off for next time
      strip.show(); // display
      q++; // update the q variable
      if(q >=3 ){ // if it overflows reset it and update the J variable
        q=0;
        j++;
        if(j >= 256) j = 0;
      }
  lastUpdate = millis(); // time for next change to the display   
}

void colorWipe(uint32_t c) { // modified from Adafruit example to make it a state machine
  static int i =0;
    strip.setPixelColor(i, c);
    strip.show();
  i++;
  if(i >= strip.numPixels()){
    i = 0;
    wipe(); // blank out strip
  }
  lastUpdate = millis(); // time for next change to the display
}


void wipe(){ // clear all LEDs
     for(int i=0;i<strip.numPixels();i++){
       strip.setPixelColor(i, strip.Color(0,0,0));
       }
}

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);
}

However looking at the original request for how you want it to operate it looks like you might have been side tracked both by the above code and by @noiasca .

You would be better off going back to my original comments in reply #1, as you want the effects to stop a time after the button is released and the code you have got so far runs the pattern and then changes it when the button is pressed again, which might not be what you want.

Hi There

Yes I think I have got a little side tracked. I am feeling a little out of knowledge here too.. so sorry if I don't understand correctly.

I just want to run one effect once or twice maybe for about 2 to 3 seconds so if I just want to run TheaterChaseRainbow I would only need to put that in somewhere right?

post what you have right now. Including this magic "TheaterChaseRainbow" effect.

noiasca:
post what you have right now. Including this magic "TheaterChaseRainbow" effect.

this what I have so far

#include <Adafruit_NeoPixel.h>

const int buttonPin = 2;              // a button connected from this pin to GND
const int ledPin = 7;                 // the pin where the pixels are connected
const byte ledCount = 27;              // How many NeoPixels are attached to the Arduino?
const unsigned long durance = 1000;   // on time in milliseconds
unsigned long lastMillis;             // stores the timestamp when the button gets pressed
bool isOn = false;                    // stores if the pixel is currently on (... if the effect runs)

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);   // if you don't have external resistors use the internal pullups with reversed logic
  strip.begin();                      // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();                       // Turn OFF all pixels ASAP
  strip.setBrightness(50);            // Set BRIGHTNESS to about 1/5 (max = 255)
  randomSeed(analogRead(0));          // recommended if you use random function
  Serial.begin(115200);               // for debug purposes we need the serial monitor
  Serial.println(F("wait for button press"));
}
void  updatePattern(int pat){ // call the pattern currently being created
  switch(pat) {
    case 2:
        theaterChaseRainbow();
        break;
void loop() {
  if (!digitalRead(buttonPin) && !isOn)         // check for button press to GND (inversed - therefore the !)
  {
    Serial.println(F("Switch on by button press"));
    strip.setPixelColor(0, random(256), random(256), random(128));  // Random colors with less blue or any other pattern. You will need a slightly different logic if the pattern should change during the "showtime"
    strip.show();
    isOn = true;
    lastMillis = millis();
  }

void theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j=0, q = 0;
  static boolean on = true;
     if(on){
            for (int i=0; i < strip.numPixels(); i=i+3) {
                strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
             }
     }
      else {
           for (int i=0; i < strip.numPixels(); i=i+3) {
               strip.setPixelColor(i+q, 0);        //turn every third pixel off
                 }
      }
     on = !on; // toggel pixelse on or off for next time
      strip.show(); // display
      q++; // update the q variable
      if(q >=3 ){ // if it overflows reset it and update the J variable
        q=0;
        j++;
        if(j >= 256) j = 0;
      }
  lastUpdate = millis(); // time for next change to the display   
}

  if (millis() - lastMillis >= durance && isOn )
  {
    Serial.println(F("Switch off by time"));
    strip.setPixelColor(0, 0);
    strip.show();
    isOn = false;
  }
}

it still remais the same.

You need the "Button" example - how to read a button and toggle a variable.
you need the "BlinkWithoutDelay" example how to do non-blocking things like end an action after a period of time.
You need the chase and all functions (!) which are called in that chase

than put in the missing globals and voila:

// let an effect run for a predefined time on Button press

#include <Adafruit_NeoPixel.h>

const int buttonPin = 2;                    // a button connected from this pin to GND
const int ledPin = 7;                       // the pin where the pixels are connected
const byte ledCount = 27;                   // How many NeoPixels are attached to the Arduino?
const unsigned long durance = 1000;         // on time in milliseconds
unsigned long lastMillis;                   // stores the timestamp when the button gets pressed
bool isOn = false;                          // stores if the pixel is currently on (... if the effect runs)

unsigned long lastUpdate = 0 ;        // for millis() when last update occurred
unsigned long patternInterval = 20 ;  // time between steps in the pattern


// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);   // if you don't have external resistors use the internal pullups with reversed logic
  strip.begin();                      // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();                       // Turn OFF all pixels ASAP
  strip.setBrightness(50);            // Set BRIGHTNESS to about 1/5 (max = 255)
  randomSeed(analogRead(0));          // recommended if you use random function
  Serial.begin(115200);               // for debug purposes we need the serial monitor
  Serial.println(F("wait for button press"));
}

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 theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j = 0, q = 0;
  static boolean on = true;
  if (on) {
    for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
      strip.setPixelColor(i + q, Wheel( (i + j) % 255)); //turn every third pixel on
    }
  }
  else {
    for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
      strip.setPixelColor(i + q, 0);      //turn every third pixel off
    }
  }
  on = !on; // toggel pixelse on or off for next time
  strip.show(); // display
  q++; // update the q variable
  if (q >= 3 ) { // if it overflows reset it and update the J variable
    q = 0;
    j++;
    if (j >= 256) j = 0;
  }
  lastUpdate = millis(); // time for next change to the display
}

void goBlack()
{
  Serial.println(F("Switch off all pixels"));
  for (uint16_t i = 0; i < strip.numPixels(); i++)
  {
    strip.setPixelColor(i, 0);
  }
  strip.show();
}


void loop() {
  if (!digitalRead(buttonPin) && !isOn)         // check for button press to GND (inversed - therefore the !)
  {
    Serial.println(F("Switch on by button press"));
    isOn = true;
    lastMillis = millis();
  }

  if (millis() - lastMillis >= durance && isOn ) // Check for time out
  {
    Serial.println(F("Switch off by time"));
    goBlack();
    isOn = false;
  }

   if(isOn &&(millis() - lastUpdate > patternInterval))  theaterChaseRainbow(); // calls pattern update if necessary
}

compiles on UNO without warnings - and runs ;-).

I don't know if you want to have the pixels black after the running time, but you should be able to spot it right now and deactivate it if you don't need it.

noiasca:
i
}
lastUpdate = millis(); // time for next change to the display
}

I am getting a read only on this line error

sketch_jul27b:64:14: error: assignment of read-only variable 'lastUpdate'

lastUpdate = millis(); // time for next change to the display

^

exit status 1
assignment of read-only variable 'lastUpdate'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

check the code again, there was a change

noiasca:
check the code again, there was a change

great worked this time. :slight_smile:

thanks for your help

No Problem

Could I ask one more question to make sure I understand I know when I go into work Monday I going to be asked to change the effect and want to make sure I know how to do this..

could you post code with changes to another effect say Rainbow cycle ? I can then compare the two to hopefully be able to make more changes myself.

"Change the effect" by button is in Grumpy's code post #4.

if you want just change the effect on permanent base:
as I've already stated:

You need the chase and all functions (!) which are called in that chase

and this line of code

if(isOn &&(millis() - lastUpdate > patternInterval))  theaterChaseRainbow(); // calls pattern update if necessary

needs a change - you have to call the other chase (you putted in).

Hi

I have been asked to add sound and can't work out how I can get them to run together. The below sketch runs one then the other....

Sorry for all the questions

:

// ToyLikeMe

#include <Adafruit_NeoPixel.h>
#define buzzer 8
#include "pitches.h"

// notes in the melody:
int melody[] = {
  NOTE_C7, NOTE_C7, NOTE_C7, NOTE_C7, NOTE_D7, NOTE_C7, NOTE_D7, NOTE_E7
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 2
};


const int buttonPin = 2;                    // a button connected from this pin to GND
const int ledPin = 7;                       // the pin where the pixels are connected
const byte ledCount = 27;                   // How many NeoPixels are attached to the Arduino?
const unsigned long durance = 1000;         // on time in milliseconds
unsigned long lastMillis;                   // stores the timestamp when the button gets pressed
bool isOn = false;                          // stores if the pixel is currently on (... if the effect runs)

unsigned long lastUpdate = 0 ;        // for millis() when last update occurred
unsigned long patternInterval = 20 ;  // time between steps in the pattern


// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);   // if you don't have external resistors use the internal pullups with reversed logic
  pinMode(buzzer, OUTPUT);
  strip.begin();                      // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();                       // Turn OFF all pixels ASAP
  strip.setBrightness(50);            // Set BRIGHTNESS to about 1/5 (max = 255)
  randomSeed(analogRead(0));          // recommended if you use random function
  Serial.begin(115200);               // for debug purposes we need the serial monitor
  Serial.println(F("wait for button press"));
}

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 theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j = 0, q = 0;
  static boolean on = true;
  if (on) {
    for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
      strip.setPixelColor(i + q, Wheel( (i + j) % 255)); //turn every third pixel on
    }
  }
  else {
    for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
      strip.setPixelColor(i + q, 0);      //turn every third pixel off
    }
  }
  on = !on; // toggel pixelse on or off for next time
  strip.show(); // display
  q++; // update the q variable
  if (q >= 3 ) { // if it overflows reset it and update the J variable
    q = 0;
    j++;
    if (j >= 256) j = 0;
  }
  lastUpdate = millis(); // time for next change to the display
}
 
    
void goBlack()
{
  Serial.println(F("Switch off all pixels"));
  for (uint16_t i = 0; i < strip.numPixels(); i++)
  {
    strip.setPixelColor(i, 0);
  }
  strip.show();
}


void loop() {
  if (!digitalRead(buttonPin) && !isOn)         // check for button press to GND (inversed - therefore the !)
  {
    Serial.println(F("Switch on by button press"));
    isOn = true;   
    lastMillis = millis();

    }
    

  
  if (millis() - lastMillis >= durance && isOn ) // Check for time out
  {
    Serial.println(F("Switch off by time"));
    goBlack();
    isOn = false;

        //VICTORY MELODY
    for (int thisNote = 0; thisNote < 8; thisNote++) {
      int noteDuration = 1000 / noteDurations[thisNote];
      tone(8, melody[thisNote], noteDuration);
      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
 
    }
    // stop the tone playing:
      noTone(8);
  }

   if(isOn &&(millis() - lastUpdate > patternInterval))  theaterChaseRainbow(); // calls pattern update if necessary
  }

The below sketch runs one then the other....

What do you mean?
That sketch runs the sound bit when the the pattern ends.

Are you saying it doesn't or you want the sound to play during the animation?

If so that is tricky because every time the show function is called the processes that sends data out to the LED strip disables the interrupts for a short time which will disturb the code in the tone function. This might cause the tone to sound glitchey. However you may not notice this. I haven't tried outputting tones and driving an LED strip at the same time.

yeah I want them to both run at the same time.

yes that is the problem I am having no matter where I put the sound into the sketch it either rums one and then the other or it interrupts the LEDs when playing the sound,

I going to give it a little more thought today. I am thinking there must be a way i can do it. My second thought is to run another Arduino Nano and connect the button to them both. Its a one off project. I think this would work.

I have learnt a lot considering until 2 weeks again I never have pick up an Arduino, its been quite fun learning what it can and can't do.

you added a

delay(pauseBetweenNotes);

we did all the effort so far, to produce a non blocking code and you add a delay.
This is a nogo.

read post #4

and again.

This means removing all delays, or at least delays longer than about 100mS, and "unrolling" any for loop structures.

and again.

Post #4 didn't make to much sense to me. I was confused on the structure. Sorry.

noiasca:
you added a

delay(pauseBetweenNotes);

we did all the effort so far, to produce a non blocking code and you add a delay.
This is a nogo.

read post #4

and again.

and again.

Yes you have to write your tune code as a state machine as well. With your pauseBetweenNotes variable determining how often the function is called.

Post #4 didn't make to much sense to me.

Then you should ask about what you don’t understand. This sort of code structure is a step above simple beginner stuff.

What I did with theaterChaseRainbow over what it was in the Adafruit example is what you have to do with your sound playing code.

What do you want to do with the tune when it comes to an end? Should it repeat for as long as the LEDs are running, or should it stop once it has finished?