Okay, so before explaining my issue, here is a short description about what I'm trying to make:
I'm always leaving my fridge open. With this project I want to make it more 'fun' to actually close the fridge after I've opened it. I am trying to achieve this through gamification. The installation wil be giving points based on how fast i've closed the fridge after opening it.

I'm using:

• an Ultrasonic Distance Sensor to measure if the fridge is open or not.
• a 4 digit 7 segment LED Display to display the points.
• the Arduino Leonardo as my board.

Okay, so I know that when the fridge is closed, the distance is (less than) 20. Of course, when the fridge is open, the distance is more than 20.

What I have achieved already in code:

• If the distance is more than 20 (= if the fridge is open), a timer will measure how many milliseconds it takes for it to go back to a distance less than 20 (= the fridge is closed). This time will be stored in the variable: elapsedMillis.
• If this elapsedMillis is less than 1 second, it wil add a point to the variable: score.
• When the score is 5 (=maximum score), the display will show the word: "NICE".

My problem is this:
Each time my code loops, and the distance is less than 20 (= fridge is closed), it is adding a point. I only want it to add a point when the fridge is opened again, and then closed within a certain time period (not each time it measures a distance of less than 20, which is happening now.). So after it is closed it should not register any more points than the 1 point reward for closing it.

Can someone please help me with what to do? Preferably modify my code so that it works as i'm kind of a newbie.

Here is my code:

``````//Libraries
#include <Arduino.h>
#include <TM1637Display.h>

// Pins
#define CLK 9
#define DIO 8
const int trigPin = A4;
const int echoPin = A3;

//Global variables
long duration;
int distance;

//Timing variables
unsigned long startMillis = 0;
unsigned long currentMillis = 0;
unsigned long elapsedMillis = 0;

//Levels
const unsigned long period3 = 3000;

//Score variables
int score = 0;
int maxScore = 5;

// LED Display text
const uint8_t SEG_EMPTY[] = {};
const uint8_t SEG_NICE[] = {
SEG_C | SEG_E | SEG_G,                           // n
SEG_E | SEG_F,                                   // i
SEG_F | SEG_E | SEG_D | SEG_A,                   // c
SEG_A | SEG_D | SEG_E | SEG_F | SEG_G            // e
};

TM1637Display display(CLK, DIO);

void setup()
{
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600);
}

void loop()
{

// Display nothing on the screen
uint8_t data[] = { 0xff, 0xff, 0xff, 0xff };
display.setBrightness(0x0f);
display.setSegments(SEG_EMPTY);

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
Serial.print("Distance: ");
Serial.println(distance);
delay(500);

//

if (distance < 20) {
currentMillis = millis();
elapsedMillis = currentMillis - startMillis;
Serial.print("Time: ");
Serial.println(elapsedMillis);                         // This will print the time the distance was more than 20.

if (currentMillis - startMillis >= period1) {
startMillis = currentMillis;
}

if (elapsedMillis <= period1) {                           // If the fridge is closed within 1000ms, add a point
score++;
}
}

// If the maximum score is reached, display: "NICE"
if (score >= maxScore) {
//Display "Nice"
uint8_t data[] = { 0xff, 0xff, 0xff, 0xff };
display.setBrightness(0x0f);
display.setSegments(SEG_NICE);
delay(500);
}

}
``````

Of course, when the fridge is open, the distance is more than 20.

Even with you standing there going "Where the hell is the beer I just bought?"?

This time will be stored in the variable: elapsedMillis.

That is the dumbest name you could have possibly chosen.

``````unsigned long currentMillis = 0;
``````

Why does "now" need to be global?

``````  delay(500);
``````

That stupidity is going to play hell with your "game".

``````    if (distance < 20) {
currentMillis = millis();
elapsedMillis = currentMillis - startMillis;
Serial.print("Time: ");
Serial.println(elapsedMillis);                         // This will print the time the distance was more than 20.

if (currentMillis - startMillis >= period1) {
startMillis = currentMillis;
}
``````

If the door is closed, do a bunch of piss-poorly indented stuff.

I suspect that using names that make sense, putting EVERY { on a line BY ITSELF, and properly indenting your code will reveal exactly what the problem is.

You want to note when the door BECOMES opened. You want to note when the door BECOMES closed. Paying attention to whether the door IS open or IS closed is a waste of effort.

Of course, this means you need to keep track of the distance last time through loop, so you can see when it changes (significantly).

PaulS:
You want to note when the door BECOMES opened. You want to note when the door BECOMES closed. Paying attention to whether the door IS open or IS closed is a waste of effort.

Do you know what type of code can detect when the door becomes closed/opened?

maxneeling:
Do you know what type of code can detect when the door becomes closed/opened?

You need to remember what the state was the last time you checked. If the door was closed the last time but is open now then it has become open.

Similarly, if it was open the last time you checked but closed now, then it has become closed.

Do you know what type of code can detect when the door becomes closed/opened?

The state change detection example shows how to detect that a switch has become pressed.

It doesn't take a lot of imagination to see that
if(currentState != previousState)
is similar to
if(currentDistance < 20 && previousDistance >= 20)

But, if that requires more than you have, try this:

``````bool wasOpen = false;

void loop()
{
int distance = getDistance();
bool isOpen = distance < 20;

if(isOpen != wasOpen)
{
// door is now open but wasn't before or is closed now but was open before
}

wasOpen = isOpen;
}
``````

In the body of the if statement, you can test the state of isOpen to determine whether the door was opened (isOpen will be true) or closed (isOpen will be false).

All you have to do is create the getDistance() function (which you should have already done).

maxneeling: