Millis

Hi there.

I've been working on this project where I want to calculate the passed time during a state. I need to do it using the function millis().
When I write the code with delays, everything works well. However when I add my if parameters, I can't get what I want.
As you will see in the picture where I compare the two codes, I want to start counting once my pin reads HIGH and store that value (with "ilk") until the pin reads a LOW ("son") and store that too. Then subtract the two stored values from each other to give me the time that passed between a LOW and a HIGH state.
The problem is, as the millis keeps running, the value for "ilk" will always follow it. What I want to do is to keep the first value of the millis when its on a HIGH state and store it and don't change it UNTIL I get a LOW state. Then when the HIGH state repeats it shall change.
I hope I could make things clear.

Thanks in advance.

/CODE WITHOUT IF PARAMETERS/

int ilk,son,fark;

void setup() {
 Serial.begin(9600);
 
}

void loop() {
  

ilk = millis();
    
Serial.print("ilk:");
Serial.println(ilk);

delay(1000);
 
son = millis();

Serial.print("son:");
Serial.println(son);

fark = son - ilk;
Serial.print("fark:");
Serial.println(fark);
Serial.print("\n");
}

/CODE WITH THE IF PARAMETERS/

int pin=9;
int state, last_state;
int ilk,son,fark;

void setup() {
 Serial.begin(9600);
 pinMode(pin, INPUT_PULLUP);
}

void loop() {
state=digitalRead(pin);


if(state==HIGH){
  ilk = millis();
  Serial.println("on");
}
if(state!=last_state){
  
  if(state==LOW){
son = millis();    
  Serial.println("\noff");
  Serial.print("ilk:");
  Serial.println(ilk);  
  Serial.print("son:");
  Serial.println(son);
}

last_state=state;

}


}

From looking at your program I'm not sure what you want to happen. The usual way to use millis() to time something is to save the value when the action starts and then check for when the time interval has elapsed - something like this

if (millis() - actioStartTime >=  interval) {
   // time is up
   // do something
}

NOTE that all variables used with millis() must be defined as unsigned long - and not int as you have done

Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.

And see Using millis() for timing. A beginners guide if you need more explanation.

...R

The problem is, as the millis keeps running, the value for "ilk" will always follow it. What I want to do is to keep the first value of the millis when its on a HIGH state and store it and don't change it UNTIL I get a LOW state

Compare the state of the pin with what it was the previous time you read it. If it has changed then determine whether it is now HIGH or LOW. If it is now HIGH, save the value of millis(). If it is now LOW then the timing period is over. Save the value of millis() now and do whatever you need with the start and end values.

You seem to be trying to do this in your code but need to save the value of millis() only when the state has changed, not every time through loop()

Great advice! Thanks a lot!

However, due to my inexperience; I couldn't make it work still ::slight_smile: The value for "fark" is absurd (4294965223~)

unsigned long ilk,son,fark;

int pin=9,oku,son_oku;

void setup() {

 Serial.begin(9600);

 pinMode(pin, INPUT_PULLUP);

}



void loop() {

  

oku = digitalRead(pin);



if(oku!=son_oku){

if(oku==HIGH){

ilk = millis();

    

Serial.print("ilk:");

Serial.println(ilk);



}

son_oku=oku;

}



if(oku!=son_oku){

if(oku==LOW){

son = millis();



Serial.print("son:");

Serial.println(son);



}

son_oku=oku;

}



fark = son - ilk;

Serial.print("fark:");

Serial.println(fark);

Serial.print("\n");



}

Oh okay! I got it :slight_smile:

unsigned long ilk,son,fark;

int pin=9,oku,son_oku;

void setup() {

 Serial.begin(9600);

 pinMode(pin, INPUT_PULLUP);

}



void loop() {

  

oku = digitalRead(pin);



if(oku!=son_oku){

if(oku==HIGH){

ilk = millis();  

Serial.print("ilk:");

Serial.println(ilk);

}



else if(oku==LOW){

son = millis();

Serial.print("son:");

Serial.println(son);

fark = son - ilk;

Serial.print("fark:");

Serial.println(fark);

Serial.println("*************");

}

son_oku=oku;

}

}

You will find it much better to format your code.

Use ‘CTRL T’ or ‘CMD T’ to get your code into a more readable state.

This has been a useful thread for me, as I'm just learning how to apply similar 'millis/state combinations'. I was getting close after an hour or so, before seeing your successful code, thanks.

I made some changes:

  • from your (Turkish?) variable names so that I could better follow it:
  • used <Ctrl + t> to autoformat it
  • increased baud rate to 115200 instead of 9600
  • Used pin 6 instead of 9

