millis() struggle

I understand millis() conceptually, and I have looked at blinkwithoutdelay. I have used millis() before, but it was pulled from code that I found. I am trying to use it in a program, but I can't find examples that use it in the way I need it.

It is for a door on a hopper.
I am using a diode limit switch circuit with a DC gearmotor

electronics.stackexchange.com/questions/293726/limit-switch-on-reversing-motor

I am using a breakout board relay to control a multifunction relay from Mcmaster Carr:

www.mcmaster.com/6964k16

I am using IR beam sensors from Adafruit:

www.adafruit.com/product/2168

When a ping pong ball drops into the hopper, the IR sensor will be triggered for a very short amount of time. When the hopper fills up, the sensors will be triggered indefinitely. After 2 seconds of being triggered, the door opens and empties out the hopper. The door then closes and waits for the hopper to fill up again.

I have code that will open the door whenever the sensor is triggered, but I can't get the "after 2 seconds" part to work.

For simplicity, I am only working with only 1 of the sensors:

const int trigger1 = 11;
const int trigger2 = 12;

const int relay =  4;

int trigger1val = 0;
int trigger2val = 0;

unsigned long currentmillis;
unsigned long startmillis = 0;



void setup()
{
  Serial.begin(9600);
  pinMode(relay, OUTPUT);

  pinMode(trigger1, INPUT);
  pinMode(trigger2, INPUT);

  digitalWrite(trigger1, HIGH);
  digitalWrite(trigger2, HIGH);

  digitalWrite(relay, HIGH);
}

void loop()
{
  trigger1val  = digitalRead(trigger1);
  trigger2val  = digitalRead(trigger2);

  currentmillis = millis();// record the time



  if ( trigger1val == LOW)
    startmillis = currentmillis;
  if (currentmillis - startmillis >= 2000 && trigger1val == LOW) // is the time has passed AND the sensor
    //still being triggered
  {
    digitalWrite(relay, LOW);// pulse the relay
    delay(100);
    digitalWrite(relay, HIGH);
  }

  else
  {
    digitalWrite(relay, HIGH);
  }

  if ( trigger2val == LOW) //this part is only pulsing the relay when the sensor is triggered
    //It does not wait 2 seconds to see if the sensor is still being triggered
  {

    digitalWrite(relay, LOW);
    delay(200);
    digitalWrite(relay, HIGH);
  }

  else
  {
    digitalWrite(relay, HIGH);
  }
  Serial.println(trigger1val);
  Serial.print("\t");
  Serial.println(trigger2val);
}

I have looked at the "using millis() for timing in the forum. Helpful, but I still am doing something wrong. Any insights into what I am doing wrong will be much appreciated. Thank You.

The logic in the following is wrong. To see why, go through it line by line and figure out exactly what happens each time loop() is called.

  currentmillis = millis();// record the time

 if ( trigger1val == LOW)
    startmillis = currentmillis;
  if (currentmillis - startmillis >= 2000 && trigger1val == LOW) // is the time has passed AND the sensor
    //still being triggered

Good tutorial here: https://www.baldengineer.com/blink-without-delay-explained.html

I have been to the bald engineer's sight. A lot. He is great. The only thing I see currently is that I did the math backwards. The startmillis will be the larger number so...

 currentmillis = millis();// record the time

 if ( trigger1val == LOW)
    startmillis = currentmillis;
  if (startmillis - currentmillis >= 2000 && trigger1val == LOW) // is the time has passed AND the sensor
    //still being triggered

Now, one of the reasons I wait until the last possible moment to go on the forum is I am usually met with a patronizing response. I do not mean to devalue your help, I really appreciate your time, but it is not helpful when I am told that the logic is wrong. I know it is wrong, I just don't know "how" it is wrong. So, I hope I have not turned you away from further assistance, but if you could just point to where I am wrong I can try it out and learn that way. I will try my correction, and in the meantime if you would be willing to be more specific with your observations I would be really grateful. Thank you, again.

What you need to do is really understand the blink without delay sketch and how millis is working and how to use it .

Write some simple programs using to flash a couple of leds and use serial print to show what is happening .

Don’t try shortcuts of hacking about other people’s code , learn from others , then do your own.

I will try my correction

Why not try it before you post?

In addition to informing you that the logic was wrong, I did give you some specific advice, and that was to mentally step through each line and see what it actually does.

If you take that effort, it should be completely obvious what the problems are.

For example: the comment below is wrong. As long as trigger1value is LOW, the if statement will never be true because startmillis=currentmillis.

