millis() question

Members

I am having some trouble using an auto off switch for the LED’s after they have been remotely switched on via nRF

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>


//   ....UNO ...........CHECK
#define CE_PIN 6  //confirm pin connections for nrf
#define CSN_PIN 7

int msg[2];  //this must match msg in the Tx
RF24 radio(CE_PIN, CSN_PIN);

float ackData[2] = {ackData[0], ackData[1]}; //the value to be sent to the master UNO to DUE


const unsigned long interval = 2000; //ms
unsigned long last_sent;

const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'E'};
//const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'F'};
int LED0 = 2;     // led pin
int LED1 = 3;

void setup(void) {

  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1, slaveAddress);
  radio.enableAckPayload();
  radio.writeAckPayload(1, &ackData, sizeof(ackData)); //not used 
  radio.startListening();
  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);
}

void loop(void) {
  
  Switch();
}


/* Address'E' uses 100101-led1-0n   100102-led1-off
                   100201-led2-on   100202-led2-off
   Address'F' uses 101101-led1-on   101102-led2-off
                   101201-led2-on   101202-led2-off
*/

void Switch() {
  if (radio.available()) {
    radio.read(msg, 1);
    if (msg[0] == 111) {
      digitalWrite(LED0, HIGH);
      safety();
    }

    if (msg[0] == 110) {
      digitalWrite(LED0, LOW);
    }
    if (msg[0] == 101) {
      digitalWrite(LED1, HIGH);
      safety();
    }
    if (msg[0] == 100) {
      digitalWrite(LED1, LOW);
    }
  }
}// end Switch()


void safety() {
  unsigned long now = millis();
  if ( now - last_sent > interval  )
  {
    last_sent = now;    
    digitalWrite(LED0, LOW);
    digitalWrite(LED1, LOW);
  }
}

Thanks in advance

You didn't say what the problem was, but look carefully at how and when you call "safety"

float ackData[2] = {ackData[0], ackData[1]}; //the value to be sent to the master UNO to DUE

What's that?

AWOL:

float ackData[2] = {ackData[0], ackData[1]}; //the value to be sent to the master UNO to DUE

What's that?

that is not used

You still didn't say what "some trouble" is.

The way you ask questions probably says just as much.

I am having some trouble using an auto off switch (using millis()) for the LED's

I’ll ask one last time - what does “some trouble” mean?

its not switching the leds off after it has been switched on

OK, I refer you back to my first answer regarding "safety()"

AWOL:
OK, I refer you back to my first answer regarding "safety()"

so you did understand me the first time round?

fnb111:
so you did understand me the first time round?

No, but the code looked suspicious.

I'm good, but not psychic.

You call safety() right after the led has gone on.

safety() immediately sets now to millis, which could be a tiny number if the communications occurred soon after power up, or could be a huge number if a lot of time has gone by.

last_sent was initialised when the sketch started, and if this is the first time through, has never been changed, so is 0.

So then the now-last_sent being larger than interval or not, depends solely on how long the sketch has been running until the first command was received. Either the led stays on, or if it so happens that the sketch ran for a while before a command arrived then the led will turn off; if it does turn off, it will be immediately after it went on.

(At least, that's the way I read it all....)

Thanks Elvon. You make things so much easier by explaining it.

fnb111:
Thanks Elvon. You make things so much easier by explaining it.

Now you just have to fix it :wink:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>


//   ....UNO ...........CHECK
#define CE_PIN 6  //confirm pin connections for nrf
#define CSN_PIN 7

int msg[2];  //this must match msg in the Tx
RF24 radio(CE_PIN, CSN_PIN);

float ackData[2] = {ackData[0], ackData[1]}; //the value to be sent to the master UNO to DUE

const unsigned long interval = 5000UL; //ms
unsigned long last_sent;

const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'E'};
//const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'F'};
int LED0 = 2;     // led pin
int LED1 = 3;

void setup(void) {

  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1, slaveAddress);
  radio.enableAckPayload();
  radio.writeAckPayload(1, &ackData, sizeof(ackData)); //pre-load data
  radio.startListening();
  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);
}

