Nrf24l01 Putting Slave in sleep Mode

Hello

I am working on NRF24l01 based wireless module to which a pir sensor is connected, As some part of the topic is discussed in previous topic which was to initially to setup and make the code to work for multiple sensors and one single master.
The link is given below
https://forum.arduino.cc/index.php?topic=512027.0

Now i want to make some modification in the code The previous code for master is

// MultiTxAckPayload - the master or the transmitter
//   works with two Arduinos as slaves
//     each slave should the SimpleRxAckPayload program
//       one with the adress {'R','x','A','A','A'}
//         and the other with {'R','x','A','A','B'}

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


#define CE_PIN   9
#define CSN_PIN 10

const byte numSlaves = 2;
const byte slaveAddress[numSlaves][5] = {
        // each slave needs a different address
                            {'R','x','A','A','A'},
                            {'R','x','A','A','B'}
                        };

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

//~ char dataToSend[10] = "Message 0";
char dataToSend[10] = "ToSlvN  0";
char pirDataReceived[5];
bool newData = false;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second

//===============

void setup() {

    Serial.begin(9600);
    Serial.println(F("Source File = /mnt/SGT/SGT-Prog/Arduino/ForumDemos/nRF24Tutorial/MultiTxAckPayload.ino "));
    Serial.println("SimpleTxAckPayload Starting");

    radio.begin();
    radio.setDataRate( RF24_250KBPS );

    radio.enableAckPayload();

    radio.setRetries(3,5); // delay, count
        // radio.openWritingPipe(slaveAddress); -- moved to loop()
}

//=============

void loop() {

    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
    }
        // showData(); -- moved into send()
}

//================

void send() {

        // call each slave in turn
    for (byte n = 0; n < numSlaves; n++){

            // open the writing pipe with the address of a slave
        radio.openWritingPipe(slaveAddress[n]);

            // include the slave number in the message
        dataToSend[5] = n + '0';

        bool rslt;
        rslt = radio.write( &dataToSend, sizeof(dataToSend) );
            // Always use sizeof() as it gives the size as the number of bytes.
            // For example if dataToSend was an int sizeof() would correctly return 2

        Serial.print("  ========  For Slave ");
        Serial.print(n);
        Serial.println("  ========");
        Serial.print("  Data Sent ");
        Serial.print(dataToSend);
        if (rslt) {
            if ( radio.isAckPayloadAvailable() ) {
                radio.read(&pirDataReceived, sizeof(pirDataReceived));
                newData = true;
            }
            else {
                Serial.println("  Acknowledge but no data ");
            }
           call();
        }
        else {
            Serial.println("  Tx failed");
        }
        showData();
        Serial.print("\n");
    }

    prevMillis = millis();
 }


//=================

void showData() {
    if (newData == true) {
        Serial.println("  Acknowledge data ");
        Serial.println(pirDataReceived);
        
        newData = false;
    }
}

//================

void call()
{

  if(strcmp(pirDataReceived,"ON 1")==0)
  {
    Serial.println("Led 1On");
  }
  else if(strcmp(pirDataReceived,"ON 2")==0)
  {
    Serial.println("Led 2On");
  }
  else if(strcmp(pirDataReceived,"ON 0")==0)
  {
    Serial.println("Led Off");
  }
}

and for slave is

// SimpleRx - the slave or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);
int buttonInput = 2;
int pir1;

char pirData[5]="ON 0";


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 250; // send once per second

char dataReceived[10]; // this must match dataToSend in the TX

bool newData = false;

//==============

void setup() {

    Serial.begin(9600);
    pinMode(buttonInput,INPUT_PULLUP);
    Serial.println("SimpleRxAckPayload Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.enableAckPayload();
    radio.startListening();
    radio.writeAckPayload(1, &pirData, sizeof(pirData)); // pre-load data

}

//==========

void loop() {
  pir1 = digitalRead(buttonInput);
    getData();
    showData();
  
    
}

//============

void getData() {
    if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
       pirTest();
        newData = true;
    }
}

//================

