Wednesday, May 20, 2015

Reducing the Power Consumption of the nRF24L01 Transceiver

In this video we take a look at the power needs or power profile of the nRF24L01+ Transceiver. We discuss how much power it draws in each mode and how to reduce or optimize its power consumption for battery powered projects or designs. Finally we pair the nRF24L01 with an Arduino utilizing sleep mode and look at their combined power profile.



************Arduino and nRF24L01 Low Power Example Sketch*************
#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+
#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <avr/sleep.h>
#include <avr/wdt.h> 

/*WDT BYTE variables for setting timer value
     WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS, WDTO_250MS, WDTO_500MS, WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S */

const int pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)
const int pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command or message to send out
RF24 wirelessSPI(pinCE, pinCSN); // Create your nRF24 object or wireless SPI connection
const uint64_t wAddress = 0xB00B1E50D2LL;              // Pipe to write or transmit on
const uint64_t rAddress = 0xB00B1E50B1LL;  //pipe to recive data on

void setup() {
  randomSeed(analogRead(0)); //create unique seed value for random number generation
  wirelessSPI.begin();            //Start the nRF24 module
  wirelessSPI.setRetries(15,10);
  wirelessSPI.openWritingPipe(wAddress);        //open writing or transmit pipe
  wirelessSPI.openReadingPipe(1,rAddress);  //open reading or recieve pipe
  wirelessSPI.stopListening(); //go into transmit mode
}

void loop() {
   byte randNumber = (byte)random(11); //generate random guess between 0 and 10 
    if (!wirelessSPI.write(&randNumber, 1)){  //if the write fails
      // delivery failed      
     }
     
   delay(30); //delay for short time in normal mode
   wirelessSPI.powerDown(); //put nRF24L01 into power down mode
   delayWDT(WDTO_30MS);   // Use WDT sleep delay function, argument is byte variable from WDT Library
   wirelessSPI.powerUp(); //power up the nRF24
}

//This function serves as a power saving delay function. The argument is a Byte type variable that is used to set the delay time
//The function sets up sleep mode in power down state. The function then sets up the WDT timer in interrupt mode and sets it.
//It then puts the Arduino to sleep for the set time. Upon wake up the WDT and sleep mode are shut off
void delayWDT(byte timer) {
  sleep_enable(); //enable the sleep capability
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); //set the type of sleep mode. Default is Idle
  ADCSRA &= ~(1<<ADEN); //Turn off ADC before going to sleep (set ADEN bit to 0)
  WDTCSR |= 0b00011000;    //Set the WDE bit and then clear it when set the prescaler, WDCE bit must be set if changing WDE bit   
  WDTCSR =  0b01000000 | timer; //Or timer prescaler byte value with interrupt selectrion bit set
  wdt_reset(); //Reset the WDT 
  sleep_cpu(); //enter sleep mode. Next code that will be executed is the ISR when interrupt wakes Arduino from sleep
  sleep_disable(); //disable sleep mode
  ADCSRA |= (1<<ADEN); //Turn the ADC back on
}

//This is the interrupt service routine for the WDT. It is called when the WDT times out. 
//This ISR must be in your Arduino sketch or else the WDT will not work correctly
ISR (WDT_vect) 
{
  wdt_disable();
   MCUSR = 0; //Clear WDT flag since it is disabled, this is optional

}  // end of WDT_vect

Saturday, May 9, 2015

Creating a nRF24L01 Transceiver Network

In this video we will look at how to create an nRF24L01 Transceiver module network (more than two). This is useful if you want to build a wireless sensor network or some type of wireless automation system that has multiple wireless nodes.



***************************Arduino Code for Receiver*******************************
//This sketch is from a tutorial video for networking more than two nRF24L01 tranciever modules on the ForceTronics YouTube Channel
//the code was leverage from the following code http://maniacbug.github.io/RF24/starping_8pde-example.html
//This sketch is free to the public to use and modify at your own risk

#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+
#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/

