Need some help converting delays to millis

I posted a couple of days ago about getting started with millis. I have researched this extensively and took your input but still do not understand how it works. Problem is, I figure out things by seeing examples. With that said, we are working on a project for a state STEM challenge. I have since updated my code from the previous competition. I will post the old code below:

#include "Adafruit_FONA.h"

#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4

#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);


// constants won't change:
const int disconnectPin = 5 ;     // button for auto emergency distress
const int cancelPin = 6             //button for cancelling
const int ledPin =  12;      // LED for distress will be called
const int recordPin = 11;         //trigger for automated phone call

// variables will change:
int disconnectState = 1;         // start button HIGH
int cancelState = 0;               //start button LOW
char gps_string[ 140 ];

void setup() {
  fonaSerial->begin(4800);
  fona.begin(*fonaSerial);
  fona.enableGPS(true);               //enable GPS function
  fona.getGPS( 0, gps_string, 140 );
  pinMode(ledPin, OUTPUT);            // initialize the LED pin as an output
  pinMode(disconnectPin, INPUT);      // initialize the pushbutton pin as an input
  pinMode(cancelPin, INPUT);          //initialize the pushbutton pin as an input
  pinMode(recordPin, OUTPUT);
}

void loop() {
  disconnectState = digitalRead(disconnectPin);
  fona.getGPS( 0, gps_string, 140 );
  
if (disconnectState == LOW) {
    digitalWrite(ledPin, LOW);
    digitalWrite(recordPin, LOW);
    fona.hangUp();}
else { 
    digitalWrite(ledPin, HIGH);
      delay( 5000);
    fona.sendSMS("5555555555", gps_string );
     delay(5000);
    fona.callPhone("5555555555");
      delay(10000);
    digitalWrite(recordPin, HIGH);
      delay(100);
    digitalWrite(recordPin, LOW);
      delay(15000);
  }
}

So basically, this code on an arduino nano is connected to a FONA SIM808 chip. When two wires disconnect, the nano will send a command to the FONA to text and call my phone. I want it to wait 30 seconds before it calls my phone so that I have time to cancel my action. Basically, in case of an accidental disconnection, I have 30 seconds to cancel everything. This will not work with a delay, obviously, but rather will work with millis as i am told. I have no idea how to even begin with this. I have never used it before. Can someone show my using my old code above how to implement millis into this code so that during the 30 seconds timeframe it will detect a button press and cancel everything. I really appreciate your time in reading this long spiel but I have no one else to teach this to me other than the arduino forums and google. Thanks again, Joe and team.

*** EDIT *** . - Josephm3502 - I posted several different variations of this code. I recommend looking at post #14 in this thread, as it not only addresses your inquiry, it's a clean and simple use of millis() without blocking program execution. I didn't install your libraries so I don't know if the code compiles but I went over it a couple of times and it should work fine.
*** EDIT ***

Here is an example of how I use millis() instead of delay.

First, I have a boilerplate method that I put in all my sketches called wait(). And it looks like this:

void wait(int m) {
  unsigned long startTime = millis();
  boolean waiting = true;
  while (waiting)
  {
    if ((millis() - startTime) >= m) waiting = false;
  }
}

So to use that instead of delay, I simply use wait(2500) - which will pause program execution for 2.5 seconds without consuming interrupts etc.

ALSO, if you need to check on something or click a routine regularly while the code is "waiting", you can add that code into the while loop and it'll get handled.

Mike

Okay that looks easier than millis already, but where do I put the if else statements that are in my code that are in the loop?

Ok so this is what I have so far

#include "Adafruit_FONA.h"

#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4

#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);


// constants won't change:
const int disconnectPin = 5;     // button for auto emergency distress
const int cancelPin = 6;             //button for cancelling
const int ledPin =  12;      // LED for distress will be called
const int recordPin = 11;         //trigger for automated phone call

// variables will change:
int disconnectState = 1;         // start button HIGH
int cancelState = 0;               //start button LOW
char gps_string[ 140 ];