void showData() {
    if (newData == true) {
        Serial.println("Data received ");
        Serial.println(dataReceived);
        Serial.println(" ackPayload sent ");
        Serial.println(pirData);
        
        newData = false;
    }
}

//================




void pirTest()
{
if(pir1 == HIGH)
{
  Serial.println("PIR 1");
  strncpy(pirData, "ON 1", 5);
}

else if(pir1 == LOW)
{
    Serial.println("PIR LOW");
 strncpy(pirData, "ON 0", 5);
}
delayMicroseconds(500);
radio.writeAckPayload(1, &pirData, sizeof(pirData)); // load the payload for the next time

}

i want to somewhat optimize the code and only send data by the slave when there is a trigger by the pir and rest of the time it should go in sleep mode. This will help to reduce power consumption . Please give me some suggestion what should be done in the code

I suggest you click Report to Moderator and ask to have this Thread merged with your earlier one because the context of the problem is set out there and it is very important in this case.

In general my master to many slaves code assumes that all of the slaves are always listening. If you put a slave to sleep it will likely miss a call from the master. I think it is possible to have the nRF24 wake the slave when a message arrives but I have never experimented with that. And for that to happen the nRF24 could not be asleep.

The alternative is to make the master the listener and have the slaves wake up and call it at intervals. But that will need careful coding in the slave to deal with data collisions when two slaves transmit at the same time. The auto-retry feature is no help in this case, it will probably make things worse. So that the master knows where a message comes from each slave should include an identifier as part of the message.

You could also manage things so that every slave wakes for long enough to hear a message if the master sends one. If, for example, a slave is awake for 1 second every 10 seconds that would still be a 90% energy saving.

...R

Thanks Robin2 for suggestion i have reported it to moderator

and as you suggested i think it is best to keep the master as listener and slaves to send only when data has to be send there is no need for setting specific time interval for sending data as it will have to wake up a slave for sending data at a specific time, instead of that only to send data when there is an occurring of an event.

i wanted to know whether are there functions in nrf24l01 library to start a data transfer and to stop data transfer or as it is based on pipe can we open a pipe for certain duration and close it again so that we shall send message to master only when a event has been occurred.

If I re-format your text like this, it makes more sense - stream-of-consciousness prose is very hard to understand, especially for techincal matters.

and as you suggested i think it is best to keep the master as listener and slaves to send only when data has to be send

there is no need for setting specific time interval for sending data as it will would have to wake up a slave for sending data at a specific time,

instead of that only to send data when there is an occurring of an event.

That seems to suggest you are planning to have each slave send data whenever there is new data to send.

And if that is correct I don't understand why you are asking the question in your final paragraph. Why are you thinking it might be necessary to open a pipe for a time period? Why wouldn't the master be listening all the time?

...R

Robin2:
If I re-format your text like this, it makes more sense - stream-of-consciousness prose is very hard to understand, especially for techincal matters.
That seems to suggest you are planning to have each slave send data whenever there is new data to send.

yes correct what are saying is exactly what i want to do

Robin2:
And if that is correct I don't understand why you are asking the question in your final paragraph. Why are you thinking it might be necessary to open a pipe for a time period? Why wouldn't the master be listening all the time?

...R

as in the simpleRx example in the setup function we have used

radio.openReadingPipe(1, thisSlaveAddress);

as the slave starts to listen when we use above line so i thought of there will be a way to stop it so the slave will be in ideal mode and doesn't do anything

but as i have gone through
http://tmrh20.github.io/RF24/RF24_8cpp_source.html#l00696

There is a power down mode in it and i guess this will help to put the nrf24l01 in sleep mode and wakeup it again by using code of the MCU