const int pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)
const int pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command or message to send out
byte daNumber = 0; //The number that the transmitters are trying to guess
RF24 wirelessSPI(pinCE, pinCSN); // Declare object from nRF24 library (Create your wireless SPI) 
const uint64_t rAddress[] = {0xB00B1E50D2LL, 0xB00B1E50C3LL};  //Create pipe addresses for the 2 nodes to recieve data, the "LL" is for LongLong type
const uint64_t wAddress[] = {0xB00B1E50B1LL, 0xB00B1E50A4LL};  //Create pipe addresses for the 2 nodes to transmit data, the "LL" is for LongLong type

void setup()   
{
  randomSeed(analogRead(0)); //create unique seed value for random number generation
  daNumber = (byte)random(11); //Create random number that transmitters have to guess
  Serial.begin(57600);  //start serial to communication
  Serial.print("The number they are trying to guess is: "); 
  Serial.println(daNumber); //print the number that they have to guess
  Serial.println();
  wirelessSPI.begin();  //Start the nRF24 module
  wirelessSPI.openReadingPipe(1,rAddress[0]);      //open pipe o for recieving meassages with pipe address
  wirelessSPI.openReadingPipe(2,rAddress[1]);      //open pipe o for recieving meassages with pipe address
  wirelessSPI.startListening();                 // Start listening for messages
}

void loop()  
{   
    byte pipeNum = 0; //variable to hold which reading pipe sent data
    byte gotByte = 0; //used to store payload from transmit module
    
    while(wirelessSPI.available(&pipeNum)){ //Check if recieved data
     wirelessSPI.read( &gotByte, 1 ); //read one byte of data and store it in gotByte variable
     Serial.print("Recieved guess from transmitter: "); 
     Serial.println(pipeNum); //print which pipe or transmitter this is from
     Serial.print("They guess number: ");
     Serial.println(gotByte); //print payload or the number the transmitter guessed
     if(gotByte != daNumber) { //if true they guessed wrong
      Serial.println("Fail!! Try again."); 
     }
     else { //if this is true they guessed right
      if(sendCorrectNumber(pipeNum)) Serial.println("Correct! You're done."); //if true we successfully responded
      else Serial.println("Write failed"); //if true we failed responding
     }
     Serial.println();
    }

  delay(200);    
}

//This function turns the reciever into a transmitter briefly to tell one of the nRF24s
//in the network that it guessed the right number. Returns true if write to module was
//successful
bool sendCorrectNumber(byte xMitter) {
    bool worked; //variable to track if write was successful
    wirelessSPI.stopListening(); //Stop listening, stop recieving data.
    wirelessSPI.openWritingPipe(wAddress[xMitter-1]); //Open writing pipe to the nRF24 that guessed the right number
    if(!wirelessSPI.write(&daNumber, 1))  worked = false; //write the correct number to the nRF24 module, and check that it was recieved
    else worked = true; //it was recieved
    wirelessSPI.startListening(); //Switch back to a reciever
    return worked;  //return whether write was successful
}

***************************Arduino Code for Transmitter 1****************************
//This sketch is from a tutorial video for networking more than two nRF24L01 tranciever modules on the ForceTronics YouTube Channel
//the code was leverage from the following code http://maniacbug.github.io/RF24/starping_8pde-example.html
//This sketch is free to the public to use and modify at your own risk

#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+
#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/

const int pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)
const int pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command or message to send out
byte counter = 1; //used to count the packets sent
bool done = false; //used to know when to stop sending packets
RF24 wirelessSPI(pinCE, pinCSN); // Create your nRF24 object or wireless SPI connection
const uint64_t wAddress = 0xB00B1E50D2LL;              // Pipe to write or transmit on
const uint64_t rAddress = 0xB00B1E50B1LL;  //pipe to recive data on

void setup()  
{
  Serial.begin(57600);   //start serial to communicate process
  randomSeed(analogRead(0)); //create unique seed value for random number generation
  wirelessSPI.begin();            //Start the nRF24 module
  wirelessSPI.openWritingPipe(wAddress);        //open writing or transmit pipe
  wirelessSPI.openReadingPipe(1,rAddress);  //open reading or recieve pipe
  wirelessSPI.stopListening(); //go into transmit mode
}


