Arduino programs within programs

Associate
Joined
27 Nov 2003
Posts
2,486
Location
Loughborough
Hiya,

I'm working on a project I started for a local church to control WS2812B LED's using an arduino.

I've learnt enough to change colour using a 12 way rotary switch but I hope to change programs using the switch instead. I've figured out it has something to do with calling the separate .h files but I'm not a programmer... can anyone point me in the right direction? :-)

Here is the code I have for 7 colours but I want the remaining 5 to be something like a chase, sound to light or fire effect, I have all the programs saved but I've not mastered calling them if something could offer me some advice at all? (willing to make a beer money donation for advice!)

Code:
// Include the FastLED library
#include <FastLED.h>

// Define the number of LEDs and the data pin
#define NUM_LEDS 32
#define DATA_PIN 6

// Define the brightness level
#define BRIGHTNESS 32

// Define the LED array
CRGB leds[NUM_LEDS];

// Define the program selection pins
#define PROGRAM_1 40
#define PROGRAM_2 41
#define PROGRAM_3 42
#define PROGRAM_4 43
#define PROGRAM_5 44
#define PROGRAM_6 45
#define PROGRAM_7 46
#define PROGRAM_8 47
#define PROGRAM_9 48
#define PROGRAM_10 49
#define PROGRAM_11 50
#define PROGRAM_12 51

// Define the program variables
int program = 0;
int lastProgram = 0;

// Setup function
void setup() {
  // Set the LED data pin as output
  pinMode(DATA_PIN, OUTPUT);

  // Set the program selection pins as input with pullup
  pinMode(PROGRAM_1, INPUT_PULLUP);
  pinMode(PROGRAM_2, INPUT_PULLUP);
  pinMode(PROGRAM_3, INPUT_PULLUP);
  pinMode(PROGRAM_4, INPUT_PULLUP);
  pinMode(PROGRAM_5, INPUT_PULLUP);
  pinMode(PROGRAM_6, INPUT_PULLUP);
  pinMode(PROGRAM_7, INPUT_PULLUP);
  pinMode(PROGRAM_8, INPUT_PULLUP);
  pinMode(PROGRAM_9, INPUT_PULLUP);
  pinMode(PROGRAM_10, INPUT_PULLUP);
  pinMode(PROGRAM_11, INPUT_PULLUP);
  pinMode(PROGRAM_12, INPUT_PULLUP);

  // Initialize the LED array
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);

  // Set the initial program
  program = 1;
}

// Loop function
void loop() {
  // Check for program selection
  if (digitalRead(PROGRAM_1) == LOW) {
    program = 1;
  } else if (digitalRead(PROGRAM_2) == LOW) {
    program = 2;
  } else if (digitalRead(PROGRAM_3) == LOW) {
    program = 3;
  } else if (digitalRead(PROGRAM_4) == LOW) {
    program = 4;
  } else if (digitalRead(PROGRAM_5) == LOW) {
    program = 5;
  } else if (digitalRead(PROGRAM_6) == LOW) {
    program = 6;
  } else if (digitalRead(PROGRAM_7) == LOW) {
    program = 7;
  } else if (digitalRead(PROGRAM_8) == LOW) {
    program = 8;
  } else if (digitalRead(PROGRAM_9) == LOW) {
    program = 9;
  } else if (digitalRead(PROGRAM_10) == LOW) {
    program = 10;
  } else if (digitalRead(PROGRAM_11) == LOW) {
    program = 11;
  } else if (digitalRead(PROGRAM_12) == LOW) {
    program = 12;
  }

  // Check if the program has changed
  if (program != lastProgram) {
    // Clear the LED array
    FastLED.clear();

    // Set the new program
    switch (program) {
      case 1:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::White;
  }
  FastLED.show();
        break;
      case 2:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Red;
  }
  FastLED.show();
        break;
      case 3:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Blue;
  }
  FastLED.show();
        break;
      case 4:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Green;
  }
  FastLED.show();
        break;
      case 5:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Yellow;
  }
  FastLED.show();
        break;
      case 6:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Cyan;
  }
  FastLED.show();
        break;
      case 7:
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Purple;
  }
  FastLED.show();
        break;
      case 8:
        // Program 8 code here
        break;
      case 9:
        // Program 9 code here
        break;
      case 10:
        // Program 10 code here
        break;
      case 11:
        // Program 11 code here
        break;
      case 12:
        // Program 12 code here
        break;
    }

    // Show the new LED array
    FastLED.show();

    // Update the last program variable
    lastProgram = program;
  }
}