void RF24::stopListening(void)
  728 {  
  729   ce(LOW);
  730 
  731   delayMicroseconds(txDelay);
  732   
  733   if(read_register(FEATURE) & _BV(EN_ACK_PAY)){
  734     delayMicroseconds(txDelay); //200
  735     flush_tx();
  736   }
  737   //flush_rx();
  738   write_register(NRF_CONFIG, ( read_register(NRF_CONFIG) ) & ~_BV(PRIM_RX) );
  739  
  740   #if defined (RF24_TINY) || defined (LITTLEWIRE)
  741   // for 3 pins solution TX mode is only left with additonal powerDown/powerUp cycle
  742   if (ce_pin == csn_pin) {
  743     powerDown();
  744     powerUp();
  745   }
  746   #endif
  747   write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[0]))); // Enable RX on pipe0
  748   
  749   //delayMicroseconds(100);
  750 
  751 }
  752 
  753 /****************************************************************************/
  754 
  755 void RF24::powerDown(void)
  756 {
  757   ce(LOW); // Guarantee CE is low on powerDown
  758   write_register(NRF_CONFIG,read_register(NRF_CONFIG) & ~_BV(PWR_UP));
  759 }
  760 
  761 /****************************************************************************/
  762 
  763 //Power up now. Radio will not power down unless instructed by MCU for config changes etc.
  764 void RF24::powerUp(void)
  765 {
  766    uint8_t cfg = read_register(NRF_CONFIG);
  767 
  768    // if not powered up then power up and wait for the radio to initialize
  769    if (!(cfg & _BV(PWR_UP))){
  770       write_register(NRF_CONFIG, cfg | _BV(PWR_UP));
  771 
  772       // For nRF24L01+ to go from power down mode to TX or RX mode it must first pass through stand-by mode.
  773       // There must be a delay of Tpd2stby (see Table 16.) after the nRF24L01+ leaves power down mode before
  774       // the CEis set high. - Tpd2stby can be up to 5ms per the 1.0 datasheet
  775       delay(5);
  776    }
  777 }

JairajDange:
as in the simpleRx example in the setup function we have used

radio.openReadingPipe(1, thisSlaveAddress);

as the slave starts to listen when we use above line

Aren't you changing things around so that the slave does not listen at all?

That is what I understood from your Reply #2

...R

Yes you are correct if the slave doesn't have to receive data it wont have to wake up.

It will wake up only when data is to be send to the master. This way we can keep slave in sleep mode for maximum time.

Hello,

Transmitting data from multiple slaves to master, and making the master as receiver only i tried following code but didn't get any result

For slave:

// SimpleRx - the slave or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};
int buttonInput = 2;
int pir1;

RF24 radio(CE_PIN, CSN_PIN);
char pirData[5]="ON 0";
bool newData = false;

//===========

void setup() {

    Serial.begin(9600);
    pinMode(buttonInput,INPUT_PULLUP);
    Serial.println("SimpleSleepMode Slave");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.startListening();
    radio.writeAckPayload(1, &pirData, sizeof(pirData)); 
}

//=============

void loop() {
  pir1 = digitalRead(buttonInput);
    
pirTest();
}

//==============





void pirTest()
{
if(pir1 == HIGH)
{
  Serial.println("PIR 1");
  strncpy(pirData, "ON 1", 5);
}

else if(pir1 == LOW)
{
    Serial.println("PIR LOW");
 strncpy(pirData, "ON 0", 5);
}
delayMicroseconds(500);
radio.writeAckPayload(1, &pirData, sizeof(pirData)); // load the payload for the next time

}

and for master

// SimpleTx - the master or the transmitter

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


#define CE_PIN   9
#define CSN_PIN 10


const byte numSlaves = 2;
const byte slaveAddress[numSlaves][5] = {
        // each slave needs a different address
                            {'R','x','A','A','A'},
                            {'R','x','A','A','B'}
                        };

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio



char pirDataReceived[5];
bool newData = false;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 250; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SleepMode Master");
   
   
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
  //  radio.openWritingPipe(slaveAddress);
    radio.openReadingPipe(1,slaveAddress);
    radio.startListening();
}

//====================

