Guidance for Implementation of millis()

I want to use an SQ11 camera with arduino. To do this I am triggering it by attaching a wire to power on switch of the camera with A1 pin of my Nano 33 BLE. The delay code works perfectly, but I want to implement the same without delay and create its function which I can call whenever I want to trigger it. I have tried using millis() for small part of the delay code, but its not working. I am posting both the codes below.

Delay Code:

void setup() {

  pinMode(A7, OUTPUT);

  digitalWrite(A7, HIGH);  //Turn on camera
  delay(2100);
  digitalWrite(A7, LOW);

  delay(50);
  digitalWrite(A7, HIGH);  //Start Recording
  delay(50);
  digitalWrite(A7, LOW);

  delay(6000);  //Record video for 6 sec

  digitalWrite(A7, HIGH);  //Stop Recording
  delay(50);
  digitalWrite(A7, LOW);
}

void loop() {
}

Millis Code:

unsigned int milli2100, milli50, milli501;

void setup() {
  pinMode(A7, OUTPUT);
  camera();  //Function created to Trigger when set condition is met
}


void loop() {
}

void camera() {

  digitalWrite(A7, HIGH);

  if (millis() - milli2100 >= 2100) {
    milli2100 += 2100;
    digitalWrite(A7, LOW);

    if (millis() - milli50 >= 50) {
      milli50 += 50;
      digitalWrite(A7, HIGH);
      if (millis() - milli501 >= 50) {
        milli501 += 50;
        digitalWrite(A7, LOW);
      }
    }
  }
}

Please explain why. It's going to take significant time and effort for you and us forum members to get your code and your level of understanding to the right level for that. So let's be sure there is a real need not to use delay() before we get into all that.

I want to use the camera in a project which needs to respond in real time, so I want to avoid using delay.

You can have the camera react in real time using delay().

During the 8.2 seconds while the camera is recording, what else will the Arduino be doing?

do you really want the A7 to be HIGH for 2100 msec or do you want it to be HIGH for 50 msec and there be a 2100 msec delay before the next cycle?

Please detail the timing requirements for us. We shouldn't have to reverse engineer that from your code.

Yes, to turn on the camera, I need to keep A7 pin high for 2 sec. Also, I can't keep the camera on by default since it has 1 minute auto shutdown built in.

That isn't complete. I can tell just by looking at the first sketch. Please be more detailed and precise. Where did you get the delay values? If you have information resources, you should share them here.

The way I would do this with millis(), is to make a look up table of the delays, and also the pin states. Then I would index and increment through the table, feed the output of that to the delay logic.

1st Step:
Keep the A7 pin HIGH for 2.1 sec to power on the camera. After the 2.1s have passed, make the pin LOW and wait for 50ms before performing step2.

2nd Step:
Send a HIGH pulse of 50 ms to start recording i.e. Keep the pin HIGH for 50 ms and then make it LOW after the pin has been HIGH for 50ms which is similar to a button press.

3rd Step:
Repeat Step 2 to stop recording

Okay. What other actions need to be performed while the delays are in progress?

There are many sensor datas like roll,pitch,yaw,pressure,altitude, latitude,longitude, etc which I need to send over radio, along with 2 PID controllers running simultaneously to maintain roll and pitch

Hmmm so the table is

initially L

H 2100ms
L you didn't say
H 50ms
L you didn't say
H 50ms
L you didn't say

since each transition is a toggle, you can condense it to a list of delays:

2100
?
50
?
50
?

So your millis() code just needs to pick the next delay from the table, and toggle the output.