void setup() {
  fonaSerial->begin(4800);
  fona.begin(*fonaSerial);
  fona.enableGPS(true);               //enable GPS function
  fona.getGPS( 0, gps_string, 140 );
  pinMode(ledPin, OUTPUT);            // initialize the LED pin as an output
  pinMode(disconnectPin, INPUT);      // initialize the pushbutton pin as an input
  pinMode(cancelPin, INPUT);          //initialize the pushbutton pin as an input
  pinMode(recordPin, OUTPUT);
}

void loop() {
  disconnectState = digitalRead(disconnectPin);
  fona.getGPS( 0, gps_string, 140 );
  
  if (disconnectPin == LOW) {
void wait(30000){
  unsigned long startTime = millis();
  boolean waiting = true;
while (waiting)
      digitalRead(cancelPin);
if (cancelPin == HIGH) 
      digitalWrite(ledPin, LOW);
      digitalWrite(recordPin, LOW);
    fona.hangUp();}
else { 
    digitalWrite(ledPin, HIGH);
      delay(1000);
    fona.sendSMS("5555555555", gps_string );
     delay(5000);
    fona.callPhone("5555555555");
      delay(10000);
    digitalWrite(recordPin, HIGH);
      delay(100);
    digitalWrite(recordPin, LOW);
      delay(15000);
  }
}

going through everything in my head, it looks okay step by step. I have many errors that are showing up but I want to get a second pair of eyes on this to see if i am going in the right direction. If so, what do i need to do to fix these errors?

Thought this looked familiar: Did you ever try the suggestion in post #3 here:

Why did you drop out of that thread without respondng only to come back 3 weeks later asking the same thing now??

I thought I understood it enough and when I went back to it I figured nobody would respond to it because it was an old thread. I need something easy for me to understand that will work. I only have a week and a half until I present this in front of the whole state, including the governor. Everything works okay as far as calling and texting goes...but I figured that a cancel button would prove to be crucial in a real life situation so I wanted to add it in. I'm sorry it is my fault for waiting until last second to ask. I am just overwhelmed and nervous about everything, especially because of time. Its not a big deal if I get it to work...I can always say that it would be one of my future improvements. : )

OK, I massaged your code a little … if you start by reading through Loop() it should read easily and make sense… i’d be happy to discuss anything that doesn’t make sense.

#include "Adafruit_FONA.h"

#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4

#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);


// constants won't change:
const int disconnectPin = 5 ;     // button for auto emergency distress
const int cancelPin = 6             //button for cancelling
const int ledPin =  12;      // LED for distress will be called
const int recordPin = 11;         //trigger for automated phone call
const int Disconnected = HIGH;
const int Connected = LOW;


// variables will change:
int disconnectState = 1;         // start button HIGH
int cancelState = 0;               //start button LOW
char gps_string[ 140 ];

void wait(int m) {
  long startTime = millis();
  boolean waiting = true;
  while (waiting)
  {
    if ((millis() - startTime) >= m) waiting = false;
  }
}

boolean fonaConnected() {
  boolean ret = false; // return variable
  if (digitalRead(disconnectPin) == Connected){
    ret = true;
  }
  fona.getGPS( 0, gps_string, 140 );
  return ret;
}

boolen reconnected(int m){
  unsigned long startTime = millis();
  boolean keepWaiting = true;
  boolean reconnected = false;
  
  while (!reconnected && keepWaiting) {
    if(fonaConnected()) reconnected = true;
    if((millis() - startTime) >= m) keepWaiting = false;
  }
  return reconnected;
}

void ledON(){
  digitalWrite(ledPin, HIGH);
}

void ledOFF(){
  digitalWrite(ledPin, LOW);
}

void sendText(){
    if(!reconnected(30000)){
      fona.sendSMS("5555555555", gps_string );
      wait(5000);
      fona.callPhone("5555555555");
      wait(10000);
      digitalWrite(recordPin, HIGH);
      wait(100);
      digitalWrite(recordPin, LOW);
      wait(15000);
    }
    else {
      ledOff();;
    }
}

void setup() {
  fonaSerial->begin(4800);
  fona.begin(*fonaSerial);
  fona.enableGPS(true);               //enable GPS function
  fona.getGPS( 0, gps_string, 140 );
  pinMode(ledPin, OUTPUT);            // initialize the LED pin as an output
  pinMode(disconnectPin, INPUT);      // initialize the pushbutton pin as an input
  pinMode(cancelPin, INPUT);          //initialize the pushbutton pin as an input
  pinMode(recordPin, OUTPUT);
}

void loop() {
    if (!fonaConnected()) {
      ledON();
      sendText();
    }
    else {
      ledOFF();
      digitalWrite(recordPin, LOW);
      fona.hangUp();
    }
}

That wait function in above posts is blocking (just like delay).

The advantage is that you can break out of its while loop under certain conditions.

I massaged your code a little

and in doing so you managed to write blocking function using millis(). You might just as well have used delay()

The many examples in Using millis() for timing. A beginners guide and Several things at the same time show you how it should be done

UKHeliBob:
and in doing so you managed to write blocking function using millis(). You might just as well have used delay()

The many examples in Using millis() for timing. A beginners guide and Several things at the same time show you how it should be done

It is NOT the same as delay because it can be massaged to do other things or even respond to interrupts UNLIKE delay ... and I also wrote in the code a function that meets his criteria which is to start an event but wait 30 seconds for user interaction before said event takes place and if user takes action, then do not run said event ...

Did you manage to see that one?

sterretje:
The advantage is that you can break out of its while loop under certain conditions.

Which is why I always use that method for pausing execution. Im working on a program now that has 10 different millis() based timed events happening at differing intervals of time ... its the closest I can get to anything resembling multithreading ... MAN If only I could write sketches in fully functional Java ... i'd be unstoppable :slight_smile:

I'd use a pi if they weren't just scaled down PCs ... where's the fun in that?

:slight_smile:

Hello EasyGoing1

The way you use it in your example, it's blocking.

Regards,
bidouilleelec

bidouilleelec:
Hello EasyGoing1

The way you use it in your example, it's blocking.

Regards,
bidouilleelec

I'm not disputing that point ... it is a basic template that can be massaged as needed, thereby yielding more potential than delay.

Did you look at the function called reconnected() ?

EasyGoing1:
I'm not disputing that point ... it is a basic template that can be massaged as needed, thereby yielding more potential than delay.

Did you look at the function called reconnected() ?

Oh!
I beg your pardon.

Regards,
bidouilleelec

OK you bunch of OCD freaks … here is your NON-BLOCKING version with added feature of re-sending the text alert every 20 minutes until the red alert has been dealt with.

#include "Adafruit_FONA.h"

#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4

#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);


// constants won't change:
const int disconnectPin = 5 ;     // button for auto emergency distress
const int cancelPin = 6             //button for cancelling
const int ledPin =  12;      // LED for distress will be called
const int recordPin = 11;         //trigger for automated phone call
const int Disconnected = HIGH;
const int Connected = LOW;
const int reconnectDelayTime = 30000; //30 seconds
const int repeatTextDelay = 1200000; //20 minutes

unsigned long disconnectStartTime;
unsigned long disconnectElapsedTime;
unsigned long repeatTextStartTime;
unsigned long repeatTextElapsedTime;

boolean disconnectMode = false;
boolean repeatTextMode = false;

// variables will change:
char gps_string[ 140 ];


boolean fonaConnected() {
  boolean ret = false; // return variable
  if (digitalRead(disconnectPin) == Connected){
    ret = true;
  }
  fona.getGPS( 0, gps_string, 140 );
  return ret;
}

void ledON(){
  digitalWrite(ledPin, HIGH);
}

void ledOFF(){
  digitalWrite(ledPin, LOW);
}

void sendText(){
  fona.sendSMS("5555555555", gps_string );
  delay(5000);
  fona.callPhone("5555555555");
  delay(10000);
  digitalWrite(recordPin, HIGH);
  delay(100);
  digitalWrite(recordPin, LOW);
  delay(15000);
}

void setup() {
  fonaSerial->begin(4800);
  fona.begin(*fonaSerial);
  fona.enableGPS(true);               //enable GPS function
  fona.getGPS( 0, gps_string, 140 );
  pinMode(ledPin, OUTPUT);            // initialize the LED pin as an output
  pinMode(disconnectPin, INPUT);      // initialize the pushbutton pin as an input
  pinMode(cancelPin, INPUT);          //initialize the pushbutton pin as an input
  pinMode(recordPin, OUTPUT);
}

void loop() {
    if (!fonaConnected() && !disconnectMode) {
      ledON();
      disconnectMode = true;
      disconnectStartTime = millis();
    }
    else {
      ledOFF();
      digitalWrite(recordPin, LOW);
      fona.hangUp();
    }
    if (fonaConnected() && disconnectMode) {//If someone reconnects, then stand down the alert (texting) and reset variables
      disconnectMode = false;
      repeatTextMode = false;
      ledOFF;
    }
    if (disconnectMode && !repeatTextMode){ //This will start and monitor the first 30 seconds after the disconnect. Then the mode changes to sending texts every 20 minutes.
      disconnectElapsedTime = millis() - disconnectStartTime;
      if(disconnectElapsedTime >= reconnectDelayTime) {//wait 30 seconds for someone to reconnect the darn thing then send the text if not reconnected
        sendText();
        repeatTextMode = true;
        repeatTextStartTime = millis();
      }
    }

    if (disconnectMode && repeatTextMode){
      repeatTextElapsedTime = millis() - repeatTextStartTime;
      if (repeatTextElapsedTime >= repeatTextDelay) {// Send a text every 20 minutes ... this event timer will stop once reconnection happens.
        sendText();
        repeatTextStartTime = millis();
      }
    }
}

… and here is yet another version that checks for reconnection while its going through the process of sending a text … not one wasted millisecond on that reconnect state … waste not, want not … :slight_smile:

(YES, it’s overkill … but somehow it seems appropriate for this motley crew lol)

#include "Adafruit_FONA.h"

#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4

#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);


// constants won't change:
const int disconnectPin = 5 ;     // button for auto emergency distress
const int cancelPin = 6             //button for cancelling
const int ledPin =  12;      // LED for distress will be called
const int recordPin = 11;         //trigger for automated phone call
const int Disconnected = HIGH;
const int Connected = LOW;
const int reconnectDelayTime = 30000; //30 seconds
const int repeatTextDelay = 1200000; //20 minutes

unsigned long disconnectStartTime;
unsigned long disconnectElapsedTime;
unsigned long repeatTextStartTime;
unsigned long repeatTextElapsedTime;

boolean disconnectMode = false;
boolean repeatTextMode = false;

// variables will change:
char gps_string[ 140 ];


boolean fonaConnected() {
  boolean ret = false; // return variable
  if (digitalRead(disconnectPin) == Connected){
    ret = true;
  }
  fona.getGPS( 0, gps_string, 140 );
  return ret;
}

void ledON(){
  digitalWrite(ledPin, HIGH);
}

void ledOFF(){
  digitalWrite(ledPin, LOW);
}
boolean reconnected(int m){
  unsigned int startTime = millis();
  boolean disconnected = true;
  boolean waiting = true;
  while(disconnected && waiting) {
    waiting = !((millis() - startTime) >= m);
    disconnected = !fonaConnected();
  }
  return !disconnected;
}
void sendText(){
  fona.sendSMS("5555555555", gps_string );
  if(reconnected(5000)) return;
  fona.callPhone("5555555555");
  if(reconnected(10000)) return;
  digitalWrite(recordPin, HIGH);
  if(reconnected(100)) return;
  digitalWrite(recordPin, LOW);
  if(reconnected(15000)) return;
}

void setup() {
  fonaSerial->begin(4800);
  fona.begin(*fonaSerial);
  fona.enableGPS(true);               //enable GPS function
  fona.getGPS( 0, gps_string, 140 );
  pinMode(ledPin, OUTPUT);            // initialize the LED pin as an output
  pinMode(disconnectPin, INPUT);      // initialize the pushbutton pin as an input
  pinMode(cancelPin, INPUT);          //initialize the pushbutton pin as an input
  pinMode(recordPin, OUTPUT);
}

void loop() {
    if (!fonaConnected() && !disconnectMode) {
      ledON();
      disconnectMode = true;
      disconnectStartTime = millis();
    }
    else {
      ledOFF();
      digitalWrite(recordPin, LOW);
      fona.hangUp();
    }
    if (fonaConnected() && disconnectMode) {//If someone reconnects, then stand down the alert (texting) and reset variables
      disconnectMode = false;
      repeatTextMode = false;
      ledOFF;
    }
    if (disconnectMode && !repeatTextMode){ //This will start and monitor the first 30 seconds after the disconnect. Then the mode changes to sending texts every 20 minutes.
      disconnectElapsedTime = millis() - disconnectStartTime;
      if(disconnectElapsedTime >= reconnectDelayTime) {//wait 30 seconds for someone to reconnect the darn thing then send the text if not reconnected
        sendText();
        repeatTextMode = true;
        repeatTextStartTime = millis();
      }
    }

    if (disconnectMode && repeatTextMode){
      repeatTextElapsedTime = millis() - repeatTextStartTime;
      if (repeatTextElapsedTime >= repeatTextDelay) {// Send a text every 20 minutes ... this event timer will stop once reconnection happens.
        sendText();
        repeatTextStartTime = millis();
      }
    }
}

Looking back, you presented your wait() function as a general purpose solution in reply #1 then later introduced your reconnected() function without initially mentioning it. No wonder there has been confusion, including on my part.

Im working on a program now that has 10 different millis() based timed events happening at differing intervals of time

How does your wait() function, or a derivative of it, help when dealing with multiple timed events if some/all are happening simultaneously ?

UKHeliBob:
Looking back, you presented your wait() function as a general purpose solution in reply #1 then later introduced your reconnected() function without initially mentioning it. No wonder there has been confusion, including on my part.
How does your wait() function, or a derivative of it, help when dealing with multiple timed events if some/all are happening simultaneously ?

It doesn't ... I use non-blocking millis() unsigned long variable tracking ... LOL

OK ... the wait thing was just ... whatever ... I take it all back ... :slight_smile:

Honestly, I snapped my first reply off without really thinking about what was being asked ... I figured a little sample of using Millis() and the guy could take it and run with it ... then all you guys started to get all particular about it ...

Programmers ... hmph!

:smiley:

I figured a little sample of using Millis() and the guy could take it and run with it

The problem is that unless you have had previous experience of helping the poster then you have no way of knowing whether they are capable of taking an example and expanding on it to meet their needs. Sometimes you can get an inkling of their experience and abilities from the way that the question is asked, the level of detail given and the their code if any is posted.

I tend to answer in one of several ways ranging from "look at this tutorial" through "here is some pseudo code" right through to "here is the code that does what you want" but it is not easy to hit the right level. Another factor is, that being a forum, others join in and make suggestions often very different from what has already been suggested, thus confusing the issue even more. I, of course, am never guilty of doing that :slight_smile:

You and I both understand that there is nothing fundamentally wrong with your wait() function boilerplate, if it is used properly and in the right context, but a newcomer may not realise this, hence the need to explain things that seem obvious.

Overall, all we can do is to provide the best help possible and responding to follow up questions as and when they arise

UKHeliBob:
The problem is that unless you have had previous experience of helping the poster then you have no way of knowing whether they are capable of taking an example and expanding on it to meet their needs.

You are absolutely correct. I was obviously being … wreckless and assumptive (mainly).

UKHeliBob:
Sometimes you can get an inkling of their experience and abilities from the way that the question is asked, the level of detail given and the their code if any is posted.

I tend to answer in one of several ways ranging from “look at this tutorial” through “here is some pseudo code” right through to “here is the code that does what you want” but it is not easy to hit the right level. Another factor is, that being a forum, others join in and make suggestions often very different from what has already been suggested, thus confusing the issue even more. I, of course, am never guilty of doing that :slight_smile:

You and I both understand that there is nothing fundamentally wrong with your wait() function boilerplate, if it is used properly and in the right context, but a newcomer may not realise this, hence the need to explain things that seem obvious.

Overall, all we can do is to provide the best help possible and responding to follow up questions as and when they arise

I taught myself how to program back in 1982 on my C=64 … All of my computer and IT knowledge is 100% self taught except for two Java classes and formal OOP classes when I majored in CIS in college (later in life after I was already established as a network engineer) … the traditional learning curve with all things computers has never been my path to knowledge … so Im not usually mindful of it …

In hind sight, I can see the good and the bad in the way I educated myself … the bad is in the lack of thoroughness on topics I dearly wish I had a broader understanding of (these micro controllers for example and the connection or understanding of writing code for them at lower levels … )

Thank you for taking the time to discuss this with me. It is sound advice that I needed to read.

Onward and upward! :slight_smile:

Mike Sims