currently trying to make a motion sensor light that i can turn on and off with sensor detection but also have auto turn off after lets say 15 minutes if left on.
I've got it so i can turn it off and on now using motion but not sure how to have it auto turn off after a set time since delay blocks me from turning it off with motion if i try using that.
I'm thinking I'll have to use the millis function? but not sure where to start and feel like I've hit a wall so any guidance would be appreciated.
here's the code i have so far to have the sensor turn it off and on.
int pir = 2;
int val;
int state = 0;
void setup() {
pinMode(led, OUTPUT);
pinMode(pir, INPUT);
}
void loop() {
val = digitalRead(pir);
if (val == HIGH)
{
if (state == 0)
{
state = 1;
digitalWrite(led, HIGH);
delay (4000);
}
else {
state = 0;
digitalWrite(led, LOW);
delay (4000);
}
}
}```
have a global variable unsigned long sleep_start;. Set sleep_start = 0 everytime you turn the LED off andsleep_start = millis(); every time the LED goes on.
Then at the start of loop():
if (sleep_start > 0 && millis() > sleep_start + 15 * 60 * 1000) {
// it is now over 15 minutes since the LED went on
// do whatever you want - turn LED off and set state = 0 ?
}
I not you have your actions and state tied together - i.e. you set the state and then turn on/off the LED at the same time. Much better to set the state separately and then set the LED based on the state.
void loop()
{
unsigned long now = millis();
val = digitalRead(pir);
bool state_changed = false;
if (val == HIGH)
{
if (state == 0)
state = 1;
else
state = 0;
state_changed = true;
}
// state was not changed by the sensor so look for timeout
if (!state_changed)
{
if (state == 1 && now > sleep_start + 15 * 60 * 1000)
{
state = 0;
state_changed = true;
}
}
if (state_changed)
{
switch(state) {
case 0: digitalWrite(led, LOW);
break;
case 1: digitalWrite(led, HIGH);
sleep_start = now;
break;
}
}
delay(4000);
}
Related
I have an ATTiny85 which I program using a sparkfun programmer (https://www.sparkfun.com/products/11801) and the ATTiny Board Manager I am using is: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json
Below is my code, I am having trouble getting the interrupt to work when I ground Pin 2.
I have tested the LED does work outside of the interrupt (inside the loop). Any suggestions are welcome.
#include "Arduino.h"
#define interruptPin 2
const int led = 3;
bool lastState = 0;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(interruptPin, pulseIsr, CHANGE);
pinMode(led, OUTPUT);
}
void loop() {
}
void pulseIsr() {
if (!lastState) {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
lastState = 1;
}
else {
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
lastState = 0;
}
}
I was way off.
Here is how to set up an interrupt on the ATTiny85 using the Arduino IDE (this example uses digital pin 4 (pin 3 on the chip):
#include "Arduino.h"
const byte interruptPin = 4;
const byte led = 3;
bool lastState = false;
ISR (PCINT0_vect) // this is the Interrupt Service Routine
{
if (!lastState) {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
lastState = true;
}
else {
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
lastState = false;
}
}
void setup() {
pinMode(interruptPin, INPUT_PULLUP); // set to input with an internal pullup resistor (HIGH when switch is open)
pinMode(led, OUTPUT);
// interrupts
PCMSK |= bit (PCINT4); // want pin D4 / pin 3
GIFR |= bit (PCIF); // clear any outstanding interrupts
GIMSK |= bit (PCIE); // enable pin change interrupts
}
void loop() {
}
I see one possible error with your Boolean data type. Boolean data types are either true or false. I see that your using it for variable lastState. The initialization to equal 0 is something that I don't think the compiler allows. Maybe you should try setting the bool variable to the following...
bool lastState = true;
if (!lastState) {
// what you want your code to perform if lastState is FALSE
}
else {
//what else you want your code to perform if lastState is TRUE
}
OR
bool lastState = true;
if (lastState) {
// what you want your code to perform if lastState is TRUE
}
else {
//what else you want your code to perform if lastState is FALSE
}
Here is a helpful pdf on Boolean data types, available for download through my Nextcloud instance.
https://nextcloud.point2this.com/index.php/s/so3C7CzzoX3nkzQ
I know this doesn't fully fix your problem, but hopefully this will help some.
What is my Issue with the button, it dont work correctly and I am wondering why. I dont get it. The Button is connected over the 5V Then a 10k resistor and connected with a wire to the ground. I think the isr is correctly implemented. And the function is also correct. But I do not really get whats the issue with the Button is. I tried a capacitor but that didnt also work well... I connected it directly before the the button.
#include <LiquidCrystal.h>
LiquidCrystal lcd(5, 6, 9, 10, 11, 12);
unsigned long volatile startTime = 0;
unsigned long volatile endTime = 0;
unsigned long volatile sec;
volatile boolean buttonState;
const int button = 2;
long ms;
long timeT;
long z;
void setup() {
Serial.begin(9600);
// put your setup code here, to run once:
pinMode(button, INPUT_PULLUP);
lcd.setCursor(0, 0);
lcd.print("Stopwatch");
attachInterrupt(digitalPinToInterrupt(button), isr, FALLING);
}
void loop() {
if (buttonState == LOW) {
startTime = millis();
}
while (buttonState == HIGH) {
z = (millis() - startTime);
sec = (z / 1000);
ms = z % 1000;
lcd.setCursor(0, 1);
lcd.print(sec);
lcd.print(".");
lcd.print(ms);
lcd.setCursor(9, 1);
lcd.print("Secs");
}
}
//Interrupt Service Routines
void isr() {
buttonState = !buttonState;
}
Buttons are quirky things. It can happen that they send multiple signals (rather, that the contact isn't immediately stable). A condenser might help, but that too can output a wavy signal and trigger multiple "events" and, anyway, it introduces a delay.
So, delay for delay, you could do something like this which should be more controllable:
if (buttonState !== previousState) {
startTime = millis();
previousState = buttonState;
triggered = 0;
} else {
if (0 == triggered) {
if ((millis() - startTime) > threshold) {
triggered = 1;
// Okay, buttonState is now reliably LOW or HIGH
...
}
} else {
// Continuous event (pressed or not-pressed)
}
}
In practice, this should only react when the button has been uninterruptedly pressed or released for "threshold" millis. Assuming BTN is the actual signal from the button without any other attending hardware,
1 2 3 4 5 6
BTN: LLLLLLLLLLLLLLHLHHLHHHLHHHHHHHHHHHHHHHHHHHHHHHHHHHLHHHLLHHLLLLLLLLL
FLT: ___________________________-----------------------------------_____
Time --------------------------------------------------------------->
1 button is physically pressed
2 button is now truly pressed
3 stable button press is detected
4 button begins to be released
5 button is now fully released
6 stable button release is detected
I need to make this object following robot which uses 2 servo motors to move and a ultrasonic sensor to detect where objects are and where the Arduino should tell the servos to move. But, the problem seems to be that whenever the servo motors are trying to move forwards or backwards they just keep spinning. I've tried to check for loose wires but no wires seem loose, I've tried changing how I write the code but nothing has seemed to work yet...
Also here's some relevant code (not all):
void forward() {
for (pos = 0; pos <= 180; pos++)
{
for (pos2 = 0; pos2 <= 180; pos2++)
{
myServo1.write(pos);
myServo2.write(pos2);
delay(15);
}
}
}
int Distance_thing() {
digitalWrite(Trig, LOW);
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(20);
digitalWrite(Trig, LOW);
float Fdistance = pulseIn(Echo, HIGH);
Fdistance= Fdistance / 58;
return (int)Fdistance;
}
void loop() {
rightDistance = Distance_thing();
leftDistance = Distance_thing();
if ((rightDistance > 70) && (leftDistance > 70)) {
stop();
delay(500);
}
else if ((rightDistance >= 20) && (leftDistance >= 20)) {
forward();
delay(500);
}
else if ((rightDistance <= 10) && (leftDistance <= 10)) {
back();
delay(500);
}
else if (rightDistance - 3 > leftDistance) {
left();
delay(500);
}
else if (rightDistance + 3 < leftDistance) {
right();
delay(500);
}
else {
stop();
delay(500);
}
}
As paddy already pointed out your movements take very long.
The nested for loops will call delay(15) 181*181 times. That's 32716 times 15 milliseconds. A total of 8.2 minutes.
Another problem with your code is that you expect the servo to return from 180° to 0° within 15ms which is not going to happen.
Also don't need to call myServo1.write(pos) in the inner loop as pos is only updated in the outer loop. That's a total of 32580 uneccessary function calls.
You should learn how to write non-blocking code. There are plenty of resources available.
You might also develop a habit of checking your maths. Don't just delay. Think about what it actually means to delay 181*181*15ms!
This is my very first code in arduino. Im trying to build a simple watering automation for my garden. The code contain 3 main functions which is:
To topup fertilizer tank with water.
To add fertilizer into the water tank while water being topup with assumption fertilizer will be mix during this process.
To automated watering process through the day.
For the 1st and 3rd function, Im already got it done (theoretically + small scale system) i think. haha!
Now, for the fertilizer function number 2 (fertilizer_PUMP()), im using 2 peristaltic pump to add AB fertilizer solutions into the tank. Im trying to get the pump to run for the x amount of time but the the function only run once, after that the loop need to reset if both float switch become dry and wait for the bottom switch wet again. Could anyone please help and guide me which part im missing? Im open for any suggestion to improved my code too.. Thank you.
UPDATE:
Im so sorry for the confusing. Actually for this function, below are my requirements.
If top float dry and bottom float wet > turn on both peristaltic pump for 10s(or more will change later) and stop.
Then, if top float dry and bottom float dry > reset.
Wait for next top float dry and bottom float wet.
Im really sorry again for the confusing. Kinda messed up with the logic previously.
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 RTC;
#define relayON HIGH
#define relayOFF LOW
#define floatWET HIGH
#define floatDRY LOW
const byte bottom_float = 13; //bottom position float switch
const byte top_float = 12; //top position float switch
const byte relay_topup_PUMP = 2; //Relay 1 for PUMP/Solenoid to topup water into the fertilizer tank
const byte relay_watering_PUMP = 3; //Relay 2 for scheduled watering PUMP
const byte relay_fertilizer_PUMPA = 4; //Relay 3 for Peristaltic PUMP "A" solution fertilizer
const byte relay_fertilizer_PUMPB = 5; //Relay 4 for Peristaltic PUMP "B" solution fertilizer
unsigned long previousMillis = 0; // stores last time relay was active(on)
unsigned long fertilizer_pumpON_interval = 10000; //(10s for testing)Time to turn ON fertilizer peristaltic pump to get required EC reading
void topup_PUMP();
void watering_PUMP();
void fertilizer_PUMP();
void setup ()
{
Serial.begin (9600);
Wire.begin();
// RTC.begin();
if (! RTC.begin())
{
Serial.println("Couldn't find RTC");
while (1);
}
if (! RTC.isrunning())
{
Serial.println("RTC is NOT running!");
}
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
pinMode (bottom_float, INPUT_PULLUP);
pinMode (top_float, INPUT_PULLUP);
pinMode (relay_topup_PUMP, OUTPUT);
pinMode (relay_watering_PUMP, OUTPUT);
pinMode (relay_fertilizer_PUMPA, OUTPUT);
pinMode (relay_fertilizer_PUMPB, OUTPUT);
//digitalWrite (relay_topup_PUMP, relayOFF);
//digitalWrite (relay_watering_PUMP, relayOFF);
digitalWrite (relay_fertilizer_PUMPA, relayOFF);
digitalWrite (relay_fertilizer_PUMPB, relayOFF);
DateTime now = RTC.now();
} // end of setup
void loop ()
{
// topup_PUMP();
// watering_PUMP();
fertilizer_PUMP();
}
//void topup_PUMP()
//{
// if (digitalRead (top_float) == floatDRY && digitalRead (bottom_float) == floatDRY)
// {
// Serial.println("TOPUP PUMP ON");
// digitalWrite(relay_topup_PUMP, relayON);
// }
//
// if (digitalRead (top_float) == floatWET && digitalRead (bottom_float) == floatWET)
// {
// Serial.println("TOPUP PUMP OFF");
// digitalWrite(relay_topup_PUMP, relayOFF);
// }
// delay (1000);
//}
//
//void watering_PUMP()
//{
//// DateTime now = RTC.now();
// Serial.print(now.hour(), DEC);
// Serial.print(':');
// Serial.print(now.minute(), DEC);
// Serial.print(':');
// Serial.print(now.second(), DEC);
// Serial.print(' ');
// Serial.print(now.day(), DEC);
// Serial.print('/');
// Serial.print(now.month(), DEC);
// Serial.print('/');
// Serial.print(now.year(), DEC);
// Serial.println();
// delay(1000);
//
// boolean watering_PUMPstate = false;
// if (now.hour() == 15 && now.minute() >= 38 && now.minute() < 39) watering_PUMPstate = true; //6:00 am - 5 mins
// if (now.hour() == 15 && now.minute() >= 40 && now.minute() < 41) watering_PUMPstate = true; //8:30 am - 5 mins
//// if (now.hour() == 11 && now.minute() >= 0 && now.minute() < 5) watering_PUMPstate = true; //11:00 am - 5 mins
//// if (now.hour() == 13 && now.minute() >= 30 && now.minute() < 35) watering_PUMPstate = true; //1:30 pm - 5 mins
//// if (now.hour() == 16 && now.minute() >= 0 && now.minute() < 10) watering_PUMPstate = true; //4:00 pm - 10 mins
//
// if (watering_PUMPstate == true)
// {
// digitalWrite(relay_watering_PUMP, relayON);
// Serial.print("\t");
// Serial.println(F("Watering Plant"));
// Serial.print("\t");
// Serial.println();
// }
// else
// {
// digitalWrite(relay_watering_PUMP, relayOFF);
// }
//}
void fertilizer_PUMP()
{
unsigned long currentTime = millis();
boolean fertilizer_pumpON = false;
if ((digitalRead (top_float) == floatDRY) && (digitalRead (bottom_float) == floatWET) && (currentTime - previousMillis <= fertilizer_pumpON_interval)) //Turn on for 10s
{
Serial.print("\t");
Serial.println(currentTime);
delay (1000);
fertilizer_pumpON = true;
}
if (fertilizer_pumpON == true)
{
Serial.print("\t");
Serial.println(F("Adding Fertilizer A and B"));
delay (1000);
digitalWrite(relay_fertilizer_PUMPA, relayON);
digitalWrite(relay_fertilizer_PUMPB, relayON);
}
else
{
digitalWrite(relay_fertilizer_PUMPA, relayOFF);
digitalWrite(relay_fertilizer_PUMPB, relayOFF);
}
}
Define your currentTime and fertilizer_pumpON as global
unsigned long currentTime = 0;
unsigned long previousMillis = 0; // stores last time relay was active(on)
unsigned long fertilizer_pumpON_interval = 10000; //(10s for testing)Time to turn ON fertilizer peristaltic pump to get required EC reading
then in your
function void fertilizer_PUMP()
if ((digitalRead (top_float) == floatDRY)
&& (digitalRead (bottom_float) == floatWET)
&& (currentTime - previousMillis <= fertilizer_pumpON_interval))
should include the state of the pump - I guess you only want to enter the if on pump off state
if ((digitalRead (top_float) == floatDRY) // CAN BOTH STATES BE AT THE SAME TIME??
&& (digitalRead (bottom_float) == floatWET)
&& (currentTime - previousMillis <= fertilizer_pumpON_interval))
I reduce to
if((millis() - previousMillis > fertilizer_pumpON_interval)
&& fertilizer_pumpON == true) {//time is up and state is on stop pump
fertilizer_pumpON = false; // switch off
}
else if (PUMP_ON_condition == true && fertilizer_pumpON == false){ //check if we have to switch on
fertilizer_pumpON = true; // switch on
previousMillis = millis(); // set timer to switch on time
setRelaytoON = true; // Use YOUR COMMAND/PIN whatever you need
}
else {
// DO NOTHING OR something while waiting or running use more ELSE IF if needed
}
To sum it up
Check for state AND time when running to stop
Check for INIT command/conditions AND state set state & timer
Check for emergency stop if needed
do something/nothing if none of above applies
Break long clause up into single parts and check if states can have a different value at a time (logical error)
if (A == true && A == false) // YOU CAN NEVER ENTER THIS CLAUSE
EDIT Implemented the logic as you described (read the comments in the code!) Add the line
bool fertilizer_pumpON = false;
before Setup() to the global vars and replace void fertilizer_PUMP() with below code. A tip: Never use delay() - this blocks processing and renders time driven logics useless.
void fertilizer_PUMP() {
// If top float dry and bottom float wet > turn on both peristaltic pump for 10s(or more will change later) and stop CODE STARTS HERE
if ((digitalRead (top_float) == floatDRY) && (digitalRead (bottom_float) == floatWET) && fertilizer_pumpON == false) { //Turn on
Serial.print("\t");
Serial.println(millis());
// delay (1000); // NEVER use delays or the whole logic wont work - delays BLOCK processing!
fertilizer_pumpON = true;
previousMillis = millis();
Serial.print("\t");
Serial.println(F("Adding Fertilizer A and B"));
// delay (1000);
digitalWrite(relay_fertilizer_PUMPA, relayON);
digitalWrite(relay_fertilizer_PUMPB, relayON);
}
else if (fertilizer_pumpON == true && (millis() - previousMillis > fertilizer_pumpON_interval)) { //Run for 10s then stop
digitalWrite(relay_fertilizer_PUMPA, relayOFF);
digitalWrite(relay_fertilizer_PUMPB, relayOFF);
fertilizer_pumpON = false;
Serial.println(F("Time elapsed"));
}
// If top float dry and bottom float wet > turn on both peristaltic pump for 10s(or more will change later) and stop CODE STARTS HERE
// Then, if top float dry and bottom float dry > reset. CODE ENDS HERE
else if ((digitalRead (top_float) == floatDRY) && (digitalRead (bottom_float) == floatDRY && fertilizer_pumpON == true) ) {
digitalWrite(relay_fertilizer_PUMPA, relayOFF);
digitalWrite(relay_fertilizer_PUMPB, relayOFF);
fertilizer_pumpON = false;
Serial.println(F("Reset condition encountered"));
}
// Then, if top float dry and bottom float dry > reset. CODE ENDS HERE
else { // Wait for next top float dry and bottom float wet.
Serial.println(F("Waiting ......")); // use only for testing comment out afterwards
}
}
The code compiles so logic testing is up to you.
You might want to change the way you are calling the function from loop:
Define global variable unsigned long previousMillis=-1; Then in void loop():
void loop()
{
if((digitalRead (top_float) == floatDRY) && (digitalRead (bottom_float) == floatWET))
{ //If your above condition is correct(means you are read to pour fertilizer)
if(previousMillis==-1)
previousMillis=millis();//Set time elapsed till now in global variable
if(previousMillis!=-1)
{
fertilizer_PUMP();//call function with a fixed previousMillis till millis()-previousMillis becomes 10s
}
}
}
Then in fertilizer_PUMP():
void fertilizer_PUMP()
{
boolean fertilizer_pumpON = false;
if (millis() - previousMillis <= fertilizer_pumpON_interval)) //Turn on for 10s
{
Serial.print("\t");
Serial.println(currentTime);
delay (1000);//This delay is not required because your effective interval would be 5 seconds then(10/2)
//As you have a delay(1000) in the next if block too.
fertilizer_pumpON = true;
}
...
And in the same function:
else
{
digitalWrite(relay_fertilizer_PUMPA, relayOFF);
digitalWrite(relay_fertilizer_PUMPB, relayOFF);
previousMillis=-1;//Wait for top float dry and bottom float wet, then set previousMillis
}
I am trying to detect when continuous motion has been triggered from a PIR sensor for more than 8 seconds. Here is what I have. When sensor is LOW 'no motion...' is displayed, then short motion fires the first '< 8 sec' IF statement. When sensor returns to LOW - no motion is displayed as it should but then when motion is detected a second time, the code seems to freeze and nothing happens.
unsigned long startMillis;
boolean timingFlag = false;
const int buttonPin = 2;
int buttonState = 0;
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(19200);
delay(500);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH && millis() - startMillis <= 8000UL)
{
Serial.println("Motion Detected but less than 8");
delay(1000);
//the PIR timed out with in the three seconds so cancel timing
timingFlag = false; //disable timing
}
if (buttonState == LOW)
{
Serial.println("No Motion...");
delay(1000);
timingFlag = true; //enable timing
}
//when nine seconds have gone by with consistant detection do something
if (timingFlag == false && millis() - startMillis >= 9000UL)
{
//There has now been nine seconds of constant PIR detection
Serial.println("Motion Detected and greater than 9 sec");
delay(1000);
//Do Something
}
}
There is one very obvious problem with your current code, as Scheff already mentioned in the comments: You never actually set your startMillis to anything, so they are probably (but not necessarily) always 0.
This means, that the statement if (buttonState == HIGH && millis() - startMillis <= 8000UL) will always be false after 8000 ms (until millis() flows over, after around 50 days* ), so timingFlag will never be reset to false after that. This ultimately leads to your "freezing" situation.
I tried to find a good place to set the startMillis in your code, but I honestly find it a little confusing, so I allowed myself to rewrite your logic, hope you don't mind. (Please note that I also changed the variable names from button to detector, since it seemed more fitting to me):
(This version triggers at the transitions from HIGH to LOW)
// define the threshold, after which an action shall be triggered
const int detectionThreshold = 8000;
const int detectorPin = 2;
unsigned long startTime = 0;
int lastDetectorState = LOW;
void setup() {
pinMode(detectorPin, INPUT);
Serial.begin(19200);
delay(500);
}
void triggerDetectionAction(){
// do whatever needs to be done after 8 seconds of motion in here
}
void loop() {
int currentDetectorState = digitalRead(detectorPin);
// if detector is low, no motion is detected
if( currentDetectorState == LOW ){
// when the detector is LOW, we want to check if the last state was HIGH
// because then we just arrived at the transition from HIGH to LOW =>
// "something was detected" to "there is no longer something detected"
if( lastDetectorState == HIGH ){
// then, we can get the total duration, the detection lasted
unsigned long detectionDuration = millis() - startTime;
// and print it for easier debugging
Serial.print("Detection ended after ");
Serial.print(detectionDuration);
Serial.println(" milliseconds");
// finally, we check if the durations was more than
// or equal to our threshold
if( detectionDuration >= detectionThreshold ){
// and trigger stuff if necessary
triggerDetectionAction();
}
}
// if last detector state was LOW too,
// we don't want to do anything
}else{
// here we wan't to check for the transition of LOW to HIGH,
// so we check our last detector state
if( lastDetectorState == LOW ){
// if we caught the transition,
// set the start time to the current millis
startTime = millis();
// we could also set an indicator LED
// or Serial.print something here
Serial.println("Detection started");
}
// otherwise, we don't wan't to do anything
}
// finally, we save our current state into the last state,
// so we have it available in the next loop
lastDetectorState = currentDetectorState;
// do your other loop stuff here
}
Please note that I couldn't test the code at the time writing, so there may be (syntax) errors
*More about millis and overflow here: https://www.arduino.cc/reference/en/language/functions/time/millis/
Update: This version will trigger immediately when the threshold is reached. It also includes an example how to trigger an action once and every loop after the threshold was reached.
// define the threshold, after which an action shall be triggered
const int detectionThreshold = 8000;
const int detectorPin = 2;
unsigned long startTime = 0;
int lastDetectorState = LOW;
bool actionTriggered = false;
void setup() {
pinMode(detectorPin, INPUT);
Serial.begin(19200);
delay(500);
}
void triggerOnce(){
// this will be called once, when the threshold is reached
}
void triggerEveryLoop(){
// this will be called every loop, after the threshold was reached
// for as long as the detector stays high
}
void loop() {
int currentDetectorState = digitalRead(detectorPin);
if( currentDetectorState == LOW ){
if( lastDetectorState == HIGH ){
// since we want to trigger immediately when the threshold is reached,
// we actually don't need this transition any longer.
// We can still keep it for debugging reasons thought.
// If you don't need this, you can simply remove the entire block
unsigned long detectionDuration = millis() - startTime;
Serial.print("Detection ended after ");
Serial.print(detectionDuration);
Serial.println(" milliseconds");
}
}else{
// Check for LOW => HIGH transition change
if( lastDetectorState == LOW ){
// if we caught the transition,
// set the start time to the current millis
startTime = millis();
// and reset the flag
actionTriggered = false;
// we could also set an indicator LED
// or Serial.print something here
Serial.println("Detection started");
}else{
// otherwise we want to check the duration
unsigned long detectionDuration = millis() - startTime;
// and trigger immediatley when the threshold is reached
if( detectionDuration >= detectionThreshold ){
// as long as it wasn't already triggered before
if( !actionTriggered ){
Serial.println("Threshold reached, triggering");
// now we also need to set a flag, so we know we already triggerd this action once
actionTriggered = true;
triggerOnce();
}
// we can also do something every loop
// this can be handy for e.g. blinking a light or playing a sound or something
triggerEveryLoop();
}
}
}
// finally, we save our current state into the last state,
// so we have it available in the next loop
lastDetectorState = currentDetectorState;
// do your other loop stuff here
}