Controlling timed millis() loops

hey,

an except of code;

so, intervalLeds is small (10ms) and intervalBreathe is large (5000ms)

what i want to happen;

the leds light up depending on what sensor is activated, le, ri, to, bo, ba, fr are all positions that call showLeds() that lights the leds.

is if a sensor detects no movement (==255) for 5 seconds (intervalBreathe) then the currently lit led fades in and out (like its breathing!) until movement is detected.

whats happening;

showLeds is called consistently, and every 5 seconds, the breatheLeds is called, and then immediately goes back to showLeds.

how do i latch the breatheLeds so that it runs, until a change in sensors is detected.

the le, fr, ri etc variables comes from accelerometer readings, that either output 0 or 255, so either the led is on or off, but there is always 1 led lit!

ill post the full code in the next post!

also, as a side note, i dont want to use any delays whatsoever, and i think that my usage of IF timed loops is right, but do i lose efficiency / time by using them nested, or do the loops happen so quickly thats its not so relevant?

if (currentMillisLeds - previousMillisLeds >= intervalLeds) {
  previousMillisLeds = currentMillisLeds;
    readXyz();
    showLeds();
    state=9;
    Serial.print("**showLeds**");
    
//  unsigned long currentMillisBreathe = millis();
//    if (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) {
//    previousMillisBreathe = currentMillisBreathe;

if ((le==255 || ri==255 || to==255 || bo==255 || fr==255 || ba==255) && (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) ) {
  previousMillisBreathe = currentMillisBreathe;
    breatheLeds();
    state=10;
    
      Serial.print("**breaLeds**");

    }
//#include <Wire.h>
#include <ADXL345.h>
#include "FastLED.h"

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library

#define NUM_LEDS 12
#define DATA_PIN 3
#define CLOCK_PIN 13
#define BRIGHTNESS 255

struct CRGB leds[NUM_LEDS];

int accuracy = 50;
int var = 1;  // initial sequence
int sensitivity = 210;
int fadeIn = 20;
int fadeOut = 10;
int state = 1;

// game variables
int gameOn = 3000;
int difficulty = 10000;

// core xyz
int x, y, z;

// mapped xyz
int xa, ya, za, xb, yb, zb;

// led xyz
int xc, yc, zc, xd, yd, zd;
int fr, ba, le, ri, to, bo;

// HSV colour values
//0 red, 32 orange, 64 yellow, 96 green, 128 aqua, 160 blue, 192 purple, 224 pink, 255 red
int ledColour = 160;
int resetColour = 160;

// time variables
unsigned long previousMillisSensor = 0;        // will store last time sensor was updated
const long intervalSensor = 50;           // interval at which to check sensor
unsigned long previousMillisLeds = 0;        // will store last time LED was updated
const long intervalLeds = 10;           // interval at which to operate leds
unsigned long previousMillisBreathe = 0;        // will store last time sensor was updated
const long intervalBreathe = 5000;           // interval at which to check sensor
int breatheTime = 5;    // inteval for inactivity in seconds

void setup()
{
  adxl.powerOn();

  //set activity/ inactivity thresholds (0-255)
  adxl.setActivityThreshold(75); //62.5mg per increment
  adxl.setInactivityThreshold(75); //62.5mg per increment
  adxl.setTimeInactivity(breatheTime); // how many seconds of no activity is inactive?
 
  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(1);
 
  //look of inactivity movement on this axes - 1 == on; 0 == off
  adxl.setInactivityX(1);
  adxl.setInactivityY(1);
  adxl.setInactivityZ(1);
 
  //look of tap movement on this axes - 1 == on; 0 == off
  adxl.setTapDetectionOnX(0);
  adxl.setTapDetectionOnY(0);
  adxl.setTapDetectionOnZ(1);
 
  //set values for what is a tap, and what is a double tap (0-255)
  adxl.setTapThreshold(50); //62.5mg per increment
  adxl.setTapDuration(15); //625μs per increment
  adxl.setDoubleTapLatency(80); //1.25ms per increment
  adxl.setDoubleTapWindow(200); //1.25ms per increment
 
  //set values for what is considered freefall (0-255)
  adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment
 
  //setting all interupts to take place on int pin 1
  //I had issues with int pin 2, was unable to reset it
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );
 
  //register interupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
  
//  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  delay(2000);
  FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, BRG>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.setBrightness(BRIGHTNESS);
}