void loop(void) {

  Switch();
}

void Switch() {
  if (radio.available()) {
    radio.read(msg, 1);
    if (msg[0] == 111) {
      digitalWrite(LED0, HIGH);
    }

    if (msg[0] == 110) {
      digitalWrite(LED0, LOW);
    }
    if (msg[0] == 101) {

      digitalWrite(LED1, HIGH);
    }
    if (msg[0] == 100) {
      digitalWrite(LED1, LOW);
    }
  }
  safety();
}// end Switch()

Like you said: time starts at the top. The led switch off after about 2 sec the following time. Not predictable at 5 sec intervals.

How can I reset millis()?

fnb111:
How can I reset millis()?

You can't but it doesn't matter.

What I would do is to move the calls to safety() out of Switch() into loop() just below Switch().

Move now = millis() into loop() as the first line of loop().

In Switch, where the led goes on, put the last_sent=now (although I would give it what I would see as a more meaningful name like ledWentOnAtMillis)

So then the flow would be that in Switch(), ledWentOnAtMillis is set to now when the led goes on. Back out in loop(), safety() is called and it compares now to ledWentOnAtMillis to see if interval has elapsed. First time through there after the led goes on, now and ledWentOnAtMillis are to all intents and purposes the same, so interval has not elapsed. Each time through safety(), now is of course getting bigger (it gets set to millis() each time through loop()), ledWentOnAtMillis hasn't changed, and so the difference is increasing. Eventually it gets bigger than interval and voila... turn off the led.

Caveat... that's right off the top of my head, in between snoozing on a Saturday afternoon after a 5k run :wink:

fnb111:
Thanks Elvon. You make things so much easier by explaining it.

Get into the habit of explaining it to yourself, your cat, your R2-D2 pencil sharpener or your Peppa Pig duvet cover.

Don't use words like "some trouble" or "difficulty", but observations.

Remember, we can't see what you can, and we don't know what your expectations are.

elvon_blunden:
You can't but it doesn't matter.

I haven't looked at for a while, but it used to be shockingly easy, though completely unnecessary.

@OP

1. Have you made the real setup using two NRF Modules?

2. What message (111 or 101) are you sending from the Master to the Slave?

3. Have you received the message by the slave. Can you make a print of it in the Serial Monitor of the Slave and post the screenshot here?

4. The received message of Step-3 makes your Led (LED0/LED1) ON, and then you call the safety() sub-function. Is it correct?

5. Can you guess how much time has elapsed between the points of the reception of the message and the entry of the safety() sub-function? Post#11 has correctly estimated that the elapsed time is very very tiny. Can you make a print out of it in the Serial Monitor of the Slave and post here the screenshot? (Hints: The elapsed time since the UNO has come into operation (after the uploading of the sketch) is maintained by the Arduino withing the MCU of the UNO Board, and it can be known by executing this instruction: unsigned long elapsedTime = millis();.)

6. In view of the results of Step-5, do you think that the expression (now - last_sent(0)>2000) will be satisfied and your Led (LED0/LED1) will become OFF? This is the point that @AWOL had been trying to make you understand; but, you did not listen well! (The variable now holds the elapsed time which is very very small compared to your interval period of 2000 ms.)

BTW: Please, make your Led (LED0/LED1) OFF in the setup().

AWOL:
Get into the habit of explaining it to yourself, your cat, your R2-D2 pencil sharpener or your Peppa Pig duvet cover.

Don't use words like "some trouble" or "difficulty", but observations.

Remember, we can't see what you can, and we don't know what your expectations are.
I haven't looked at for a while, but it used to be shockingly easy, though completely unnecessary.

Expanding on this. The basics of explaining a problem are actually very simple. This is all you need to do:

  1. Tell us what you want to happen.

  2. Tell us what is actually happening.

Saying that you have "trouble" or "difficulty" does not tell us any of that, and is a very lazy way of asking for help. Most people here are not going to put much effort into answering a question that doesn't look like much effort was put into asking.

AWOL:
I haven't looked at for a while, but it used to be shockingly easy, though completely unnecessary.

Shooting yourself in the foot is also easy.