Understanding millis()

Hello!

So, I have this code, that works just fine for what I intend him to do, my doubt is not to make it work. I know this may seem weird, but my doubt is actually why does it work? xD I've seen the millis Beginners guide and the blink without delay, and that's where I took that bit of the code from.

So, my actual doubt is, why does the millis counting work? I mean if the startMillis=millis() isn't it supposed that this number is bigger than currentMillis?

And, for example, how can (currentMillis-startMillis) be possible in the "ciclo1" sub function if I haven't even said what currentMillis is?

That operation should result in a negative number shouldn't it, since startMillis is increasing with the passage of time?

I'm sorry about all the questions. I just got this code to work by trying over and over again and messing with the code, and when I put it like that it worked, but I just don't undestand why. Hope you can help me, thanks!

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::DRIVER, 9, 8); //entradas motor (9 é step control(CLK+), 8 é direction(CW+))      (motor-azul(A+)-vermelho(A-)-preto(B+)-verde(B-)
AccelStepper stepper2(AccelStepper::DRIVER, 7, 6);

int press1 = 0;
int press2 = 0;
int fdc1=3;                                     //fins de curso---> atenção corresponder fins de curso superiores ou inferiores ao devido movimento dos motores
int fdc2=12;                                    //fins de curso a utilizar resistência de 10k para pull-down
int led=13;                                     //led representa a válvula de entrada de água
const unsigned long period1 = 10000;            //período circulação água (em milisegundos)
const unsigned long period2 = (10000+period1);  //período água enchimento (em milisegundos)
const unsigned long period3 = (10000+period2);  //período água no reservatório (em milisegundos)
const unsigned long period4 = (10000+period3);  //período escoamento (em milisegundos)
int Nciclos=1;                                  //nº de ciclos totais (1 ciclo corresponde à passagem de água quente OU fria e não à passagem de uma seguida pela outra)
unsigned long startMillis;  
unsigned long currentMillis;


void setup() {
 startMillis=millis();
  stepper1.setMaxSpeed(5000);
  stepper1.setAcceleration(1000);
  stepper2.setMaxSpeed(5000);
  stepper2.setAcceleration(1000);
  pinMode(fdc1,INPUT);
  pinMode(fdc2,INPUT);
  pinMode(led,OUTPUT);

  
}

void loop() {

for (int i=1; i<=Nciclos; i++) {
ciclo1();   //ciclo de circulação de água pelo reservatório
ciclo2();   //ciclo de enchimento do reservatório
ciclo3();   //água estagnada dentro do reservatório
ciclo4();   //esvaziamento do reservatório
startMillis=currentMillis;  //reinicia o tempo
}
for (;;) {}
}

void ciclo1() {

  while (currentMillis-startMillis<=period1) {

currentMillis=millis();
digitalWrite(led, HIGH);
stepper1.setSpeed(500);
stepper2.setSpeed(500);
stepper1.run();
stepper2.run();

press1=digitalRead(fdc1);
   if (press1==HIGH) {
   
    digitalWrite(9, LOW);
    delay(500);          
    digitalWrite(7, LOW); 
    delay(500);
   }
 
}
}

void ciclo2() {

  while ((period1<currentMillis-startMillis) and (currentMillis-startMillis<=period2)) {
   currentMillis=millis();

stepper1.setSpeed(-500);
stepper2.setSpeed(-500);
stepper1.run();
stepper2.run();
press2=digitalRead(fdc2);
       if (press2==HIGH) {
        
     
    digitalWrite(9, LOW);
    delay(500);          
    digitalWrite(7, LOW); 
    delay(500);
       }
}
}

void ciclo3() {

 while ((period2<currentMillis-startMillis) and (currentMillis-startMillis<=period3)) {
   currentMillis=millis();
   digitalWrite(led,LOW);
 }
}

void ciclo4() {

 while ((period3<currentMillis-startMillis) and (currentMillis-startMillis<=period4)) {
   currentMillis=millis();

stepper1.setSpeed(500);
stepper2.setSpeed(500);
stepper1.run();
stepper2.run();
 press1=digitalRead(fdc1);
       if (press1==HIGH) {
        
     
    digitalWrite(9, LOW);
    delay(500);          
    digitalWrite(7, LOW); 
    delay(500);
       }
}
}

how can (currentMillis-startMillis) be possible in the "ciclo1" sub function if I haven't even said what currentMillis is?

