Help with a multifunction millis() program

I have a question - what I'd like to do is trigger a relay and LED's based on a timer count (int timer) [see below]

the complicated part for me is I need the relay to be on and off for different times - like blink an LED on and off but "on" longer than "off", let's say for example at timer = 60 seconds , LED will blink long, off short, on long, then LED = false; wait for next time.

I've tried using an array to contain the times and then trigger a function, I couldn't get it to work without bugs, so if I can have an array[] = { 1, 10, 20, 30, 60}; and at those times blink an LED, I've found myself at a roadblock and though I've found good examples and learned cool stuff like how to use poynters, I haven't figured this out - driving me crazy.

I couldn't seem to get this to work, I'm sure there's got to be a better way:

for( i = 0, i <= sizeof(array[]), i++){
If ( timer == array[i]){ //run LED sequence here;
}

I'm always looking to improve my programming so all advice is greatly appreciated

void loop() {
  // Main start

if (digitalRead(start3BTN) == HIGH){
  start = true;
  }
  
 if (start == true){
  sequence = true; 
  start = false;
  timer = 0;
  }

  if (sequence == true){
    while (timer < 180)
    {
        ms = millis();
  
      if(ms - prevms >= oneSEC ){
        prevms = ms;
        timer++; 
        Serial.println(timer); // for checking time on serial monitor
        
        }

      if (timer == 1){
        longON();
}

Show us a good schematic of your circuit.
Show us a good image of your ‘actual’ wiring.
Give links to components.

Use CTRL T to format your code then copy the ‘complete sketch’ and paste it here between code tags.

-I'm using the arduino uno for developing this project, final project will likely be using the pro mini
-happy to share a schematic once I complete the project, right now it's just a prototype or in other words a simple LED and one button, I'm using pin 4 for the button and pin 12 for the LED
-the relay is 5v, triggered the same way as an LED - when HIGH it's on otherwise it's LOW

  • I have a ton of code written and none of them quite work which is why I'm here.
void onLONG() {
  ms = millis();
  if (ms - prevms1 >= ledON) {
    HORN = true;
    digitalWrite(hornPin, LED);
    prevms1 = ms;
  }
  if (ms - prevms2 >= ledOFF) {
    HORN = false;
    digitalWrite(hornPin, LED);
    prevms2 = ms;
  }

Here's one that is a proof of concept, but not quite there:

//

//BTN's

int start3BTN = 4;

//Boolean Vars

bool start = false;
bool sequence = false;
bool warning = false;
bool leds1 = false;

//int's

int timer = 0;
int count = 0;


unsigned long ms = 0;
unsigned long prevms = 0;
unsigned long oneSEC = 1000UL;


const uint8_t         pinLED      = 12;   // Arduino Uno


const unsigned long     dtON_DELAY  = 600UL;
const unsigned long     dtOFF_DELAY = 125UL;

const uint8_t           LED_OFF     = LOW;
const uint8_t           LED_ON      = HIGH;


uint8_t                 stateLED    = LED_OFF;
unsigned long           dtTrigger;

bool hasTimeArrived(const unsigned long& dtTrigger)
{
  return (((long)(millis() - dtTrigger)) >= 0);
}

unsigned long blink()
{
  stateLED = ((stateLED == LED_ON) ? LED_OFF : LED_ON);
  digitalWrite(pinLED, stateLED);

  return ((stateLED == LED_ON) ? dtON_DELAY : dtOFF_DELAY);
}

void setup()
{

  pinMode(4, INPUT);

  dtTrigger = millis();

  pinMode(pinLED, OUTPUT);
}

void loop()
{

  if (digitalRead(start3BTN) == HIGH)
  {
    start = true;
  }


  if (start == true) {
    sequence = true;
    start = false;
  }

  if (sequence == true)
  {
    while (timer < 180)
    {
      ms = millis();
      if (ms - prevms >= oneSEC )
      {
        prevms = ms;
        timer++;
      }
      if (timer == 1) {
        warning = true;
      }
      if (warning = true) {
        leds1 = true;
        warning = false;
        if (leds1 = true) {
          LED();
        }
      }
    }

  }


}


void LED()
{


  if ( hasTimeArrived(dtTrigger) )
  {
    dtTrigger += blink();
  }

}

How did you get this far without testing as you wrote the code?
Paul

OOPS

Here is the BlinkWithoutDelay example blinking S-O-S using an array for the timing.

File -> Examples -> 02.Digital -> BlinkWithoutDelay

// constants won't change. Used here to set a pin number:
const int ledPin =  LED_BUILTIN;// the number of the LED pin
const int buzzerPin =  10;

// Variables will change:
int ledState = HIGH;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

#define s    100      // Morse code short
#define l    (3 * s)  // long
#define g    s        // gap between dots and dashes
#define mg   (3 * s)  // medium gap between letters
#define lg   (7 * s)  // long gap between words

// constants won't change:
const long interval[] = { s,g,s,g,s,mg,l,g,l,g,l,mg,s,g,s,g,s,lg }; // S-O-S

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
}

void loop() {
  static int state = 0;
  
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval[state]) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
    digitalWrite(buzzerPin, !ledState);
    
    state = ( state +1 ) % ( sizeof( interval ) / sizeof( interval[0] ) );
  }
}
1 Like

You can save half the space of that interval array by just automatically doing a short gap after every entry, and adjusting the medium and long gaps to take that into account.

Also, whenever you #define an expression, enclose it in parentheses so there's no chance of an order of operations problem. Like: #define l (3 * s). Remember that #define is a text substitution not a variable, so if you use it around operators that have higher precedence that what's used in the expression it can cause unexpected behavior without parentheses around it.

#include "blinker.h"

// So everyone wants newbies to write blink without delay. This is good
// because delay() is bad. Well, here's the simple way to do it..

// Allocate a global blinker object.
blinker aBLinker(13,5000,6000);   // Pin#, On Ms, Total Ms             

void setup() {

   // Fire it up.
   aBLinker.setOnOff(true); 
}


void loop() {

   // blinker is an idler. Calling idle() once in loop lets ALL idlers run.
   idle();                    
}

That will deal with the relay/blinking You will need to grab LC_baseTools from the library manager to compile it.

Good luck!

-jim lee

1 Like

I used an Arduino Nano 33 IoT with 256kB of Flash and 32kB of RAM to blink an LED and a buzzer. No need to save any memory. :slight_smile:

You are right about the define. I will change that to show good programming.

1 Like

Thank you Klaus! This is very very helpful

This is also very interesting Jim, definitely going to check this out as well, thank you!

How is start3BTN wired?

if (:grimacing: == true){
:man_facepalming:
}

I usually wire them like this:
SIK Experiment Guide for Arduino - V3.2 - SparkFun Learn.

Here are a couple methods that you may like to use on your blinker.

aBLinker.setPeriod(float ms);
aBLinker.setPulse(float ms);

You can set the total(period) and pulse-on time, on the fly, with these two.

-jim lee

This example in
in my How to write Timers and Delays in Arduino
covers sequences of on/off

Great info and example @drmpf

So I got one part of what I want to occur... sometimes, I had it mostly working maybe 75% of the time which is alot better than 0% of the time lol

my current problem is some of the time the LED blinks more than it's supposed to and the intervals aren't correct - any ideas on how to fix this? The code and variables are at the bottom if you want to test it out, I setup an external led on pin 12 for testing

Serial.println(interval[state]); // delay time
Serial.println(trig); // trigger value, this is set at 5 then subtracts 1 each time the delay is reached

250
4
450
3
250
2
450
1
250
4
250
4
250
4
450
3
250
2
450
1
250
0

the interval state should start with 450 then go to 250 based on the array, and they should alternate - they're repeating sometimes. Also trig should be 5 then trig-- each time through the loop until trig == 0 ( if(trig > 0)) appears it doesn't stop when trig == 1 then sets trig = 4, so that I'm confused about

here's the loop for this part

void SEQUENCE() {

  static int state = 0;
  unsigned long currentMillis = millis();

  // start
  if (currentMillis - prms >= second) {
    prms = currentMillis;
    timer++;

   //  Serial.println(timer);
  }
  // main timer keeps track of time left

  //start time functions
  if (timer == 1) {
    trig = 5;
    state = 0;
    runTrig = true;
  }

  if (runTrig == true && trig > 0) {
    if (currentMillis - previousMillis >= interval[state]) {
      // save the last time you blinked the LED
      trig--;
      state++;

      // if the LED is off turn it on and vice-versa:
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }

      // set the LED with the ledState of the variable:
      digitalWrite(ledPin, ledState);
      
      
      Serial.println(interval[state]);
      Serial.println(trig);
     previousMillis = currentMillis;
    }
  }
  else {
    digitalWrite(ledPin, false);
    runTrig = false;
  }
}



Variables needed to test this code

// constants 
const int ledPin =  12;// the number of the LED pin

// Variables will change:
int ledState = LOW;  // ledState used to set the LED
int lastSTATE = LOW;

int btnSTATE = LOW;
bool start;
bool sequence;
bool runTrig;

//int vars
int timer;
int trig;

unsigned long previousMillis = 0;        // timer memory
unsigned long prms = 0;                 //trigger time memory

#define s    450     // long delay
#define g    250        // short delay
#define second 1000 // one second

// constants won't change:
const long interval[] = { s, g, s, g, s, g, s, g, s, g };

Not exactly sure what trig is doing, but try this code.
If you have two separate things happening, put them in separate tasks

// install SafeString V4.0.3 from Arduino library manager for millisDelay
#include "millisDelay.h"
// constants
const int ledPin =  13;// the number of the LED pin

// Variables will change:
bool ledStateON = false;  // ledState used to set the LED
int lastSTATE = LOW;

int btnSTATE = LOW;
bool start;
bool sequence;
bool runTrig;

//int vars
int timer;
int trig;

unsigned long previousMillis = 0;        // timer memory
unsigned long prms = 0;                 //trigger time memory

#define s    450     // long delay
#define g    250        // short delay
#define second 1000 // one second

// constants won't change:
const unsigned long interval[] = { s, g, s, g, s, g, s, g, s, g };
size_t intervalSize = sizeof(interval) / sizeof(unsigned long); // number of elements in interval
size_t intervalIdx = intervalSize; // will not run yet
millisDelay intervalTimer;
millisDelay mainTimer;

void setLed(bool ledStateON) {
  if (ledStateON) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }
}