One minor query: I'm using a mini-button on my breadboard to deliver the low inputs to pin 6 and I'm puzzled why the serial output always shows the first line of the output when I release the button. I expected to see all three lines as soon as I pressed the button?

unsigned long first, last, difference;
int pin = 6, read, last_read; // Changed from pin 9
void setup()
{
  Serial.begin(115200);

  pinMode(pin, INPUT_PULLUP);
}

void loop()
{

  read = digitalRead(pin);

  if (read != last_read)
  {

    if (read == HIGH)
    {

      first = millis();

      Serial.print("first:");

      Serial.println(first);

    }

    else if (read == LOW)
    {

      last = millis();

      Serial.print("last:");

      Serial.println(last);

      difference = last - first;

      Serial.print("difference (ms):");

      Serial.println(difference);

      Serial.println("*************");

    }

    last_read = read;

  }

}
15:53:15.954 -> first:0
15:53:24.118 -> last:8203
15:53:24.118 -> difference (ms):8203
15:53:24.165 -> *************
15:53:24.305 -> first:8349
15:53:34.130 -> last:18206
15:53:34.130 -> difference (ms):9857
15:53:34.130 -> *************
15:53:34.273 -> first:18344
15:53:37.085 -> last:21168
15:53:37.085 -> difference (ms):2824
15:53:37.085 -> *************
15:53:37.226 -> first:21270
15:53:37.367 -> last:21413
15:53:37.367 -> difference (ms):143
15:53:37.367 -> *************
15:53:37.460 -> first:21518
15:53:37.554 -> last:21626
15:53:37.554 -> difference (ms):108
15:53:37.554 -> *************
15:53:37.601 -> first:21678
15:53:49.193 -> last:33257
15:53:49.193 -> difference (ms):11579
15:53:49.193 -> *************
15:53:49.333 -> first:33387
16:00:21.925 -> last:425979
16:00:21.925 -> difference (ms):392592
16:00:21.925 -> *************
16:00:22.065 -> first:426099
16:02:01.849 -> last:525874
16:02:01.849 -> difference (ms):99775
16:02:01.849 -> *************
16:02:01.943 -> first:525997

I'm puzzled why the serial output always shows the first line of the output when I release the button.

    if (read == HIGH) //the button was released
    {
      first = millis();
      Serial.print("first:"); //so this line
      Serial.println(first);  //and this are printed
    }

You release the button, the print happens

Incidentally, your code layout would benefit from Auto formatting in the IDE. Why all the blank lines ?

Thanks, understood.

I did auto-format but copy/pasted an earlier draft by mistake! Here's my actual code:

unsigned long first, last, difference;
int pin = 6, read, last_read; // Changed from pin 9
void setup()
{
  Serial.begin(115200);
  pinMode(pin, INPUT_PULLUP);
}

void loop()
{

  read = digitalRead(pin);
  if (read != last_read)
  {
    if (read == HIGH)
    {
      first = millis();

      Serial.print("first:");

      Serial.println(first);
    }

    else if (read == LOW)
    {
      last = millis();
      Serial.print("last:");
      Serial.println(last);
      difference = last - first;
      Serial.print("difference (ms):");
      Serial.println(difference);
      Serial.println("*************");
    }
 
    last_read = read;

  }

}

You can change what Auto format does, such as removing blank lines in functions, putting spaces around operators, adding a space after if/for and while and moving braces onto their own lines, all of which I find particularly useful after copying code from the forum and in tidying up my own sketches

UKHeliBob:
You can change what Auto format does

Interesting! But how?

Find the folder in which preferences.txt is stored. If you don't know where preferences.txt is stored, open the IDE, File -> Preferences and you'll find a link

Copy the attached file into that folder. If you look at the file with an editor (which you should) you will see a link to http://astyle.sourceforge.net/astyle.html giving details of the formatting commands

The attached file is how I have got my IDE set up, but you can, of course, change it to suit your requirements

The forum does not like the real name of the file but this one should get uploaded

After downloading it rename it to formatter.conf before you use it

formatter.txt (1.01 KB)

Thank you!

Thanks, neat. I'd modified formatter.conf soon after installing the IDE, primarily to get all opening curly brackets on a new line. But yours is nicer, especially the deletion of empty lines. Mind you, I may regret that as I do like lots of space around key lines while I'm learning ...

I may regret that as I do like lots of space around key lines while I'm learning ...

Me too, sometimes, but an empty comment line works for me