void loop()  
{
   if(!done) { //true once you guess the right number
     byte randNumber = (byte)random(11); //generate random guess between 0 and 10
   
    if (!wirelessSPI.write( &randNumber, 1 )){  //if the write fails let the user know over serial monitor
         Serial.println("Guess delivery failed");      
     }
     else { //if the write was successful 
          Serial.print("Success sending guess: ");
          Serial.println(randNumber);
       
        wirelessSPI.startListening(); //switch to recieve mode to see if the guess was right
        unsigned long startTimer = millis(); //start timer, we will wait 200ms 
        bool timeout = false; 
        while ( !wirelessSPI.available() && !timeout ) { //run while no recieve data and not timed out
          if (millis() - startTimer > 200 ) timeout = true; //timed out
        }
    
        if (timeout) Serial.println("Last guess was wrong, try again"); //no data to recieve guess must have been wrong
        else  { //we recieved something so guess must have been right
          byte daNumber; //variable to store recived value
          wirelessSPI.read( &daNumber,1); //read value
          if(daNumber == randNumber) { //make sure it equals value we just sent, if so we are done
            Serial.println("You guessed right so you are done");
            done = true; //signal to loop that we are done guessing
          }
          else Serial.println("Something went wrong, keep guessing"); //this should never be true, but just in case
        }
        wirelessSPI.stopListening(); //go back to transmit mode
      
     }
   }
    delay(1000);
}

***************************Arduino Code for Transmitter 2****************************
//This sketch is from a tutorial video for networking more than two nRF24L01 tranciever modules on the ForceTronics YouTube Channel
//the code was leverage from the following code http://maniacbug.github.io/RF24/starping_8pde-example.html
//This sketch is free to the public to use and modify at your own risk

#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+
#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/

const int pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)
const int pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command or message to send out
bool done = false; //used to know when to stop sending guesses
RF24 wirelessSPI(pinCE, pinCSN); // Create your nRF24 object or wireless SPI connection
const uint64_t wAddress = 0xB00B1E50C3LL;  //pipe for writing or transmitting data
const uint64_t rAddress = 0xB00B1E50A4LL;  //pipe for reading or recieving data

void setup()  
{
  Serial.begin(57600);   //start serial to communicate process
  randomSeed(analogRead(0)); //create unique seed value for random number generation
  wirelessSPI.begin();            //Start the nRF24 module
  wirelessSPI.openWritingPipe(wAddress);    // setup pipe to transmit over
  wirelessSPI.openReadingPipe(1,rAddress);  //set up pipe to recieve data
  wirelessSPI.stopListening();  //turn off recieve capability so you can transmit
}


void loop()  
{
  if(!done) { //true once you guess the right number
     byte randNumber = (byte)random(11); //generate random guess between 0 and 10
   
    if (!wirelessSPI.write( &randNumber, 1 )){  //if the write fails let the user know over serial monitor
         Serial.println("Guess delivery failed");      
     }
     else { //if the write was successful 
          Serial.print("Success sending guess: ");
          Serial.println(randNumber);
       
        wirelessSPI.startListening(); //switch to recieve mode to see if the guess was right
        unsigned long startTimer = millis(); //start timer, we will wait 200ms 
        bool timeout = false; 
        while ( !wirelessSPI.available() && !timeout ) { //run while no recieve data and not timed out
          if (millis() - startTimer > 200 ) timeout = true; //timed out
        }
    
        if (timeout) Serial.println("Last guess was wrong, try again"); //no data to recieve guess must have been wrong
        else  { //we recieved something so guess must have been right
          byte daNumber; //variable to store recived value
          wirelessSPI.read( &daNumber,1); //read value
          if(daNumber == randNumber) { //make sure it equals value we just sent, if so we are done
            Serial.println("You guessed right so you are done");
            done = true; //signal to loop that we are done guessing
          }
          else Serial.println("Something went wrong, keep guessing"); //this should never be true, but just in case
        }
        wirelessSPI.stopListening(); //go back to transmit mode
      
     }
   }
    delay(1000);
}