void setup() {
  pinMode(ledPin, OUTPUT);
  ledStateON = false;
  setLed(ledStateON);
  mainTimer.start(10000); // run seq every 10sec
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) {
    Serial.print(' '); Serial.print(i);
    delay(500);
  }
  Serial.println();
}


void blinkSequence() {
  if (intervalIdx >= intervalSize) {
    return;
  }
  if (intervalTimer.justFinished()) {
    // toggle led and do next interval
    // if the LED is off turn it on and vice-versa:
    ledStateON = !ledStateON;
    setLed(ledStateON);
    // do next interval
    intervalIdx++;
    if (intervalIdx >= intervalSize) {
      ledStateON = false;
      setLed(ledStateON);
      return;
    } else {
      Serial.print(" intervalIdx:"); Serial.print(intervalIdx);
      intervalTimer.start(interval[intervalIdx]);
      Serial.print(" time:"); Serial.println(interval[intervalIdx]);
    }
  }
}

// check if we should start led sequence
void checkMainTimer() {
  if (mainTimer.justFinished()) {
    Serial.println(F("start seq"));
    mainTimer.repeat();
    intervalIdx = 0;
    intervalTimer.start(interval[intervalIdx]);
    ledStateON = true;
    setLed(ledStateON);
  }
}

void loop() {
  checkMainTimer();
  blinkSequence(); // does nothing if interval idx >= intervalSize
}