Thanks for any help you can offer.
 
Thanks both for your answers, I'll need to read and digest it. :-)

I'd read using separate .h files was the only way to use different void loops which is why I went that route but I'll read in greater detail and take it from there with the results.

I'm also 3d printing the case and framework to hold it all so it is quite entertaining to do.

Edit - some of the programs use the Fastled library and some use the Neopixel library, hence the separation and need for individual void loops. The audio component is handled using Amplie-tie and is really quite a lovely way of doing it, code attached below if you want a try at it. I don't claim to have done much of the original coding at all as it is still work in progress. :-)

Code:
/*
LED VU meter for Arduino and Adafruit NeoPixel LEDs.
 
 Hardware requirements:
 - Most Arduino or Arduino-compatible boards (ATmega 328P or better).
 - Adafruit Electret Microphone Amplifier (ID: 1063)
 - Adafruit Flora RGB Smart Pixels (ID: 1260)
 OR
 - Adafruit NeoPixel Digital LED strip (ID: 1138)
 - Optional: battery for portable use (else power through USB or adapter)
 Software requirements:
 - Adafruit NeoPixel library
 
 Connections:
 - 3.3V to mic amp +
 - GND to mic amp -
 - Analog pin to microphone output (configurable below)
 - Digital pin to LED data input (configurable below)
 See notes in setup() regarding 5V vs. 3.3V boards - there may be an
 extra connection to make and one line of code to enable or disable.
 
 Written by Adafruit Industries.  Distributed under the BSD license.
 This paragraph must be included in any redistribution.
 
 fscale function:
 Floating Point Autoscale Function V0.1
 Written by Paul Badger 2007
 Modified from code by Greg Shakar
 
 */

#include <Adafruit_NeoPixel.h>
#include <math.h>

#define LED_PIN    6
#define NUM_LEDS  32
#define MIC_PIN   A0

#define SAMPLE_WINDOW   30  // Sample window for average level
#define PEAK_HANG 24 //Time of pause before peak dot falls
#define PEAK_FALL 4  //Rate of falling peak dot
#define INPUT_FLOOR 10 //Lower range of analogRead input
#define INPUT_CEILING 100 //Max range of analogRead input, the lower the value the more sensitive (1023 = max)



byte peak = 16;      // Peak level of column; used for falling dots
unsigned int sample;

byte dotCount = 0;  //Frame counter for peak dot
byte dotHangCount = 0; //Frame counter for holding peak dot

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
  // This is only needed on 5V Arduinos (Uno, Leonardo, etc.).
  // Connect 3.3V to mic AND TO AREF ON ARDUINO and enable this
  // line.  Audio samples are 'cleaner' at 3.3V.
  // COMMENT OUT THIS LINE FOR 3.3V ARDUINOS (FLORA, ETC.):
  //  analogReference(EXTERNAL);

  // Serial.begin(9600);
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

}

void loop()
{
  unsigned long startMillis= millis();  // Start of sample window
  float peakToPeak = 0;   // peak-to-peak level

  unsigned int signalMax = 0;
  unsigned int signalMin = 1023;
  unsigned int c, y;


  // collect data for length of sample window (in mS)
  while (millis() - startMillis < SAMPLE_WINDOW)
  {
    sample = analogRead(MIC_PIN);
    if (sample < 1024)  // toss out spurious readings
    {
      if (sample > signalMax)
      {
        signalMax = sample;  // save just the max levels
      }
      else if (sample < signalMin)
      {
        signalMin = sample;  // save just the min levels
      }
    }
  }
  peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
 
  // Serial.println(peakToPeak);


  //Fill the strip with rainbow gradient
  for (int i=0;i<=strip.numPixels()-1;i++){
    strip.setPixelColor(i,Wheel(map(i,0,strip.numPixels()-1,30,150)));
  }


  //Scale the input logarithmically instead of linearly
  c = fscale(INPUT_FLOOR, INPUT_CEILING, strip.numPixels(), 0, peakToPeak, 2);

 


  if(c < peak) {
    peak = c;        // Keep dot on top
    dotHangCount = 0;    // make the dot hang before falling
  }
  if (c <= strip.numPixels()) { // Fill partial column with off pixels
    drawLine(strip.numPixels(), strip.numPixels()-c, strip.Color(0, 0, 0));
  }

  // Set the peak dot to match the rainbow gradient
  y = strip.numPixels() - peak;
 
  strip.setPixelColor(y-1,Wheel(map(y,0,strip.numPixels()-1,30,150)));

  strip.show();

  // Frame based peak dot animation
  if(dotHangCount > PEAK_HANG) { //Peak pause length
    if(++dotCount >= PEAK_FALL) { //Fall rate
      peak++;
      dotCount = 0;
    }
  }
  else {
    dotHangCount++;
  }
}