void loop() {
  
  //getInterruptSource clears all triggered actions after returning value
  //so do not call again until you need to recheck for triggered actions
  byte interrupts = adxl.getInterruptSource();
//  adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables  x,y,z
  
  unsigned long currentMillisLeds = millis();
  unsigned long currentMillisBreathe = millis();
  
if (currentMillisLeds - previousMillisLeds >= intervalLeds) {
  previousMillisLeds = currentMillisLeds;
    readXyz();
    showLeds();
    state=9;
    Serial.print("**showLeds**");
    
//  unsigned long currentMillisBreathe = millis();
//    if (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) {
//    previousMillisBreathe = currentMillisBreathe;

if ((le==255 || ri==255 || to==255 || bo==255 || fr==255 || ba==255) && (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) ) {
  previousMillisBreathe = currentMillisBreathe;
    breatheLeds();
    state=10;
    
      Serial.print("**breaLeds**");

    }


serialText();


  } // end of timed loops
} // end of void loop

void serialText() {
  Serial.print(le); Serial.print(" ");
  Serial.print(ri); Serial.print(" | ");
  Serial.print(ba); Serial.print(" ");
  Serial.print(fr); Serial.print(" | ");
  Serial.print(to); Serial.print(" ");
  Serial.print(bo); Serial.print(" || ");
  Serial.print(" state: "); Serial.print(state); Serial.print(" || ");
  Serial.println();
}

void showLeds() {
      for (int i = 0; i < 2; i++) {
      leds[i]    =   CHSV( ledColour, 255, ba); // back
      leds[i+2]  =   CHSV( ledColour, 255, le); // left
      leds[i+4]  =   CHSV( ledColour, 255, fr); // front
      leds[i+6]  =   CHSV( ledColour, 255, ri); // right
      leds[i+8]  =   CHSV( ledColour, 255, to); // top
      leds[i+10] =   CHSV( ledColour, 255, bo); // bottom
    FastLED.show();
    }
}

void breatheLeds() {
    float breathe = (exp(sin(millis()/1000.0*PI)) - 0.36787944)*108.0;
      for (int i = 0; i < 2; i++) {
      leds[i]    =   CHSV( ledColour, 255, breathe*ba); // back
      leds[i+2]  =   CHSV( ledColour, 255, breathe*le); // left
      leds[i+4]  =   CHSV( ledColour, 255, breathe*fr); // front
      leds[i+6]  =   CHSV( ledColour, 255, breathe*ri); // right
      leds[i+8]  =   CHSV( ledColour, 255, breathe*to); // top
      leds[i+10] =   CHSV( ledColour, 255, breathe*bo); // bottom
    FastLED.setBrightness(breathe);
    FastLED.show();
    }
}

void readXyz () {
  adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables  x,y,z

  xa = map(x, -255, 255, 255, 0); // left
  xb = map(x, -255, 255, 0, 255); // right
  ya = map(y, -255, 255, 255, 0); // front
  yb = map(y, -255, 255, 0, 255); // back
  za = map(z, -255, 255, 0, 255); // top
  zb = map(z, -255, 255, 255, 0); // bottom
  
  if (xa < sensitivity) le -= fadeOut;  if (xa > sensitivity) le += fadeIn; if (le<0) le=0; if (le>255) le=255; state=3;
  if (ya < sensitivity) fr -= fadeOut;  if (ya > sensitivity) fr += fadeIn; if (fr<0) fr=0; if (fr>255) fr=255; state=4;
  if (za < sensitivity) to -= fadeOut;  if (za > sensitivity) to += fadeIn; if (to<0) to=0; if (to>255) to=255; state=5;
  if (xb < sensitivity) ri -= fadeOut;  if (xb > sensitivity) ri += fadeIn; if (ri<0) ri=0; if (ri>255) ri=255; state=6;
  if (yb < sensitivity) ba -= fadeOut;  if (yb > sensitivity) ba += fadeIn; if (ba<0) ba=0; if (ba>255) ba=255; state=7;     
  if (zb < sensitivity) bo -= fadeOut;  if (zb > sensitivity) bo += fadeIn; if (bo<0) bo=0; if (bo>255) bo=255; state=8;

  byte interrupts = adxl.getInterruptSource();

}

