How to stop a timer delay using millis() from executing with NRF24L01 Network (Arduino)

Thread Starter

firashelou

Joined Feb 28, 2021
4
Hello,
what i have in my circuit is 2 push buttons, the first for starting a timer of 3 seconds which then when the timer is done it sends a 1 to the NRF24L01 which turn a relay on for a specific time which is 3 seconds then turn it off by sending 0 to NRF24L01. The second button is reset button which if the timer did not finish, it prevents the 1 from being sent through the NRF24L01. My connection are good I tested them separately and they are working well and my NRF24L01 code is good it sends data that i want, my only problem is how to stop the timer from being executed if the 1 has not been sent means if the relay is not on but if the relay is on and i clicked reset, I don't want this reset to stop the relay which is working to finish it's time which is 3 seconds on.

here is my code so far:


C:
#include <SPI.h>
#include <RF24.h>
#include <RF24Network.h>

RF24 radio(9, 10);               // nRF24L01 (CE,CSN)
RF24Network network(radio);      // Include the radio in the network
const uint16_t this_node = 00;   // Address of this node in Octal format ( 04,031, etc)
const uint16_t node01 = 01;


int relayButtonPin = A2;
int resetButton = 8;


boolean lastRelay5_pb = LOW;
boolean currentRelay5_pb = LOW;
boolean relay5PushBOn = false;
int relay5NumClicks = 0;
boolean relay5Working = false;
int relay5Data;


boolean okToPrint = true;

boolean lastReset = LOW;
boolean currentReset = LOW;
boolean resetPushBOn = false;
int resetNumClicks = 0;
boolean resetWorking = false;

unsigned long interval = 3000;
unsigned long startClickTime;
unsigned long startResetTime;



void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(relayButtonPin, INPUT);


  SPI.begin();
  radio.begin();
  network.begin(90, this_node);  //(channel, node address)
  radio.setDataRate(RF24_2MBPS);
}

void loop()
{
  // This is for the Relay 5 Push button connected to A2 ---------------------------------------
  currentRelay5_pb = debounce(lastRelay5_pb, relayButtonPin);
  if (lastRelay5_pb == LOW && currentRelay5_pb == HIGH)
  {
    relay5PushBOn = !relay5PushBOn;
    relay5NumClicks++;
   
    okToPrint = true;
  }
  lastRelay5_pb = currentRelay5_pb;

  if(relay5Working == false && relay5NumClicks >= 2){
    relay5Working = true;
    startClickTime = millis();
    relay5Data = 1;
  }

  if(relay5Working == true){
    relay5NumClicks = 0;
   
  }
 
  // This is for reset button
  currentReset = debounce(lastReset, resetButton);
  if (lastReset == LOW && currentReset == HIGH)
  {
    resetPushBOn = !resetPushBOn;
    resetNumClicks++;
   
  }
  lastReset = currentReset;

  if(resetWorking == false && resetNumClicks >= 1){
    resetWorking = true;
    okToPrint = false;
    startResetTime = millis();
    relay5Data = 0;
  }

  if(resetWorking == true){
    resetNumClicks = 0;
  }
  Serial.print("Print: ");
  Serial.println(relay5Data);
  if(millis() - startResetTime > interval){
    okToPrint = true;
  }
 
  if (millis() - startClickTime > interval){
    if (okToPrint)
    {
      Serial.print("ok send: ");
      Serial.println(relay5Data);
     
    }
  }

  bool ok1 = network.write(header1, &relay5Data, sizeof(relay5Data)); // Send the data
}

// Debouncing function
boolean debounce(boolean last, int switchPin)
{
  boolean current = digitalRead(switchPin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(switchPin);
  }
  return current;
}
Moderators note : used code tags
 
Last edited by a moderator:

sagor