The delay time and number of blinks works really well using your library, starting to get familiar and optimistic this can do what I'm hoping for :sunglasses: Thank you!

Hey All, thanks for all the ideas, I've just come up with a simplified version that works for delaying blinks at different intervals, I'm using an array[2] and if/else to change from [0] to [1], seems to work quite well with less code, hope this helps anyone who's looking to do this and maybe helps everyone create something :sunglasses:

might be a convenient way to use several delays because you can just write say 10 different ones in the array, then switch them for your conditions - maybe you want regular blink but then like a strobe effect, this is basically what my program is going to be except it will just include a couple of different blink types, run for a specific period of time and be activated by a momentary button

thanks again for everyone's help!

//unsigned
uint32_t currentMillis = 0;
uint32_t prevMillis = 0;

//definitions
#define a 450 //define time LED is off for
#define b 50 //define time LED is on for

// array for delay times
const uint32_t delayShift [] = {a, b}; // array for switching delay times
uint32_t index = 0; //array index


//ints
int ledpin = 13; // set pin for LED


//bools
bool LED; // for writing LED on or off

void setup() {
  // setup code here, to run once:

  pinMode(ledpin, OUTPUT);

}


void loop() {
  //  main code here, to run repeatedly:


  currentMillis = millis();

  if (currentMillis - prevMillis >= delayShift[index] ) {
    LED = !LED;
    digitalWrite(ledpin, LED);
    if (index == 0) {
      index = 1;
    }
    else {
      index = 0;
    }
    prevMillis = currentMillis;

  }
}