if (startmillis - currentmillis >= 2000 && trigger1val == LOW) // is the time has passed AND the sensor
    //still being triggered

The other possibility is that I have to record the millis() time within the "if" loop:

void loop()
{
trigger1val = digitalRead(trigger1);
trigger2val = digitalRead(trigger2);

currentmillis = millis();// record the time

if ( trigger1val == LOW)
startmillis = millis();
if (startmillis - currentmillis >= 2000 && trigger1val == LOW) // is the time has passed AND the sensor
//still being triggered
{
digitalWrite(relay, LOW);// pulse the relay
delay(100);
digitalWrite(relay, HIGH);
}

I think that might be the incorrect logic that you were referring to...?

Our posts crossed. See reply #5. The new code does not fix the problem.

The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R

The problem is that as long as trigger1val is LOW, you heep setting startmillis to currentmillis.
So there will never be a difference between those.

Store the sensor value in another global (or static) variable, and only set startmillis when it was high last iteration of loop, but is now low.

I know it is wrong, I just don't know "how" it is wrong.

  if ( trigger1val == LOW)
{
  startmillis = millis();
}

  if (startmillis - currentmillis >= 2000 && trigger1val == LOW) // is the time has passed AND the sensor
  //still being triggered
{
  digitalWrite(relay, LOW);// pulse the relay
  delay(100);
  digitalWrite(relay, HIGH);
}

Things happen very quickly on the Arduino.

When trigger1val == LOW you set startmillis = millis();
But you then ask if (startmillis - currentmillis >= 2000 && trigger1val == LOW).
Since, trigger1val == LOW is TRUE, there is ‘no way’ startmillis - currentmillis >= 2000 can be true since you just did, startmillis = millis();

You must start thinking ahead and behind in time when you program.

The only thing I see currently is that I did the math backwards. The startmillis will be the larger number so...

No you were correct originally. Current millis is the larger number. At least until millis() rollover but that is another discussion and the subtraction of unsigned long numbers deals with that.

When the hopper fills up, the sensors will be triggered indefinitely. After 2 seconds of being triggered, the door opens and empties out the hopper.

if ( trigger1val == LOW)
    startmillis = currentmillis;

With the sensor triggered indefinitely, startmillis will constantly be the value of current millis and the two second timeout won't happen.

When a ping pong ball drops into the hopper, the IR sensor will be triggered for a very short amount of time.

You want a stable triggered reading for a period of time longer than a single ball passing before marking a start time. Your problem is more like switch reading with debounce. But, the debounce routine needs to look for a stable reading, and not be based on a lock out time.

There are several ways you can proceed with this, but it's possible you could use the Bounce2 library to read the triggers. Thae library uses a stable period debounce algorithm.

If you want to write your own code, blocking methods are fairly straight forward, and non blocking methods are more complex.

Thank you DrAzzy. That is helpful and allows me to get a fresh look at something that "because I have been looking at it so long I no longer see it" situation.

I am really frustrated because clearly millis() is a simple function, I just can't wrap my head around how it is set up mathematically. It what order do you layout the lines of code. I am not a mathematician or a programmer, and as such the logic sometimes escapes me. I know at some point a synapse will make that jump and BOOM, I will understand. But until then...I struggle and feel stupid. So....Thank you DrAzzy.

That is the logic that jremington was asking me to look at. As I looked at it and read jremingtons emphatic
"startmillis=currentmillis" I realized that currentmillis had to be a global variable, and then I read the supporting response.

I have looked at all sorts of millis() posts and sites. I have looked at BwoD many times and watched many youtube videos and lynda.com videos and read the "using millis()" at the beginig of this section of the forum, I have bought and read books by Simon Monk, among others, and I subscribe to Programming Electronics Academy [, and I still get tripped up.

I am determined to have my EUREKA moment. Coming here as an inexperienced person invariably involves getting berated for not working hard enough, or expecting too much. I realize I come off as defensive and possible too sensitive, but posting here is not easy because it is the last resort. So, thank you DrAzzy. I have to take my daughter to the park now....

](https://programmingelectronics.com/)

Something like the following will allow you to compute how long a switch has been held closed, and execute an action upon timeout.

unsigned long timeout=2000UL; //two second timeout
...
if (digitalRead(switchpin) == HIGH) last_high_millis = millis();
if ((digitalRead(switchpin) == LOW) && (millis() - last_high_millis > timeout)) do_something();

This does not take into account possible switch bounce, which can be milliseconds long.