As you found out, doing it with nested 'if' logic, creates a big mess even if it can be made to work (which I'm not sure of).

@dhir_33

try something like:

/*
  switch on/off one pin (?) in a sequence
  
  https://forum.arduino.cc/t/guidance-for-implementation-of-millis/1105654/13

  by noiasca
  2023-03-23

  to be deleted 2023-06
  code in Forum
*/
const uint8_t pin = 13; // could be A7 on another microcontroller;

// not used any more - just as guide what's requested
void blocking() {
  pinMode(A7, OUTPUT);
  digitalWrite(A7, HIGH);  //Turn on camera
  delay(2100);
  digitalWrite(A7, LOW);
  delay(50);
  digitalWrite(A7, HIGH);  //Start Recording
  delay(50);
  digitalWrite(A7, LOW);
  delay(6000);  //Record video for 6 sec
  digitalWrite(A7, HIGH);  //Stop Recording
  delay(50);
  digitalWrite(A7, LOW);
}

// define the states of your sequence:
enum State {IDLE, ON_PULSE, ON, RECORDING_PULSE, RECORDING, STOP_PULSE, STOP};
static State state;           // the current state of the sequence
uint32_t previousMillis = 0;  // time management for the sequence

// start the sequence
void start() {
  previousMillis = millis();
  digitalWrite(pin, HIGH);
  state = ON_PULSE;
}

// call the finite state machine and run through the states
void runFSM() {
  uint32_t currentMillis = millis();
  switch (state) {
    case ON_PULSE :
      if (currentMillis - previousMillis > 2100) {
        previousMillis = currentMillis;     // time management
        Serial.println(F("end ON_PULSE"));  // write to serial to keep track what's happening
        digitalWrite(pin, LOW);             // do something
        state = ON;                         // next state
      }
      break;
    case ON :
      if (currentMillis - previousMillis > 50) {
        previousMillis = currentMillis;
        Serial.println(F("end ON"));
        digitalWrite(pin, HIGH);
        state = RECORDING_PULSE;
      }
      break;
    case RECORDING_PULSE :
      if (currentMillis - previousMillis > 50) {
        previousMillis = currentMillis;
        Serial.println(F("end RECORDING_PULSE"));
        digitalWrite(pin, LOW);
        state = RECORDING;
      }
      break;
    case RECORDING :
      if (currentMillis - previousMillis > 6000) {
        previousMillis = currentMillis;
        Serial.println(F("end RECORDING"));
        digitalWrite(pin, HIGH);
        state = STOP_PULSE;
      }
      break;
    case STOP_PULSE :
      if (currentMillis - previousMillis > 50) {
        previousMillis = currentMillis;
        Serial.println(F("end STOP_PULSE"));
        digitalWrite(pin, LOW);
        state = STOP;  
      }
      break;
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(pin, OUTPUT);
  start();   // start the sequence
}

void loop() {
  runFSM();  // run the sequence
}

for sure it can be much less code. But this should show you how to implement a logic to do different things in a sequence. The concept is a "finite state machine" where each new step is triggered when the time has passed.

1 Like

Thanks a lot! It works perfectly. Can you suggest any references where I can learn this concept in detail?

a little awkward

#undef MyHW
#ifdef MyHW
# include "sim.hh"
const byte PinCam = LED_BUILTIN;

#else
const byte PinCam = A7;
#endif

unsigned long msecSeq [] = { 2100, 50, 50, 6000, 50, 1 };
const int     Nseq = sizeof(msecSeq) / sizeof(long);
int           idxSeq;

unsigned long msecPeriod;
unsigned long msecLst;
unsigned long msec;

char s [80];

// -------------------------------------
void camera (void)
{
    if (Nseq <= idxSeq)
        return;

    if (0 == idxSeq || (msec - msecLst >= msecPeriod))  {
        msecLst    = msec;
        msecPeriod = msecSeq [idxSeq];
        digitalWrite(PinCam, ! digitalRead (PinCam));

        sprintf (s, "%s: %4lu msec, %d",
            __func__, msecPeriod, digitalRead(PinCam));
        Serial.println (s);

        if (Nseq < ++idxSeq)
            msecPeriod = 0;
    }
}

// -----------------------------------------------------------------------------
void loop()
{
    msec = millis ();
    camera ();
}

void setup()
{
    Serial.begin (9600);
    pinMode(PinCam, OUTPUT);
    digitalWrite(PinCam, LOW);
}
1 Like

I like the explanation on Wikipedia.

and I like drawings. For example the UML state machine

(imho the German article is better than the English one...)

p.s.:

I think it should be pretty clear, that you can use the "start()" more often.
Furthermore you can decide what should happen if you press "start()" when the sequence is already running. Easiest way would be if you just accept "start()" in IDLE and STOP.

Furthermore you can consider to just use IDLE or STOP (and omit the other state).
Again I think a nice drawing of a state diagram will make it obvious what you will need.

1 Like

Ok then, I agree you have a valid reason to not use delay().

Many newcomers to the forum are convinced that they must not use delay(), otherwise the gods will strike them down or something, but have no actual reason not to use delay(), because their Arduino would be doing nothing else anyway.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.