Joined Mar 10, 2019
406
It is not clear what timer, etc. your sequence is doing.
However, to interrupt a main loop sequence, you could attach a hardware interrupt pin to an interrupt routine to set a simple flag. When you push a button for that interrupt pin, that interrupts the main code and sets a flag. When the main code continues, and the millis() routine finishes, it checks for that flag, if it is set you then does NOT send the "1", then program clears the flag or does something else for the next run around...
You check the "reset" flag only with the first 3 second timer, and ignore (clear it anyway) on the second timer (to turn off the relay).

Hardware Interrupt pins vary by Arduino. On the Nano or Uno for example, they are D2 and D3. They are different for the Mega, Micro, etc.
 

John P

Joined Oct 14, 2008
1,876
Suppose that instead of a single 3-second delay, you use 300 10 millisecond delays, with a counter to count through them. After every 1/100 second, you check the reset button, and if it's been pressed, you cancel the count and return to checking for the "start" button.

But really, this program ought to be constructed using a timer interrupt which does everything, and no use of delays at all.
Say the interrupt happens at 100 per second:

State 0: Clear relay, check for presses of start button, move to state 1 when seen
State 1: Count to 300, if reset button pressed return to state 1, if 300 reached, move to state 2
State 2: Set relay, count to 300, when 300 reached, move to state 0

Edited to say oops, how could I have written state 1 should return to state 1 if the button is pressed? Return to state 0, of course.
 
Last edited:

andrewmm

Joined Feb 25, 2011
1,150
If you are using buttons,
then I'd suggest you use the buttons library for the arduino
it takes care of such things as debouncing the switches,

Also use interrupts,
and then a state machine in the main loop

Note also that mills wraps after a numbe rof days ( can't rember how many )
so if your turned on for that lenght, two consecutive reads of mills might go down not up.
 

ApacheKid

Joined Jan 12, 2015
379
Hello,
what i have in my circuit is 2 push buttons, the first for starting a timer of 3 seconds which then when the timer is done it sends a 1 to the NRF24L01 which turn a relay on for a specific time which is 3 seconds then turn it off by sending 0 to NRF24L01. The second button is reset button which if the timer did not finish, it prevents the 1 from being sent through the NRF24L01. My connection are good I tested them separately and they are working well and my NRF24L01 code is good it sends data that i want, my only problem is how to stop the timer from being executed if the 1 has not been sent means if the relay is not on but if the relay is on and i clicked reset, I don't want this reset to stop the relay which is working to finish it's time which is 3 seconds on.

here is my code so far:


C:
#include <SPI.h>
#include <RF24.h>
#include <RF24Network.h>

RF24 radio(9, 10);               // nRF24L01 (CE,CSN)
RF24Network network(radio);      // Include the radio in the network
const uint16_t this_node = 00;   // Address of this node in Octal format ( 04,031, etc)
const uint16_t node01 = 01;


int relayButtonPin = A2;
int resetButton = 8;


boolean lastRelay5_pb = LOW;
boolean currentRelay5_pb = LOW;
boolean relay5PushBOn = false;
int relay5NumClicks = 0;
boolean relay5Working = false;
int relay5Data;


boolean okToPrint = true;

boolean lastReset = LOW;
boolean currentReset = LOW;
boolean resetPushBOn = false;
int resetNumClicks = 0;
boolean resetWorking = false;

unsigned long interval = 3000;
unsigned long startClickTime;
unsigned long startResetTime;



void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(relayButtonPin, INPUT);


  SPI.begin();
  radio.begin();
  network.begin(90, this_node);  //(channel, node address)
  radio.setDataRate(RF24_2MBPS);
}