void loop() {

    
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================
void send() {

        // call each slave in turn
    for (byte n = 0; n < numSlaves; n++){

          
                        radio.read(&pirDataReceived, sizeof(pirDataReceived));
                newData = true;
                call();
                showData();
        Serial.print("\n");
    }

    prevMillis = millis();
 }


//================



//=================

void showData() {
    if (newData == true) {
        Serial.println("  Acknowledge data ");
        Serial.println(pirDataReceived);
        
        newData = false;
    }
}
void call()
{

  if(strcmp(pirDataReceived,"ON 1")==0)
  {
    Serial.println("Led 1On");
  }
  else if(strcmp(pirDataReceived,"ON 2")==0)
  {
    Serial.println("Led 2On");
  }
  else if(strcmp(pirDataReceived,"ON 0")==0)
  {
    Serial.println("Led Off");
  }
}

the transfer of data is not successful. what can be the possible reason?

JairajDange:
Transmitting data from multiple slaves to master, and making the master as receiver only i tried following code but didn't get any result

Don't you need the Tx code for the slave and the Rx code for the master? You seem to have it the wrong way round.

...R

Robin2:
Don't you need the Tx code for the slave and the Rx code for the master? You seem to have it the wrong way round.

...R

yes right i want a Tx code for receiver and Rx for master this will transfer data to the the master only when a event will occur and for rest of the time the slaves will go in sleep

JairajDange:
yes right i want a Tx code for receiver and Rx for master this will transfer data to the the master only when a event will occur and for rest of the time the slaves will go in sleep

It may be a typo, but that bit in bold is silly. I believe you mean "Tx code for the slave". Computer programming only works when you are very precise.

Try with the Tx and Rx the right way round, and if it does not work post the programs you have tried.

...R

Robin2:
It may be a typo, but that bit in bold is silly. I believe you mean "Tx code for the slave". Computer programming only works when you are very precise.

:stuck_out_tongue: It was a typing mistake by me sorry for that, i am going now with the "simple one way transmission" example making slave to transmit and master to receive and thinking of adding adding slave addresses in the master

// SimpleTx - the slave or the transmitter

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


#define CE_PIN   9
#define CSN_PIN 10

int buttonInput = 2;
int pir1;


const byte slaveAddress[5] = {'R','x','A','A','A'};


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char pirData[5]="ON 0";



unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 250; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx Starting");
    pinMode(buttonInput,INPUT_PULLUP);
   
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

//====================

void loop() {

    pir1=digitalRead(buttonInput);
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================

void send() {

   
    bool rslt1;
   
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2
  pirTest();
  rslt1 = radio.write( &pirData, sizeof(pirData) );
    
    
    
    if (rslt1) {
     
        Serial.println("  Acknowledge received");
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }
}

//================

void updateMessage() {
        // so you can see that new data is being sent
  
}



void pirTest()
{
  
if(pir1 == HIGH)
{
 
  Serial.println("PIR 1");
  strncpy(pirData, "ON 1", 5);
}

else if(pir1 == LOW)
{
    Serial.println("PIR LOW");
 strncpy(pirData, "ON 0", 5);
}
}

the master code

// SimpleRx - the master or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);
char pirDataReceived[5];
bool newData = false;

//===========

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

//=============

void loop() {
    getData();
    showData();
}

//==============

void getData() {
    if ( radio.available() ) {
        
        radio.read( &pirDataReceived, sizeof(pirDataReceived) );
        newData = true;
    }
}

void showData() {
    if (newData == true) {
        
       Serial.println("Pir data ");
       Serial.println(pirDataReceived);
        
        call();
        newData = false;
          
       
        
    }
}


void call()
{

  if(strcmp(pirDataReceived,"ON 1")==0)
  {
    Serial.println("Led On");
  }
  else if(strcmp(pirDataReceived,"ON 0")==0)
  {
    Serial.println("Led Off");
  }
}

in the slave code i tried with powerUp and powerDown function to start sending data when PIR == HIGH
but couldn't get any success.

Way back in Reply #18 of your other Thread I questioned you use of strncpy() and you have not changed it.

(This is why I don't like people dealing with the same project in multiple Threads)

I am not an expert but I think you are doing it wrong. I believe you should only be copying 4 characters. You need to check whether your copying is screwing up pirData[]

In any case, as you only want to change the 4th character why not just do it with pirData[3] = '1';

...R