void ciclo1()
{
  while (currentMillis - startMillis <= period1)
  {
    currentMillis = millis();

Here is where the value of currentMillis is set. startMillis was set to zero when it was declared

But by using a while loop waiting for millis() to reach a certain value you have written blocking code which is often not a good idea. To compound things you have then incorporated a 1 second delay() into the function which ensures that the code does nothing for 1 second.

The essence of using millis() for timing is to allow loop() to run freely and check each time through loop() whether it is time to do something. Your code does not do that.

It appears to me that you have defined a function named void ciclo1() within loop(), which is incorrect. It is easier to see this if you place the IDE cursor in the source code window and press Ctrl-T. This will reformat your code and make it easier to see what I mean.

Basically, you are right: it's written rather badly. startMillis and currentMillis both start off as 0, because they are globally defined. The test in ciclo1()

  while (currentMillis-startMillis<=period1)

works because 0 is <= period1, and startMillis will get set during the first iteration of that loop.

Since the timers are independent it makes the code cleaner to use local variables rather than globals:

#include <AccelStepper.h>


AccelStepper stepper1(AccelStepper::DRIVER, 9, 8); //entradas motor (9 é step control(CLK+), 8 é direction(CW+))      (motor-azul(A+)-vermelho(A-)-preto(B+)-verde(B-)
AccelStepper stepper2(AccelStepper::DRIVER, 7, 6);


int press1 = 0;
int press2 = 0;
const int fdc1 = 3;                                   //fins de curso---> atenção corresponder fins de curso superiores ou inferiores ao devido movimento dos motores
const int fdc2 = 12;                                  //fins de curso a utilizar resistência de 10k para pull-down
const int led = 13;                                   //led representa a válvula de entrada de água
const unsigned long period1 = 10000; //período circulação água (em milisegundos)
const unsigned long period2 = 10000; //período água enchimento (em milisegundos)
const unsigned long period3 = 10000; //período água no reservatório (em milisegundos)
const unsigned long period4 = 10000; //período escoamento (em milisegundos)
int Nciclos = 1;                                //nº de ciclos totais (1 ciclo corresponde à passagem de água quente OU fria e não à passagem de uma seguida pela outra)


void setup()
{
  stepper1.setMaxSpeed(5000);
  stepper1.setAcceleration(1000);
  stepper2.setMaxSpeed(5000);
  stepper2.setAcceleration(1000);
  pinMode(fdc1, INPUT);
  pinMode(fdc2, INPUT);
  pinMode(led, OUTPUT);
}


void loop()
{


  for (int i = 0; i < Nciclos; i++)
  {
    ciclo1();   //ciclo de circulação de água pelo reservatório
    ciclo2();   //ciclo de enchimento do reservatório
    ciclo3();   //água estagnada dentro do reservatório
    ciclo4();   //esvaziamento do reservatório
  }
  for (;;) {}
}


void ciclo1()
{
  unsigned long startMillis = millis();


  while (millis() - startMillis <= period1)
  {
    digitalWrite(led, HIGH);
    stepper1.setSpeed(500);
    stepper2.setSpeed(500);
    stepper1.run();
    stepper2.run();


    press1 = digitalRead(fdc1);
    if (press1 == HIGH)
    {
      digitalWrite(9, LOW);
      delay(500);
      digitalWrite(7, LOW);
      delay(500);
    }
  }
}


void ciclo2()
{
  unsigned long startMillis = millis();


  while (millis() - startMillis <= period2)
  {
    stepper1.setSpeed(-500);
    stepper2.setSpeed(-500);
    stepper1.run();
    stepper2.run();
    press2 = digitalRead(fdc2);
    if (press2 == HIGH)
    {
      digitalWrite(9, LOW);
      delay(500);
      digitalWrite(7, LOW);
      delay(500);
    }
  }
}


void ciclo3()
{
  unsigned long startMillis = millis();
  
  while (millis() - startMillis <= period3)
  {
    digitalWrite(led, LOW);
  }
}


void ciclo4()
{
  unsigned long startMillis = millis();


  while (millis() - startMillis <= period4)
  {
    stepper1.setSpeed(500);
    stepper2.setSpeed(500);
    stepper1.run();
    stepper2.run();
    press1 = digitalRead(fdc1);
    if (press1 == HIGH)
    {
      digitalWrite(9, LOW);
      delay(500);
      digitalWrite(7, LOW);
      delay(500);
    }
  }
}

I think also that familiarity has left us a bit short on explanation.

currentMillis is an abstraction that is used often as a temporary value meaning now. It cannot however, be used without first assigning it a value. The test for elapsed time should be

if (currentMillis - startMillis <= period1)

and is invariably preceded immediately by

currentMillis = millis();