Wouldn't that be a matter of a different 'sequence' of test in loop(). Currently you always call showLeds() every 5 seconds.
What happens if you only call showLeds() if the condition to breathe the LEDs is not satisfied.

  if (currentMillisLeds - previousMillisLeds >= intervalLeds) {
    previousMillisLeds = currentMillisLeds;
    readXyz();

    if ((le == 255 || ri == 255 || to == 255 || bo == 255 || fr == 255 || ba == 255) && (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) ) {
      previousMillisBreathe = currentMillisBreathe;
      breatheLeds();
      state = 10;

      Serial.print("**breaLeds**");

    }
    else
    {
      showLeds();
      state = 9;
      Serial.print("**showLeds**");
    }

Some comments:
1)
Is 'state' a preparation for something? You assign but never test as far as I can see.
2)
It's advisable not to use single character variables; especially if they are global. Rename x, y, and z to something better like coreX, coreY and coreZ. A lot easier to do a search in the code.
3)
xa, xb, ya, yb, za and zb are only used in readXyz. So declare them there instead of making them global.

hey!

so instead of run showleds all the time and check for breatheleds; run breatheleds and check to see if showleds is apparent?

i guess im trying to code like im thinking...

light the led... if the led is static for 5 seconds, fade in and out.

as opposed to;

fade the led in and out, but if any movement is detected, then make the led static.

state is a test;

for the 6 side of the cube (leds) each is assigned a state (3-8) showleds was 7, breatheleds is 8, purely to show where code gets stuck... debugging!

i was using it to change case in a switch loop, but it wasnt working.

xy and z, were immediately mapped to xa, xb, ya, yb, za, and zc, and then ported to the easier (for me) to read le (left) ri (right, fr (front) ba (back) to (top) and bo (bottom)

and 3... for memory state, or just good practice?

Mostly good practice. And in code with lots of variables it can just save you a bit of memory so you don't run out.

then ported to the easier (for me) to read le (left) ri (right, fr (front) ba (back) to (top) and bo (bottom)

Why not use left, right, front, back, top, and bottom ?

UKHeliBob:
Why not use left, right, front, back, top, and bottom ?

ahh, ok whilst looking at the code, a little bit of ocd in me can see issues quicker if everything is spaced out nicely.

before it was xa, xb, ya, yb, za, zb, then as i was adding non directly affected code, i tweaked this to xc, xd, yc, yd, zc, zd, and this was getting confusing...

now xc, xd, is fr, ba, le, ri, bo, to... which looks confusing, but in my mind, is 200% easier.

even just writing this paragraph i ended up writing, xa, xb, yc, yd, za, zb...

ok, so i swapped the code around and i can see whats happening.

the sensors are constantly checking which is fine, but the program is locked. as i have 6 sides, one of the sides is always 255, so the breatheLeds is always active, but because it is in a millis() loop, it only updates every 5 seconds.

i want the code to sense no movement for 5 seconds and then start breathing, but if movement is detected, stop breathing and continue lighting leds.

kelvinmead:
ahh, ok whilst looking at the code, a little bit of ocd in me can see issues quicker if everything is spaced out nicely.

You can split a long line like that into multiple lines. It actually reads very well. C/C++ is nice that way. I believe the auto-formatter treats those respectfully, as well. e.g.

if ((left == 255
     || right == 255
     || top == 255
     || bottom == 255
     || front == 255
     || back == 255)
    && (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) )

I find it hard to believe that you (or anybody) would find that harder to read than

    if ((le == 255 || ri == 255 || to == 255 || bo == 255 || fr == 255 || ba == 255) && (currentMillisBreathe - previousMillisBreathe >= intervalBreathe) )