void loop()
{
  // This is for the Relay 5 Push button connected to A2 ---------------------------------------
  currentRelay5_pb = debounce(lastRelay5_pb, relayButtonPin);
  if (lastRelay5_pb == LOW && currentRelay5_pb == HIGH)
  {
    relay5PushBOn = !relay5PushBOn;
    relay5NumClicks++;

    okToPrint = true;
  }
  lastRelay5_pb = currentRelay5_pb;

  if(relay5Working == false && relay5NumClicks >= 2){
    relay5Working = true;
    startClickTime = millis();
    relay5Data = 1;
  }

  if(relay5Working == true){
    relay5NumClicks = 0;

  }

  // This is for reset button
  currentReset = debounce(lastReset, resetButton);
  if (lastReset == LOW && currentReset == HIGH)
  {
    resetPushBOn = !resetPushBOn;
    resetNumClicks++;

  }
  lastReset = currentReset;

  if(resetWorking == false && resetNumClicks >= 1){
    resetWorking = true;
    okToPrint = false;
    startResetTime = millis();
    relay5Data = 0;
  }

  if(resetWorking == true){
    resetNumClicks = 0;
  }
  Serial.print("Print: ");
  Serial.println(relay5Data);
  if(millis() - startResetTime > interval){
    okToPrint = true;
  }

  if (millis() - startClickTime > interval){
    if (okToPrint)
    {
      Serial.print("ok send: ");
      Serial.println(relay5Data);

    }
  }

  bool ok1 = network.write(header1, &relay5Data, sizeof(relay5Data)); // Send the data
}

// Debouncing function
boolean debounce(boolean last, int switchPin)
{
  boolean current = digitalRead(switchPin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(switchPin);
  }
  return current;
}
Moderators note : used code tags
On the surface this seems to requires a simple state variable recording the state of the system. There's likely no need to disable the timer at all, just have the timer interrupt handler examine the system state and decide what to do, it can decide to do nothing at all if the system is in some state, that's how it reads but I'm not 100% sure I understood.

So make a small table of the set of states the system can be in, and what events (button press, timer etc) have what effects in each state.

Think of the timer as just another (imaginary) button that gets pressed by some imaginary robot, every three seconds, over and over and over. Don't think of explicitly disabling the timer but disabling what the timer expiry code does.

In principle your code could be a switch statement that has a case for each "event" (button press, time expiry etc).

Each case hen does some action, possibly adjusts the state and then returns.

Every time any event occurs that switch handler should run, what the handler does will always depend only on a) The current state and b) The type of event that occured.

Once you get that tabulated and error free, the code will almost write itself.

(PS your code is structured in a way that will get complicated to debug and complicated to extend. A state machine design is far better as each case is examined in isolation, as soon as you see code with stuff like "if X happened but I did Y last time but I've never yet done Z but have done J then..." its a sign of trouble; such code begins to exhibit huge sensitivity to even small changes and will often behave in maddening ways, so hard to maintain and update.)
 
Last edited:

djsfantasi

Joined Apr 11, 2010
7,563
Note also that mills wraps after a numbe rof days ( can't rember how many )
so if your turned on for that lenght, two consecutive reads of mills might go down not up.
However, the code is correct for using millis() to test for intervals. There are two ways to construct the if() statement. The incorrect way and the way it is done is his sketch.

I suggest it is one of the first techniques one is forced to learn in Arduino C. Read this article on the millis() rollover.
 

Thread Starter

firashelou

Joined Feb 28, 2021
4
thank you everyone for such explanations !! I really appreciate your help !
about the interrupts, I have a question, as i know about interrupts that they are used on pin 2 for example so if i can not use pin 2 or i have many buttons that will be attached then how can i use interrupts ?
 

Thread Starter

firashelou

Joined Feb 28, 2021
4
I suggest it is one of the first techniques one is forced to learn in Arduino C. Read this article on the millis() rollover.
I checked the article but i could not understand how it would affect my sketch ? i mean if i understood well the millis() will simply become 0, so if millis() record 1000ms then that is good the number is not big anymore and i will turn my circuit off anyway and not use it on that long of 49 days. Please correct me if i misunderstood
 

Thread Starter

firashelou

Joined Feb 28, 2021
4
according to this video the timer starts counting from 0 when the arduino is powered on, so that means everytime i power it off then on the timer will start again from 0 so that should not create any problems in my case
 
Top