//Used to draw a line between two points of a given color
void drawLine(uint8_t from, uint8_t to, uint32_t c) {
  uint8_t fromTemp;
  if (from > to) {
    fromTemp = from;
    from = to;
    to = fromTemp;
  }
  for(int i=from; i<=to; i++){
    strip.setPixelColor(i, c);
  }
}


float fscale( float originalMin, float originalMax, float newBegin, float
newEnd, float inputValue, float curve){

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;


  // condition curve parameter
  // limit range

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
  curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function

  /*
   Serial.println(curve * 100, DEC);   // multply by 100 to preserve resolution
   Serial.println();
   */

  // Check for out of range inputValues
  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  // Zero Refference the values
  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin){
    NewRange = newEnd - newBegin;
  }
  else
  {
    NewRange = newBegin - newEnd;
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal  =  zeroRefCurVal / OriginalRange;   // normalize to 0 - 1 float

  // Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine
  if (originalMin > originalMax ) {
    return 0;
  }

  if (invFlag == 0){
    rangedValue =  (pow(normalizedCurVal, curve) * NewRange) + newBegin;

  }
  else     // invert the ranges
  { 
    rangedValue =  newBegin - (pow(normalizedCurVal, curve) * NewRange);
  }

  return rangedValue;
}


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

Also, one of the Fastled programs, this is why I couldnt try and do it all in one program (I don't think anyway!)

Code:
#include <FastLED.h>

#define LED_PIN     6
#define NUM_LEDS    32
#define BRIGHTNESS  32

#define COLOR_ORDER GRB
#define CHIPSET     WS2812B
#define FRAMES_PER_SECOND 60

bool gReverseDirection = false;

CRGB leds[NUM_LEDS];

void setup() {
  delay(3000); // sanity delay
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()
{
  // Add entropy to random number generator; we use a lot of it.
  // random16_add_entropy( random());

  Fire2012(); // run simulation frame
 
  FastLED.show(); // display this frame
  FastLED.delay(1000 / FRAMES_PER_SECOND);
}


// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
// at each point along the line.  Every cycle through the simulation,
// four steps are performed:
//  1) All cells cool down a little bit, losing heat to the air
//  2) The heat from each cell drifts 'up' and diffuses a little
//  3) Sometimes randomly new 'sparks' of heat are added at the bottom
//  4) The heat from each cell is rendered as a color into the leds array
//     The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
//
// Looks best on a high-density LED setup (60+ pixels/meter).
//
//
// There are two main parameters you can play with to control the look and
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
// in step 3 above).
//
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames.  More cooling = shorter flames.
// Default 50, suggested range 20-100
#define COOLING  55

// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire.  Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
#define SPARKING 120


void Fire2012()
{
// Array of temperature readings at each simulation cell
  static uint8_t heat[NUM_LEDS];

  // Step 1.  Cool down every cell a little
    for( int i = 0; i < NUM_LEDS; i++) {
      heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
    }
 
    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for( int k= NUM_LEDS - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }
  
    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160,255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for( int j = 0; j < NUM_LEDS; j++) {
      CRGB color = HeatColor( heat[j]);
      int pixelnumber;
      if( gReverseDirection ) {
        pixelnumber = (NUM_LEDS-1) - j;
      } else {
        pixelnumber = j;
      }
      leds[pixelnumber] = color;
    }
}
 
Last edited:
Back
Top Bottom